EXTRA_DIST = \
autogen.sh \
xournal.glade xournal.gladep \
- xournal.xml x-xoj.desktop xournal.desktop \
- maemo/xournal.desktop maemo/xournal.service
+ xournal.xml x-xoj.desktop xournal.desktop
install-data-local:
@$(NORMAL_INSTALL)
fi \
fi
-if USE_HILDON
-desktopdir = $(datadir)/applications/hildon
-desktop_DATA = maemo/xournal.desktop
-
-servicedir = $(libdir)/dbus-1.0/services
-service_DATA = maemo/xournal.service
-endif
dnl Process this file with autoconf to produce a configure script.
AC_INIT(configure.in)
-AM_INIT_AUTOMAKE(xournal, 0.4.2.1)
+AM_INIT_AUTOMAKE(xournal, 0.4.2.9)
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE
AM_PROG_CC_STDC
AC_HEADER_STDC
-dnl set this var to NONE (PC) or other thing (Maemo)
-usehildon='NONE'
-if test "x$usehildon" != xNONE
-then
- pkg_modules="gtk+-2.0 >= 2.4.0 libgnomecanvas-2.0 >= 2.4.0 libgnomeprintui-2.2 >= 2.0.0 hildon-libs libosso"
-else
- pkg_modules="gtk+-2.0 >= 2.4.0 libgnomecanvas-2.0 >= 2.4.0 libgnomeprintui-2.2 >= 2.0.0"
-fi
+pkg_modules="gtk+-2.0 >= 2.4.0 libgnomecanvas-2.0 >= 2.4.0 libgnomeprintui-2.2 >= 2.0.0 poppler-glib >= 0.6.1"
PKG_CHECK_MODULES(PACKAGE, [$pkg_modules])
AC_SUBST(PACKAGE_CFLAGS)
AC_SUBST(PACKAGE_LIBS)
-AM_CONDITIONAL(USE_HILDON, test "x$usehildon" != xNONE)
-
AC_OUTPUT([
Makefile
src/Makefile
----------------------------------------------------------------
- collaborative editing (see discussion with Erik Demaine)
-- porting to Win32 and MacOS
+- porting to Win32 and MacOS; merge Nokia port
- multiple-scenario undo history
+- collaborative: allow non-x86 endianness (for ints, for floats?)
+- collaborative: have an initial undo item = contents of the initial
+ xoj file + attachments for bitmap, pdf, and ps backgrounds
+
+- cleanup of undo history (keep track of refcounts, delete old undo)
+ save-and-clear-undo ?
+
+- RandR / recalibration awareness?
+ (e.g. if xinput events are far away from core events, re-query geometry?)
+ or see if removing the GTK bugfix would help? -- e.g. by recalling an
+ internal gtk init function?
+
+DONE: fix GTK+ 2.16 XInput issues with scrollbars and menus
+DONE: fix bug 2826845 (shape recognizer accel doesn't work in fullscreen mode)
+DONE: bug affecting resize zone in statusbar
+DONE: page spinbutton wide enough for 3 digits; avoid "deprecated" warning
+DONE: edit->paste command should refresh toolbar to unselect color/thickness
+ (so can repaint sel)
+DONE: cursor doesn't reset properly after selection operation if primary
+ tool is select mode (stays with arrow cursor instead of pointer)
+DONE: device with "eraser" at the end of its name is of type ERASER
+ (Edward Yang)
+DONE: fix_xinput_coords() replaces buggy xinput events by core pointer
+ coordinates
+DONE: use poppler to render PDF bakgrounds (after patches contributed
+ by Mike Ter Louw and Bob McElrath)
+
+
+
+****** gnu-gettext patch?
+
+****** URGENT: gtkprint; new release by November end for Debian!
+ nb: libgnomeprint produces many warnings (spinbutton; gpa assertions)
+
+
+- remove "antialias bg" flag, useless... see McElrath
+- PDF bg memory usage throttling / delete oldest pdf backgrounds
+- fix fix_xinput_coords so it works ok without ENABLE_XINPUT_BUGFIX ?
+ (with both old and new GTK+)
+ (need to shift by (sx,sy), + shift between canvas->window vs canvas in 2.17)
+- Esc should leave text box if editing; and fullscreen if fullscreen?
+- color chooser button (patch tracker?)
+** auto-hide patch from ~/prog/src/xournal-autohide/ ?
+ (check for cpu usage, add flag if need be; handle BOTH edges
+ and only (un)hide stuff at the correct edge!)
+** if bg pdf not found in absolute path, look in path of xoj file before
+ prompting user.
+** GETTEXT i18n patch (sourceforge)
+** PATCH TO WORK AROUND PPM LOADING ISSUE - see tracker
+ (make gdk_pixbuf_ref and g_object_unref(loader) as in the gv_bg
+ loading) or... switch to poppler?
+** patch to fix focus + allow up/dn in single page mode (Bob McElrath)
+ also comment out contents of reset_focus() ? (tracker patch #2494022)
+** patch to fix underscores in MRU filename display (McElrath) (tracker)
+ (fix memory leak)
+** UI update (Bob McElrath) -- eliminating status bar, compact layout,
+ "compact interface" by default; themes, with line in config file
+ to load pixmaps from pixmaps/$THEME/ (see Jan 9, 2009 emails)
+** antialias BG pixmaps doesn't do anything anymore?
+** autosave patch (Edward Yang) (fix: optional only, w/ menu + cfgfile
+ entries; fix: should clean up autosave.xoj.bg* files too; config interval)
+- patch (ikim@physics.wisc.edu): multicolumn mode + LASSO SELECTION
+- patch: ortho/snap (revised Apr 13 2009)
+** FIXME: get_pressure_multiplier() should access correct members
+ of event struct, like xinput_coords()
+** FIX RECOGNIZER BUG: for single-segment strokes (e.g. single click),
+ I_xx and I_yy = 0, sometimes -0 -> Rad = nan (should I_xx = abs(...) ?)
+ also Det = division by 0, should return 0 if ixx + iyy = 0.
+ (MAYBE: fix inertia calc: integrate dm over each segment rather than dm.pt[i])
+- new recognizer icon (andruk on patches tracker)
+- recognizer: if variable-width, associate average width
+- recognizer should snap to existing recognized geometric shapes
+
- improve recognizer: two passes for polygons (low tolerance, then higher)
to better detect elongated rectangles? (if low tolerance recognizer
doesn't get a rectangle, then use higher tolerance for everything else,
since otherwise there's too much risk of splitting a segment into 2)
- snap-to-grid (also for ruler & recognizer vertices)
and maybe also snap-to-vertices (option for ruler and recognizer)?
-- allow broken PDF with some 19-byte xref entries (LF instead of CRLF).??
- (Phil Rhoades 3/25/08)
+- config option: config save current tool options instead of default ones
+
+- "new page before/after" on a PDF bg page should ask: same page, other page of
+ PDF file, default paper
+- bug in truetype subset generation w/ Adobe 9, see if gtk-print any better?
- render page to bitmap: for export, preview, and copy-paste
(render using libart, see how gnomecanvas does it?)
+ NO: render using Cairo !!! then can switch to GtkPrint as well.
(copy-paste: config option to render only current layer or all below?)
- cut-and-paste of selection into other apps (as bitmap; as SVG?)
- navigation sidebar with bitmap page previews
- bitmap preview for document icon in desktop environments?
- "organizer" side panel (hierarchy of notes), cf. gjots
+- allow toolbar to go vertical
+- toolbar buttons should react to button 2/3 click to modify settings
+ for that tool?
+
- paste text directly into xournal, from xournal?
(instead of starting a text item and pasting into/from it)
+- insert links (to URLs; within document/to other xoj? hand mode navigates)
- increase width of spinPageNo to fit 3 digits
+- should escape '_' to '__' in MRU menu entries (else become mnemonics)
- a command + keyboard shortcut to switch mappings (1<->2, 1<->3, 2<->3)
(A. Rechnitzer Sept 11, 2007)
+- modify encoding of TrueType font subsets or provide cmap so pdf text
+ can be extracted
+- smoothing of strokes (for users without tablets / with deficient drivers)
- lasso tool
- internationalization / translation of interface
- switch to poppler instead of pdftoppm; with exact float dpi settings
(keep GnomePrint option for compatibility with GTK+ <2.10)
- insert images (screen capture or from file or from clipboard),
not as full-page backgrounds (new ITEM type)
-- convert to/from Jarnal format; to/from MS Journal format???
+- convert to/from Jarnal format; to/from MS Journal format???
+- export as SVG, as bitmap (use Cairo for this)
+- improved PDF viewer features (search text, hyperlink, page borders...)
+ (using full poppler api ?)
+- use system paper size as default (/etc/papersize)
+- autoload *.pdf.xoj if present when opening *.pdf ???
- sticky notes (anchor visually text box to a bg location)
- use relative paths for bg documents (e.g. annotated PDF)
- flush display queue when drawing over a slow X server?
- more paper customization (in particular, 1/2 inch graph paper)
+ (2 custom papers with settings in config file?
+ a folder with blank PDF or xoj papers and quick-access?)
- option to map a button to a context menu (incl. tool selection, ...)
- option to map a button to "undo"
- xournal_page-shadow.diff (Martin Kiefel Feb 5 2007)
(http://shoffsta.afraid.org/Projects/Xournal/)
- flatten (incl undo/redo...) - enabled only if nlayers>1
- color chooser (papercolor, pen color); maybe more default colors
+ cf. ojb patch #2083103 adds paper color chooser
- printing: print-options, save printer settings (throughout a session,
and on disk) (maybe a separate config file .xournal/gnome-print-settings)
- help index
- option for highlighter to be always at bottom of its layer
- more pen/highlighter shapes (chisel)
+- slanted tip pens (calligraphy)
+- toolbar buttons to access custom preset tools (e.g. text or pen with settings)
+- text boxes with opaque background
- recalibration upon screen resize / compensation for miscalibration
(use ConfigureNotify event and XInput? cf "Bugs" tracker 08/2007)
- find a better behavior for vertical space tool across page boundaries ?
- customize autogenerated save file names
- layer dialog box to set visibility status of each layer regardless of
which layer is being edited
+- option to link layer creation and visibility status for all pages
+ (Eric Borghs 04/15/08)
- display corruption on scroll down when bottom of window is obscured??
(probably a gnomecanvas or X bug -- expose event generated for wrong
region, or not processed?)
- EPOS: Export pages to pictures in the Jpg and Png formats.
- EPOS: Rotate Ink in custom angle.
- handwriting recognition???? (cellwriter?) unlikely. we don't have grids
+ see galileon comment on 2008-07-29 to tracker #1925309: word recognizer
- handwritten stroke search in document (see cellwriter?)
+ (correlate inertia-normalized strokes in lift to unit cotangent bundle?)
- option: export to PDF with incremental pages for successive layers
(for presentations) (Daniel Brugarth 8/18/07)
- Samuel Hoffstaetter: lasso, gettext localization, sidebar thumbnails, ...
rotation doesn't work): gnome_canvas_item_affine_relative(canvas->root, ...)
would rotate all but text items (still need to modify scroll bbox, and
adjust event coordinates by inverse rotation).
+- rotate PDF background pages (individually wrt each other, see #2099935)
- switch to libglade, and allow customization of key shortcuts (accels)
double DEFAULT_ZOOM;
+// prevent interface items from getting bogus XInput events
+gboolean filter_extended_events (GtkWidget *widget, GdkEvent *event,
+ gpointer user_data)
+{
+ // prevent scrollbars from reacting to XInput events
+ if (event->type == GDK_MOTION_NOTIFY &&
+ event->motion.device != gdk_device_get_core_pointer())
+ return TRUE;
+ if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS ||
+ event->type == GDK_3BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
+ event->button.device != gdk_device_get_core_pointer())
+ return TRUE;
+ return FALSE;
+}
+
void init_stuff (int argc, char *argv[])
{
GtkWidget *w;
gdk_device_set_axis_use(device, 1, GDK_AXIS_IGNORE);
#endif
gdk_device_set_mode(device, GDK_MODE_SCREEN);
+ if (g_str_has_suffix(device->name, "eraser"))
+ gdk_device_set_source(device, GDK_SOURCE_ERASER);
can_xinput = TRUE;
}
dev_list = dev_list->next;
gtk_check_menu_item_set_active(
GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsUseXInput")), ui.use_xinput);
+ /* fix a bug in GTK+ 2.16 and beyond: scrollbars shouldn't get extended
+ input events from pointer motion when cursor moves into main window */
+#if GTK_CHECK_VERSION(2,14,0)
+ if (!gtk_check_version(2, 14, 0)) {
+ g_signal_connect (
+ GET_COMPONENT("menubar"),
+ "event", G_CALLBACK (filter_extended_events),
+ NULL);
+ g_signal_connect (
+ GET_COMPONENT("toolbarMain"),
+ "event", G_CALLBACK (filter_extended_events),
+ NULL);
+ g_signal_connect (
+ GET_COMPONENT("toolbarPen"),
+ "event", G_CALLBACK (filter_extended_events),
+ NULL);
+ g_signal_connect (
+ GET_COMPONENT("statusbar"),
+ "event", G_CALLBACK (filter_extended_events),
+ NULL);
+ g_signal_connect (
+ (gpointer)(gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(w))),
+ "event", G_CALLBACK (filter_extended_events),
+ NULL);
+ g_signal_connect (
+ (gpointer)(gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(w))),
+ "event", G_CALLBACK (filter_extended_events),
+ NULL);
+ }
+#endif
+
// load the MRU
init_mru();
gtk_main ();
if (bgpdf.status != STATUS_NOT_INIT) shutdown_bgpdf();
- if (bgpdf.status != STATUS_NOT_INIT) end_bgpdf_shutdown();
save_mru_list();
if (ui.auto_save_prefs) save_config_to_file();
end_text();
reset_focus();
if (ui.pageno == journal.npages-1) { // create a page at end
- if (page_ops_forbidden()) return;
on_journalNewPageEnd_activate(menuitem, user_data);
return;
}
end_text();
reset_focus();
- if (page_ops_forbidden()) return;
reset_selection();
pg = new_page(ui.cur_page);
journal.pages = g_list_insert(journal.pages, pg, ui.pageno);
end_text();
reset_focus();
- if (page_ops_forbidden()) return;
reset_selection();
pg = new_page(ui.cur_page);
journal.pages = g_list_insert(journal.pages, pg, ui.pageno+1);
end_text();
reset_focus();
- if (page_ops_forbidden()) return;
reset_selection();
pg = new_page((struct Page *)g_list_last(journal.pages)->data);
journal.pages = g_list_append(journal.pages, pg);
end_text();
reset_focus();
- if (page_ops_forbidden()) return;
if (journal.npages == 1) return;
reset_selection();
prepare_new_undo();
if (event->button > 3) return FALSE; // no painting with the mouse wheel!
if (event->type != GDK_BUTTON_PRESS) return FALSE;
// double-clicks may have broken axes member (free'd) due to a bug in GDK
- if (!is_core) {
- // re-get the axis values since Synaptics sends bogus ones
- gdk_device_get_state(event->device, event->window, event->axes, NULL);
+ if (!is_core)
fix_xinput_coords((GdkEvent *)event);
- }
+
#ifdef INPUT_DEBUG
printf("DEBUG: ButtonDown (%s) (x,y)=(%.2f,%.2f)\n",
is_core?"core":"xinput", event->x, event->y);
val = gtk_spin_button_get_value_as_int(spinbutton) - 1;
if (val == journal.npages) { // create a page at end
- if (page_ops_forbidden()) return;
on_journalNewPageEnd_activate(NULL, NULL);
return;
}
#include <locale.h>
#include <glib.h>
#include <glib/gstdio.h>
+#include <poppler/glib/poppler.h>
#include "xournal.h"
#include "xo-interface.h"
struct Item *item;
int i, is_clone;
char *tmpfn, *tmpstr;
- gchar *pdfbuf;
- gsize pdflen;
gboolean success;
FILE *tmpf;
GList *pagelist, *layerlist, *itemlist, *list;
if (pg->bg->file_domain == DOMAIN_ATTACH) {
tmpfn = g_strdup_printf("%s.%s", filename, pg->bg->filename->s);
success = FALSE;
- if (bgpdf.status != STATUS_NOT_INIT &&
- g_file_get_contents(bgpdf.tmpfile_copy, &pdfbuf, &pdflen, NULL))
+ if (bgpdf.status != STATUS_NOT_INIT && bgpdf.file_contents != NULL)
{
tmpf = fopen(tmpfn, "w");
- if (tmpf != NULL && fwrite(pdfbuf, 1, pdflen, tmpf) == pdflen)
+ if (tmpf != NULL && fwrite(bgpdf.file_contents, 1, bgpdf.file_length, tmpf) == bgpdf.file_length)
success = TRUE;
- g_free(pdfbuf);
fclose(tmpf);
}
if (!success) {
gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
make_canvas_items();
update_page_stuff();
+ rescale_bg_pixmaps(); // this requests the PDF pages if need be
gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)), 0);
return TRUE;
}
/************** pdf annotation ***************/
-/* free tmp directory */
-
-void end_bgpdf_shutdown(void)
-{
- if (bgpdf.tmpdir!=NULL) {
- if (bgpdf.tmpfile_copy!=NULL) {
- g_unlink(bgpdf.tmpfile_copy);
- g_free(bgpdf.tmpfile_copy);
- bgpdf.tmpfile_copy = NULL;
- }
- g_rmdir(bgpdf.tmpdir);
- g_free(bgpdf.tmpdir);
- bgpdf.tmpdir = NULL;
- }
- bgpdf.status = STATUS_NOT_INIT;
-}
-
/* cancel a request */
void cancel_bgpdf_request(struct BgPdfRequest *req)
list_link = g_list_find(bgpdf.requests, req);
if (list_link == NULL) return;
- if (list_link->prev == NULL && bgpdf.pid > 0) {
- // this is being processed: kill the child but don't remove the request yet
- if (bgpdf.status == STATUS_RUNNING) bgpdf.status = STATUS_ABORTED;
- kill(bgpdf.pid, SIGHUP);
-// printf("Cancelling a request - killing %d\n", bgpdf.pid);
- }
- else {
- // remove the request
- bgpdf.requests = g_list_delete_link(bgpdf.requests, list_link);
- g_free(req);
-// printf("Cancelling a request - no kill needed\n");
- }
+ // remove the request
+ bgpdf.requests = g_list_delete_link(bgpdf.requests, list_link);
+ g_free(req);
}
-/* sigchld callback */
+/* process a bg PDF request from the queue, and recurse */
-void bgpdf_child_handler(GPid pid, gint status, gpointer data)
+gboolean bgpdf_scheduler_callback(gpointer data)
{
struct BgPdfRequest *req;
struct BgPdfPage *bgpg;
- gchar *ppm_name;
GdkPixbuf *pixbuf;
- int npad, ret;
-
- if (bgpdf.requests == NULL) return;
+ GtkWidget *dialog;
+ PopplerPage *pdfpage;
+ gdouble height, width;
+ int scaled_height, scaled_width;
+
+ // if all requests have been cancelled, remove ourselves from main loop
+ if (bgpdf.requests == NULL) { bgpdf.pid = 0; return FALSE; }
+ if (bgpdf.status == STATUS_NOT_INIT)
+ { printf("BGPDF not initialized??\n"); bgpdf.pid = 0; return FALSE; }
+
req = (struct BgPdfRequest *)bgpdf.requests->data;
-
+
+ // use poppler to generate the page
pixbuf = NULL;
- // pdftoppm used to generate p-nnnnnn.ppm (6 digits); new versions produce variable width
- for (npad = 6; npad>0; npad--) {
- ppm_name = g_strdup_printf("%s/p-%0*d.ppm", bgpdf.tmpdir, npad, req->pageno);
- if (bgpdf.status != STATUS_ABORTED && bgpdf.status != STATUS_SHUTDOWN)
- pixbuf = gdk_pixbuf_new_from_file(ppm_name, NULL);
- ret = unlink(ppm_name);
- g_free(ppm_name);
- if (pixbuf != NULL || ret == 0) break;
+ pdfpage = poppler_document_get_page(bgpdf.document, req->pageno-1);
+ if (pdfpage) {
+// printf("Processing request for page %d at %f dpi\n", req->pageno, req->dpi);
+ set_cursor_busy(TRUE);
+ poppler_page_get_size(pdfpage, &width, &height);
+ scaled_width = (int) (req->dpi * width/72);
+ scaled_height = (int) (req->dpi * height/72);
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+ FALSE, 8, scaled_width, scaled_height);
+ poppler_page_render_to_pixbuf(
+ pdfpage, 0, 0, scaled_width, scaled_height,
+ req->dpi/72, 0, pixbuf);
+ g_object_unref(pdfpage);
+ set_cursor_busy(FALSE);
}
+ // process the generated pixbuf...
if (pixbuf != NULL) { // success
-// printf("success\n");
while (req->pageno > bgpdf.npages) {
bgpg = g_new(struct BgPdfPage, 1);
bgpg->pixbuf = NULL;
if (bgpg->pixbuf!=NULL) gdk_pixbuf_unref(bgpg->pixbuf);
bgpg->pixbuf = pixbuf;
bgpg->dpi = req->dpi;
- if (req->initial_request && bgpdf.create_pages) {
- bgpdf_create_page_with_bg(req->pageno, bgpg);
- // create page n, resize it, set its bg - all without any undo effect
- } else {
- if (!req->is_printing) bgpdf_update_bg(req->pageno, bgpg);
- // look for all pages with this bg, and update their bg pixmaps
- }
- }
- else {
-// printf("failed or aborted\n");
- bgpdf.create_pages = FALSE;
- req->initial_request = FALSE;
- }
-
- bgpdf.pid = 0;
- g_spawn_close_pid(pid);
-
- if (req->initial_request)
- req->pageno++; // try for next page
- else
- bgpdf.requests = g_list_delete_link(bgpdf.requests, bgpdf.requests);
-
- if (bgpdf.status == STATUS_SHUTDOWN) {
- end_bgpdf_shutdown();
- return;
- }
-
- bgpdf.status = STATUS_IDLE;
- if (bgpdf.requests != NULL) bgpdf_spawn_child();
-}
-
-/* spawn a child to process the head request */
-
-void bgpdf_spawn_child(void)
-{
- struct BgPdfRequest *req;
- GPid pid;
- gchar pageno_str[10], dpi_str[10];
- gchar *pdf_filename = bgpdf.tmpfile_copy;
- gchar *ppm_root = g_strdup_printf("%s/p", bgpdf.tmpdir);
- gchar *argv[]= PDFTOPPM_ARGV;
- GtkWidget *dialog;
-
- if (bgpdf.requests == NULL) return;
- req = (struct BgPdfRequest *)bgpdf.requests->data;
- if (req->pageno > bgpdf.npages+1 ||
- (!req->initial_request && req->pageno <= bgpdf.npages &&
- req->dpi == ((struct BgPdfPage *)g_list_nth_data(bgpdf.pages, req->pageno-1))->dpi))
- { // ignore this request - it's redundant, or in outer space
- bgpdf.pid = 0;
- bgpdf.status = STATUS_IDLE;
- bgpdf.requests = g_list_delete_link(bgpdf.requests, bgpdf.requests);
- g_free(ppm_root);
- if (bgpdf.requests != NULL) bgpdf_spawn_child();
- return;
- }
- g_snprintf(pageno_str, 10, "%d", req->pageno);
- g_snprintf(dpi_str, 10, "%d", req->dpi);
-/* printf("Processing request for page %d at %d dpi -- in %s\n",
- req->pageno, req->dpi, ppm_root); */
- if (!g_spawn_async(NULL, argv, NULL,
- G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
- NULL, NULL, &pid, NULL))
- {
- // couldn't spawn... abort this request, try next one maybe ?
-// printf("Couldn't spawn\n");
- bgpdf.pid = 0;
- bgpdf.status = STATUS_IDLE;
- bgpdf.requests = g_list_delete_link(bgpdf.requests, bgpdf.requests);
- g_free(ppm_root);
+ bgpg->pixel_height = scaled_height;
+ bgpg->pixel_width = scaled_width;
+ bgpdf_update_bg(req->pageno, bgpg); // update all pages that have this bg
+ } else { // failure
if (!bgpdf.has_failed) {
dialog = gtk_message_dialog_new(GTK_WINDOW(winMain), GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Unable to start PDF loader %s.", argv[0]);
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Unable to render one or more PDF pages.");
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
bgpdf.has_failed = TRUE;
- if (bgpdf.requests != NULL) bgpdf_spawn_child();
- return;
- }
+ }
-// printf("Spawned process %d\n", pid);
- bgpdf.pid = pid;
- bgpdf.status = STATUS_RUNNING;
- g_child_watch_add(pid, bgpdf_child_handler, NULL);
- g_free(ppm_root);
+ bgpdf.requests = g_list_delete_link(bgpdf.requests, bgpdf.requests);
+ if (bgpdf.requests != NULL) return TRUE; // remain in the idle loop
+ bgpdf.pid = 0;
+ return FALSE; // we're done
}
/* make a request */
-void add_bgpdf_request(int pageno, double zoom, gboolean printing)
+void add_bgpdf_request(int pageno, double zoom)
{
struct BgPdfRequest *req, *cmp_req;
GList *list;
- if (bgpdf.status == STATUS_NOT_INIT || bgpdf.status == STATUS_SHUTDOWN)
- return; // don't accept requests in those modes...
+ if (bgpdf.status == STATUS_NOT_INIT)
+ return; // don't accept requests
req = g_new(struct BgPdfRequest, 1);
- req->is_printing = printing;
- if (printing) req->dpi = PDFTOPPM_PRINTING_DPI;
- else req->dpi = (int)floor(72*zoom+0.5);
-// printf("Enqueuing request for page %d at %d dpi\n", pageno, req->dpi);
- if (pageno >= 1) {
- // cancel any request this may supersede
- for (list = bgpdf.requests; list != NULL; ) {
- cmp_req = (struct BgPdfRequest *)list->data;
- list = list->next;
- if (!cmp_req->initial_request && cmp_req->pageno == pageno &&
- cmp_req->is_printing == printing)
- cancel_bgpdf_request(cmp_req);
- }
- req->pageno = pageno;
- req->initial_request = FALSE;
- } else {
- req->pageno = 1;
- req->initial_request = TRUE;
+ req->pageno = pageno;
+ req->dpi = 72*zoom;
+// printf("Enqueuing request for page %d at %f dpi\n", pageno, req->dpi);
+
+ // cancel any request this may supersede
+ for (list = bgpdf.requests; list != NULL; ) {
+ cmp_req = (struct BgPdfRequest *)list->data;
+ list = list->next;
+ if (cmp_req->pageno == pageno) cancel_bgpdf_request(cmp_req);
}
+
+ // make the request
bgpdf.requests = g_list_append(bgpdf.requests, req);
- if (!bgpdf.pid) bgpdf_spawn_child();
+ if (!bgpdf.pid) bgpdf.pid = g_idle_add(bgpdf_scheduler_callback, NULL);
}
/* shutdown the PDF reader */
GList *list;
struct BgPdfPage *pdfpg;
struct BgPdfRequest *req;
+
+ if (bgpdf.status == STATUS_NOT_INIT) return;
- if (bgpdf.status == STATUS_NOT_INIT || bgpdf.status == STATUS_SHUTDOWN) return;
+ // cancel all requests and free data structures
refstring_unref(bgpdf.filename);
for (list = bgpdf.pages; list != NULL; list = list->next) {
pdfpg = (struct BgPdfPage *)list->data;
if (pdfpg->pixbuf!=NULL) gdk_pixbuf_unref(pdfpg->pixbuf);
+ g_free(pdfpg);
}
g_list_free(bgpdf.pages);
- bgpdf.status = STATUS_SHUTDOWN;
- for (list = g_list_last(bgpdf.requests); list != NULL; ) {
+ for (list = bgpdf.requests; list != NULL; list = list->next) {
req = (struct BgPdfRequest *)list->data;
- list = list->prev;
- cancel_bgpdf_request(req);
+ g_free(req);
+ }
+ g_list_free(bgpdf.requests);
+
+ if (bgpdf.file_contents!=NULL) {
+ g_free(bgpdf.file_contents);
+ bgpdf.file_contents = NULL;
}
- if (!bgpdf.pid) end_bgpdf_shutdown();
- /* The above will ultimately remove all requests and kill the child if needed.
- The child will set status to STATUS_NOT_INIT, clear the requests list,
- empty tmpdir, ... except if there's no child! */
- /* note: it could look like there's a race condition here - if a child
- terminates and a new request is enqueued while we are destroying the
- queue - but actually the child handler callback is NOT a signal
- callback, so execution of this function is atomic */
+ if (bgpdf.document!=NULL) {
+ g_object_unref(bgpdf.document);
+ bgpdf.document = NULL;
+ }
+
+ bgpdf.status = STATUS_NOT_INIT;
}
+
+// initialize PDF background rendering
+
gboolean init_bgpdf(char *pdfname, gboolean create_pages, int file_domain)
{
- FILE *f;
- gchar *filebuf;
- gsize filelen;
+ int i, n_pages;
+ struct Background *bg;
+ struct Page *pg;
+ PopplerPage *pdfpage;
+ gdouble width, height;
if (bgpdf.status != STATUS_NOT_INIT) return FALSE;
- bgpdf.tmpfile_copy = NULL;
- bgpdf.tmpdir = mkdtemp(g_strdup(TMPDIR_TEMPLATE));
- if (!bgpdf.tmpdir) return FALSE;
- // make a local copy and check if it's a PDF
- if (!g_file_get_contents(pdfname, &filebuf, &filelen, NULL))
- { end_bgpdf_shutdown(); return FALSE; }
- if (filelen < 4 || strncmp(filebuf, "%PDF", 4))
- { g_free(filebuf); end_bgpdf_shutdown(); return FALSE; }
- bgpdf.tmpfile_copy = g_strdup_printf("%s/bg.pdf", bgpdf.tmpdir);
- f = fopen(bgpdf.tmpfile_copy, "w");
- if (f == NULL || fwrite(filebuf, 1, filelen, f) != filelen)
- { g_free(filebuf); end_bgpdf_shutdown(); return FALSE; }
- fclose(f);
- g_free(filebuf);
- bgpdf.status = STATUS_IDLE;
- bgpdf.pid = 0;
+
+ // make a copy of the file in memory and check it's a PDF
+ if (!g_file_get_contents(pdfname, &(bgpdf.file_contents), &(bgpdf.file_length), NULL))
+ return FALSE;
+ if (bgpdf.file_length < 4 || strncmp(bgpdf.file_contents, "%PDF", 4))
+ { g_free(bgpdf.file_contents); bgpdf.file_contents = NULL; return FALSE; }
+
+ // init bgpdf data structures and open poppler document
+ bgpdf.status = STATUS_READY;
bgpdf.filename = new_refstring((file_domain == DOMAIN_ATTACH) ? "bg.pdf" : pdfname);
bgpdf.file_domain = file_domain;
bgpdf.npages = 0;
bgpdf.pages = NULL;
bgpdf.requests = NULL;
- bgpdf.create_pages = create_pages;
+ bgpdf.pid = 0;
bgpdf.has_failed = FALSE;
- add_bgpdf_request(-1, ui.startup_zoom, FALSE); // request all pages
- return TRUE;
-}
-// create page n, resize it, set its bg
-void bgpdf_create_page_with_bg(int pageno, struct BgPdfPage *bgpg)
-{
- struct Page *pg = NULL;
- struct Background *bg;
+ bgpdf.document = poppler_document_new_from_data(bgpdf.file_contents, bgpdf.file_length, NULL, NULL);
+ if (bgpdf.document == NULL) shutdown_bgpdf();
- if (journal.npages < pageno) {
- bg = g_new(struct Background, 1);
- bg->canvas_item = NULL;
- } else {
- pg = (struct Page *)g_list_nth_data(journal.pages, pageno-1);
- bg = pg->bg;
- if (bg->type != BG_SOLID) return;
- // don't mess with a page the user has modified significantly...
- }
+ if (!create_pages) return TRUE; // we're done
- bg->type = BG_PDF;
- bg->pixbuf = gdk_pixbuf_ref(bgpg->pixbuf);
- bg->filename = refstring_ref(bgpdf.filename);
- bg->file_domain = bgpdf.file_domain;
- bg->file_page_seq = pageno;
- bg->pixbuf_scale = ui.startup_zoom;
- bg->pixbuf_dpi = bgpg->dpi;
-
- if (journal.npages < pageno) {
- pg = new_page_with_bg(bg,
- gdk_pixbuf_get_width(bg->pixbuf)*72.0/bg->pixbuf_dpi,
- gdk_pixbuf_get_height(bg->pixbuf)*72.0/bg->pixbuf_dpi);
- journal.pages = g_list_append(journal.pages, pg);
- journal.npages++;
- } else {
- pg->width = gdk_pixbuf_get_width(bgpg->pixbuf)*72.0/bg->pixbuf_dpi;
- pg->height = gdk_pixbuf_get_height(bgpg->pixbuf)*72.0/bg->pixbuf_dpi;
- make_page_clipbox(pg);
- update_canvas_bg(pg);
+ // create pages with correct sizes if requested
+ n_pages = poppler_document_get_n_pages(bgpdf.document);
+ for (i=1; i<=n_pages; i++) {
+ pdfpage = poppler_document_get_page(bgpdf.document, i-1);
+ if (!pdfpage) continue;
+ if (journal.npages < i) {
+ bg = g_new(struct Background, 1);
+ bg->canvas_item = NULL;
+ pg = NULL;
+ } else {
+ pg = (struct Page *)g_list_nth_data(journal.pages, i-1);
+ bg = pg->bg;
+ }
+ bg->type = BG_PDF;
+ bg->filename = refstring_ref(bgpdf.filename);
+ bg->file_domain = bgpdf.file_domain;
+ bg->file_page_seq = i;
+ bg->pixbuf = NULL;
+ bg->pixbuf_scale = 0;
+ poppler_page_get_size(pdfpage, &width, &height);
+ g_object_unref(pdfpage);
+ if (pg == NULL) {
+ pg = new_page_with_bg(bg, width, height);
+ journal.pages = g_list_append(journal.pages, pg);
+ journal.npages++;
+ } else {
+ pg->width = width;
+ pg->height = height;
+ make_page_clipbox(pg);
+ update_canvas_bg(pg);
+ }
}
update_page_stuff();
+ rescale_bg_pixmaps(); // this actually requests the pages !!
+ return TRUE;
}
+
// look for all journal pages with given pdf bg, and update their bg pixmaps
void bgpdf_update_bg(int pageno, struct BgPdfPage *bgpg)
{
if (pg->bg->type == BG_PDF && pg->bg->file_page_seq == pageno) {
if (pg->bg->pixbuf!=NULL) gdk_pixbuf_unref(pg->bg->pixbuf);
pg->bg->pixbuf = gdk_pixbuf_ref(bgpg->pixbuf);
- pg->bg->pixbuf_dpi = bgpg->dpi;
+ pg->bg->pixel_width = bgpg->pixel_width;
+ pg->bg->pixel_height = bgpg->pixel_height;
update_canvas_bg(pg);
}
}
" antialiased bitmap backgrounds (true/false)",
g_strdup(ui.antialias_bg?"true":"false"));
update_keyval("paper", "progressive_bg",
- " progressive scaling of bitmap backgrounds (true/false)",
+ " just-in-time update of page backgrounds (true/false)",
g_strdup(ui.progressive_bg?"true":"false"));
update_keyval("paper", "gs_bitmap_dpi",
" bitmap resolution of PS/PDF backgrounds rendered using ghostscript (dpi)",
struct Background *attempt_screenshot_bg(void);
void cancel_bgpdf_request(struct BgPdfRequest *req);
-void add_bgpdf_request(int pageno, double zoom, gboolean printing);
-void bgpdf_spawn_child(void);
+void add_bgpdf_request(int pageno, double zoom);
+gboolean bgpdf_scheduler_callback(gpointer data);
void shutdown_bgpdf(void);
gboolean init_bgpdf(char *pdfname, gboolean create_pages, int file_domain);
-void end_bgpdf_shutdown(void);
void bgpdf_create_page_with_bg(int pageno, struct BgPdfPage *bgpg);
void bgpdf_update_bg(int pageno, struct BgPdfPage *bgpg);
gtk_widget_show (labelPage);
gtk_box_pack_start (GTK_BOX (hbox1), labelPage, FALSE, FALSE, 0);
- spinPageNo_adj = gtk_adjustment_new (1, 1, 1, 1, 1, 1);
+ spinPageNo_adj = gtk_adjustment_new (1, 1, 1, 1, 0, 0);
spinPageNo = gtk_spin_button_new (GTK_ADJUSTMENT (spinPageNo_adj), 1, 0);
gtk_widget_show (spinPageNo);
gtk_box_pack_start (GTK_BOX (hbox1), spinPageNo, FALSE, TRUE, 0);
- gtk_widget_set_size_request (spinPageNo, 39, -1);
gtk_tooltips_set_tip (tooltips, spinPageNo, "Set page number", NULL);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinPageNo), TRUE);
gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON (spinPageNo), TRUE);
statusbar = gtk_statusbar_new ();
gtk_widget_show (statusbar);
gtk_box_pack_start (GTK_BOX (hbox1), statusbar, TRUE, TRUE, 0);
+ gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbar), FALSE);
g_signal_connect ((gpointer) winMain, "delete_event",
G_CALLBACK (on_winMain_delete_event),
gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioZoom), radioZoom_group);
radioZoom_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioZoom));
- spinZoom_adj = gtk_adjustment_new (100, 10, 1500, 5, 20, 20);
+ spinZoom_adj = gtk_adjustment_new (100, 10, 1500, 5, 0, 0);
spinZoom = gtk_spin_button_new (GTK_ADJUSTMENT (spinZoom_adj), 1, 0);
gtk_widget_show (spinZoom);
gtk_box_pack_start (GTK_BOX (hbox4), spinZoom, FALSE, TRUE, 5);
void fix_xinput_coords(GdkEvent *event)
{
-#ifdef ENABLE_XINPUT_BUGFIX
double *axes, *px, *py, axis_width;
GdkDevice *device;
- int wx, wy, sx, sy;
+ int wx, wy, sx, sy, ix, iy;
if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) {
axes = event->button.axes;
device = event->motion.device;
}
else return; // nothing we know how to do
-
+
// use canvas window, not event window (else get GTK+ 2.11 bugs!)
gdk_window_get_origin(GTK_WIDGET(canvas)->window, &wx, &wy);
gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
-
- axis_width = device->axes[0].max - device->axes[0].min;
- if (axis_width>EPSILON)
- *px = (axes[0]/axis_width)*ui.screen_width + sx - wx;
- axis_width = device->axes[1].max - device->axes[1].min;
- if (axis_width>EPSILON)
- *py = (axes[1]/axis_width)*ui.screen_height + sy - wy;
+#ifdef ENABLE_XINPUT_BUGFIX
+ // fix broken events with the core pointer's location
+ if (!finite(axes[0]) || !finite(axes[1]) || (axes[0]==0. && axes[1]==0.)) {
+ gdk_window_get_pointer(GTK_WIDGET(canvas)->window, &ix, &iy, NULL);
+ *px = ix + sx;
+ *py = iy + sy;
+ }
+ else {
+ axis_width = device->axes[0].max - device->axes[0].min;
+ if (axis_width>EPSILON)
+ *px = (axes[0]/axis_width)*ui.screen_width + sx - wx;
+ axis_width = device->axes[1].max - device->axes[1].min;
+ if (axis_width>EPSILON)
+ *py = (axes[1]/axis_width)*ui.screen_height + sy - wy;
+ }
#endif
}
double *pt;
double x, y;
int w, h;
+ gboolean is_well_scaled;
if (pg->bg->canvas_item != NULL)
gtk_object_destroy(GTK_OBJECT(pg->bg->canvas_item));
if (pg->bg->type == BG_PDF)
{
if (pg->bg->pixbuf == NULL) return;
- pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
- gnome_canvas_pixbuf_get_type(),
- "pixbuf", pg->bg->pixbuf,
- "width", pg->width, "height", pg->height,
- "width-set", TRUE, "height-set", TRUE,
- NULL);
+ is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
+ && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
+ if (is_well_scaled)
+ pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
+ gnome_canvas_pixbuf_get_type(),
+ "pixbuf", pg->bg->pixbuf,
+ "width-in-pixels", TRUE, "height-in-pixels", TRUE,
+ NULL);
+ else
+ pg->bg->canvas_item = gnome_canvas_item_new(pg->group,
+ gnome_canvas_pixbuf_get_type(),
+ "pixbuf", pg->bg->pixbuf,
+ "width", pg->width, "height", pg->height,
+ "width-set", TRUE, "height-set", TRUE,
+ NULL);
lower_canvas_item_to(pg->group, pg->bg->canvas_item, NULL);
}
-
}
gboolean is_visible(struct Page *pg)
GList *pglist;
struct Page *pg;
GdkPixbuf *pix;
+ gboolean is_well_scaled;
+ gdouble zoom_to_request;
for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
pg = (struct Page *)pglist->data;
pg->bg->pixbuf_scale = 0;
}
}
- if (pg->bg->type == BG_PDF) { // request an asynchronous update
- if (pg->bg->pixbuf_scale == ui.zoom) continue;
- add_bgpdf_request(pg->bg->file_page_seq, ui.zoom, FALSE);
- pg->bg->pixbuf_scale = ui.zoom;
+ if (pg->bg->type == BG_PDF) {
+ // make pixmap scale to correct size if current one is wrong
+ is_well_scaled = (fabs(pg->bg->pixel_width - pg->width*ui.zoom) < 2.
+ && fabs(pg->bg->pixel_height - pg->height*ui.zoom) < 2.);
+ if (pg->bg->canvas_item != NULL && !is_well_scaled) {
+ g_object_get(pg->bg->canvas_item, "width-in-pixels", &is_well_scaled, NULL);
+ if (is_well_scaled)
+ gnome_canvas_item_set(pg->bg->canvas_item,
+ "width", pg->width, "height", pg->height,
+ "width-in-pixels", FALSE, "height-in-pixels", FALSE,
+ "width-set", TRUE, "height-set", TRUE,
+ NULL);
+ }
+ // request an asynchronous update to a better pixmap if needed
+ zoom_to_request = MIN(ui.zoom, MAX_SAFE_RENDER_DPI/72.0);
+ if (pg->bg->pixbuf_scale == zoom_to_request) continue;
+ add_bgpdf_request(pg->bg->file_page_seq, zoom_to_request);
+ pg->bg->pixbuf_scale = zoom_to_request;
}
}
}
return TRUE;
}
-// test if we're still busy loading a PDF background file
-gboolean page_ops_forbidden(void)
-{
- return (bgpdf.status != STATUS_NOT_INIT && bgpdf.create_pages);
-}
-
// send the focus back to the appropriate widget
void reset_focus(void)
{
update_thickness_buttons();
update_color_buttons();
update_font_button();
+ update_cursor();
}
void move_journal_items_by(GList *itemlist, double dx, double dy,
"can-activate-accel", G_CALLBACK(can_accel), NULL);
g_signal_connect((gpointer) GET_COMPONENT("toolsRuler"),
"can-activate-accel", G_CALLBACK(can_accel), NULL);
+ g_signal_connect((gpointer) GET_COMPONENT("toolsReco"),
+ "can-activate-accel", G_CALLBACK(can_accel), NULL);
}
void add_scroll_bindings(void)
void process_paperstyle_activate(GtkMenuItem *menuitem, int style);
gboolean ok_to_close(void);
-gboolean page_ops_forbidden(void);
void reset_focus(void);
gtk_selection_data_free(sel_data);
update_copy_paste_enabled();
+ update_color_menu();
+ update_thickness_buttons();
+ update_color_buttons();
+ update_font_button();
+ update_cursor(); // FIXME: can't know if pointer is within selection!
}
// modify the color or thickness of pen strokes in a selection
BgPdfPage *pgpdf;
GdkPixbuf *pix;
GString *zpix;
+ PopplerPage *pdfpage;
char *buf, *p1, *p2;
int height, width, stride, x, y, chan;
+ double pgheight, pgwidth;
if (pg->bg->type == BG_PDF) {
- pgpdf = (struct BgPdfPage *)g_list_nth_data(bgpdf.pages, pg->bg->file_page_seq-1);
- if (pgpdf == NULL) return -1;
- if (pgpdf->dpi != PDFTOPPM_PRINTING_DPI) {
- add_bgpdf_request(pg->bg->file_page_seq, 0, TRUE);
- while (pgpdf->dpi != PDFTOPPM_PRINTING_DPI && bgpdf.status == STATUS_RUNNING)
- gtk_main_iteration();
- }
- pix = pgpdf->pixbuf;
+ if (!bgpdf.document) return -1;
+ pdfpage = poppler_document_get_page(bgpdf.document, pg->bg->file_page_seq-1);
+ if (!pdfpage) return -1;
+ poppler_page_get_size(pdfpage, &pgwidth, &pgheight);
+ width = (int) (PDFTOPPM_PRINTING_DPI * pgwidth/72.0);
+ height = (int) (PDFTOPPM_PRINTING_DPI * pgheight/72.0);
+ pix = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height);
+ poppler_page_render_to_pixbuf(
+ pdfpage, 0, 0, width, height, PDFTOPPM_PRINTING_DPI/72.0, 0, pix);
+ g_object_unref(pdfpage);
}
- else pix = pg->bg->pixbuf;
-
- if (gdk_pixbuf_get_bits_per_sample(pix) != 8) return -1;
- if (gdk_pixbuf_get_colorspace(pix) != GDK_COLORSPACE_RGB) return -1;
+ else pix = g_object_ref(pg->bg->pixbuf);
+ if (gdk_pixbuf_get_bits_per_sample(pix) != 8 ||
+ gdk_pixbuf_get_colorspace(pix) != GDK_COLORSPACE_RGB)
+ { g_object_unref(pix); return -1; }
+
width = gdk_pixbuf_get_width(pix);
height = gdk_pixbuf_get_height(pix);
stride = gdk_pixbuf_get_rowstride(pix);
chan = gdk_pixbuf_get_n_channels(pix);
- if (chan!=3 && chan!=4) return -1;
+ if (chan!=3 && chan!=4) { g_object_unref(pix); return -1; }
g_string_append_printf(str, "q %.2f 0 0 %.2f 0 %.2f cm /ImBg Do Q ",
pg->width, -pg->height, pg->height);
}
zpix = do_deflate(buf, 3*width*height);
g_free(buf);
+ g_object_unref(pix);
make_xref(xref, xref->last+1, pdfbuf->len);
g_string_append_printf(pdfbuf,
struct XrefTable xref;
GList *pglist;
struct Page *pg;
- char *buf;
- gsize len;
gboolean annot, uses_pdf;
gboolean use_hiliter;
struct PdfInfo pdfinfo;
}
if (uses_pdf && bgpdf.status != STATUS_NOT_INIT &&
- g_file_get_contents(bgpdf.tmpfile_copy, &buf, &len, NULL) &&
- !strncmp(buf, "%PDF-1.", 7)) {
+ bgpdf.file_contents!=NULL && !strncmp(bgpdf.file_contents, "%PDF-1.", 7)) {
// parse the existing PDF file
- pdfbuf = g_string_new_len(buf, len);
- g_free(buf);
+ pdfbuf = g_string_new_len(bgpdf.file_contents, bgpdf.file_length);
if (pdfbuf->str[7]<'4') pdfbuf->str[7] = '4'; // upgrade to 1.4
annot = pdf_parse_info(pdfbuf, &pdfinfo, &xref);
if (!annot) {
double x, y;
GdkPixbuf *pix;
BgPdfPage *pgpdf;
+ PopplerPage *pdfpage;
+ int width, height;
+ double pgwidth, pgheight;
if (pg->bg->type == BG_SOLID) {
gnome_print_setopacity(gpc, 1.0);
}
return;
}
- else if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
+ else
+ if (pg->bg->type == BG_PIXMAP || pg->bg->type == BG_PDF) {
if (pg->bg->type == BG_PDF) {
- pgpdf = (struct BgPdfPage *)g_list_nth_data(bgpdf.pages, pg->bg->file_page_seq-1);
- if (pgpdf == NULL) return;
- if (pgpdf->dpi != PDFTOPPM_PRINTING_DPI) {
- add_bgpdf_request(pg->bg->file_page_seq, 0, TRUE);
- while (pgpdf->dpi != PDFTOPPM_PRINTING_DPI && bgpdf.status == STATUS_RUNNING) {
- gtk_main_iteration();
- if (*abort) return;
- }
- }
- pix = pgpdf->pixbuf;
+ if (!bgpdf.document) return;
+ pdfpage = poppler_document_get_page(bgpdf.document, pg->bg->file_page_seq-1);
+ if (!pdfpage) return;
+ poppler_page_get_size(pdfpage, &pgwidth, &pgheight);
+ width = (int) (PDFTOPPM_PRINTING_DPI * pgwidth/72.0);
+ height = (int) (PDFTOPPM_PRINTING_DPI * pgheight/72.0);
+ pix = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height);
+ poppler_page_render_to_pixbuf(
+ pdfpage, 0, 0, width, height, PDFTOPPM_PRINTING_DPI/72.0, 0, pix);
+ g_object_unref(pdfpage);
}
- else pix = pg->bg->pixbuf;
- if (gdk_pixbuf_get_bits_per_sample(pix) != 8) return;
- if (gdk_pixbuf_get_colorspace(pix) != GDK_COLORSPACE_RGB) return;
+ else pix = g_object_ref(pg->bg->pixbuf);
+
+ if (gdk_pixbuf_get_bits_per_sample(pix) != 8 ||
+ gdk_pixbuf_get_colorspace(pix) != GDK_COLORSPACE_RGB)
+ { g_object_unref(pix); return; }
gnome_print_gsave(gpc);
gnome_print_scale(gpc, pg->width, pg->height);
gnome_print_translate(gpc, 0., -1.);
else if (gdk_pixbuf_get_n_channels(pix) == 4)
gnome_print_rgbaimage(gpc, gdk_pixbuf_get_pixels(pix),
gdk_pixbuf_get_width(pix), gdk_pixbuf_get_height(pix), gdk_pixbuf_get_rowstride(pix));
+ g_object_unref(pix);
gnome_print_grestore(gpc);
return;
}
#include <gtk/gtk.h>
#include <libgnomecanvas/libgnomecanvas.h>
+#include <poppler/glib/poppler.h>
-/* #define INPUT_DEBUG */
+// #define INPUT_DEBUG
/* uncomment this line if you experience event-processing problems
and want to list the input events received by xournal. Caution, lots
of output (redirect to a file). */
#define DISPLAY_DPI_DEFAULT 96.0
#define MIN_ZOOM 0.2
#define RESIZE_MARGIN 6.0
+#define MAX_SAFE_RENDER_DPI 720 // max dpi at which PDF bg's get rendered
#define VBOX_MAIN_NITEMS 5 // number of interface items in vboxMain
Refstring *filename;
int file_domain;
int file_page_seq;
- int pixbuf_dpi; // for PDF only - the *current* dpi value
double pixbuf_scale; // for PIXMAP, this is the *current* zoom value
// for PDF, this is the *requested* zoom value
+ int pixel_height, pixel_width; // PDF only: pixel size of current pixbuf
} Background;
#define BG_SOLID 0
typedef struct BgPdfRequest {
int pageno;
- int dpi;
- gboolean initial_request; // if so, loop over page numbers
- gboolean is_printing; // this is for printing, not for display
+ double dpi;
} BgPdfRequest;
typedef struct BgPdfPage {
- int dpi;
+ double dpi;
GdkPixbuf *pixbuf;
+ int pixel_height, pixel_width; // pixel size of pixbuf
} BgPdfPage;
typedef struct BgPdf {
int status; // the rest only makes sense if this is not STATUS_NOT_INIT
- int pid; // PID of the converter process
+ guint pid; // the identifier of the idle callback
Refstring *filename;
int file_domain;
- gchar *tmpfile_copy; // the temporary work copy of the file (in tmpdir)
+ gchar *file_contents; // buffer containing a copy of file data
+ gsize file_length; // size of above buffer
int npages;
GList *pages; // a list of BgPdfPage structures
GList *requests; // a list of BgPdfRequest structures
- gchar *tmpdir; // where to look for pages coming from pdf converter
- gboolean create_pages; // create journal pages as we find stuff in PDF
gboolean has_failed; // has failed in the past...
+ PopplerDocument *document; // the poppler document
} BgPdf;
#define STATUS_NOT_INIT 0
-#define STATUS_IDLE 1
-#define STATUS_RUNNING 2 // currently running child process on head(requests)
-#define STATUS_ABORTED 3 // child process running, but head(requests) aborted
-#define STATUS_SHUTDOWN 4 // waiting for child process to shut down
+#define STATUS_READY 1 // things are initialized and can work
+// there used to be more possible values, things got streamlined...
// UTILITY MACROS
<child>
<widget class="GtkSpinButton" id="spinPageNo">
- <property name="width_request">39</property>
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Set page number</property>
<property name="can_focus">True</property>
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">True</property>
<property name="wrap">False</property>
- <property name="adjustment">1 1 1 1 1 1</property>
+ <property name="adjustment">1 1 1 1 0 0</property>
<signal name="value_changed" handler="on_spinPageNo_value_changed" last_modification_time="Tue, 13 Dec 2005 21:15:21 GMT"/>
</widget>
<packing>
<child>
<widget class="GtkStatusbar" id="statusbar">
<property name="visible">True</property>
- <property name="has_resize_grip">True</property>
+ <property name="has_resize_grip">False</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="update_policy">GTK_UPDATE_ALWAYS</property>
<property name="snap_to_ticks">False</property>
<property name="wrap">False</property>
- <property name="adjustment">100 10 1500 5 20 20</property>
+ <property name="adjustment">100 10 1500 5 0 0</property>
<signal name="value_changed" handler="on_spinZoom_value_changed" last_modification_time="Sat, 22 Jul 2006 21:04:21 GMT"/>
</widget>
<packing>