]> git.donarmstrong.com Git - xournal.git/commitdiff
Fix various bugs; use poppler instead of pdftoppm
authorauroux <auroux>
Sat, 29 Aug 2009 01:02:19 +0000 (01:02 +0000)
committerauroux <auroux>
Sat, 29 Aug 2009 01:02:19 +0000 (01:02 +0000)
14 files changed:
Makefile.am
configure.in
src/TODO
src/main.c
src/xo-callbacks.c
src/xo-file.c
src/xo-file.h
src/xo-interface.c
src/xo-misc.c
src/xo-misc.h
src/xo-paint.c
src/xo-print.c
src/xournal.h
xournal.glade

index 2bfe3dbb108ff88a2f26d271ca88f4c5cd974d84..a9303f9e4955e4c6279b08fc6d4259c437da7bf9 100644 (file)
@@ -5,8 +5,7 @@ SUBDIRS = src
 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)
@@ -111,10 +110,3 @@ dist-hook:
          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
index b85ae367738fabe88eea025c22c93026bee56394..597bc6e288e731bdc18f8700e68aed6faf7e963a 100644 (file)
@@ -1,7 +1,7 @@
 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
 
@@ -10,20 +10,11 @@ AC_PROG_CC
 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
index d73e6dd77c0cc763fe97361fffb4cba44a7dbcd0..fe2b777e03db07b32015275706e9b8f6036f56bf 100644 (file)
--- a/src/TODO
+++ b/src/TODO
@@ -2,32 +2,118 @@ List of features to be implemented (not in any particular order)
 ----------------------------------------------------------------
 
 - 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
@@ -40,13 +126,20 @@ List of features to be implemented (not in any particular order)
    (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)
@@ -57,11 +150,15 @@ List of features to be implemented (not in any particular order)
      (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 ?
@@ -79,6 +176,8 @@ List of features to be implemented (not in any particular order)
 - 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?)
@@ -93,7 +192,9 @@ List of features to be implemented (not in any particular order)
 - 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, ...
@@ -102,4 +203,5 @@ List of features to be implemented (not in any particular order)
   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)
index f22125e51b49103536be8f65f7575b2ecb6e4253..ac6e3ebf944f9267bb0e83fe32719a5025be7c8e 100644 (file)
@@ -26,6 +26,21 @@ struct UndoItem *undo, *redo; // the undo and redo stacks
 
 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;
@@ -175,6 +190,8 @@ void init_stuff (int argc, char *argv[])
       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;
@@ -214,6 +231,37 @@ void init_stuff (int argc, char *argv[])
   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();
@@ -274,7 +322,6 @@ main (int argc, char *argv[])
   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();
index d52b47626fda5bac41cc60d5102c8f871638d1e7..6c087d3a0dc95c74dfd9276bdabd577895087316 100644 (file)
@@ -1048,7 +1048,6 @@ on_viewNextPage_activate               (GtkMenuItem     *menuitem,
   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;
   }
@@ -1105,7 +1104,6 @@ on_journalNewPageBefore_activate       (GtkMenuItem     *menuitem,
 
   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);
@@ -1127,7 +1125,6 @@ on_journalNewPageAfter_activate        (GtkMenuItem     *menuitem,
 
   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);
@@ -1149,7 +1146,6 @@ on_journalNewPageEnd_activate          (GtkMenuItem     *menuitem,
 
   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);
@@ -1172,7 +1168,6 @@ on_journalDeletePage_activate          (GtkMenuItem     *menuitem,
 
   end_text();
   reset_focus();
-  if (page_ops_forbidden()) return;
   if (journal.npages == 1) return;
   reset_selection();  
   prepare_new_undo();
@@ -2391,11 +2386,9 @@ on_canvas_button_press_event           (GtkWidget       *widget,
   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);
@@ -2800,7 +2793,6 @@ on_spinPageNo_value_changed            (GtkSpinButton   *spinbutton,
   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;
   }
index 016fcd4cd63bc79c3a65ed47d18186740aab4959..2b3f361df7e7cac08cf89dc0a83e7cc4c49144b5 100644 (file)
@@ -16,6 +16,7 @@
 #include <locale.h>
 #include <glib.h>
 #include <glib/gstdio.h>
+#include <poppler/glib/poppler.h>
 
 #include "xournal.h"
 #include "xo-interface.h"
@@ -77,8 +78,6 @@ gboolean save_journal(const char *filename)
   struct Item *item;
   int i, is_clone;
   char *tmpfn, *tmpstr;
-  gchar *pdfbuf;
-  gsize pdflen;
   gboolean success;
   FILE *tmpf;
   GList *pagelist, *layerlist, *itemlist, *list;
@@ -142,13 +141,11 @@ gboolean save_journal(const char *filename)
         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) {
@@ -790,6 +787,7 @@ gboolean open_journal(char *filename)
   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;
 }
@@ -930,23 +928,6 @@ struct Background *attempt_screenshot_bg(void)
 
 /************** 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)
@@ -955,46 +936,50 @@ 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;
@@ -1005,125 +990,49 @@ void bgpdf_child_handler(GPid pid, gint status, gpointer data)
     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 */
@@ -1133,103 +1042,107 @@ void shutdown_bgpdf(void)
   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)
 {
@@ -1241,7 +1154,8 @@ 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);
     }
   }
@@ -1562,7 +1476,7 @@ void save_config_to_file(void)
     " 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)",
index 5fcf6e83f0a12dae0b8912daa6243d1bbbaced88..fab3139c683c9152a0d934dc3a5d10970b8f57cc 100644 (file)
@@ -23,11 +23,10 @@ GList *attempt_load_gv_bg(char *filename);
 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);
index f10b134ab8180946d306a064421f12fb8a65fdd4..3f761e11c5f2b7125f9f57c8ca70117950184c7f 100644 (file)
@@ -1911,11 +1911,10 @@ create_winMain (void)
   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);
@@ -1939,6 +1938,7 @@ create_winMain (void)
   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),
@@ -3010,7 +3010,7 @@ create_zoomDialog (void)
   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);
index 410797cd875af6a4ec2a19fbb298a56524389482..a5329c3a49d8761ffba5bd28deb3aea9c177c1e4 100644 (file)
@@ -351,10 +351,9 @@ void get_pointer_coords(GdkEvent *event, gdouble *ret)
 
 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;
@@ -369,18 +368,26 @@ void fix_xinput_coords(GdkEvent *event)
     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
 }
 
@@ -512,6 +519,7 @@ void update_canvas_bg(struct Page *pg)
   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));
@@ -596,15 +604,23 @@ void update_canvas_bg(struct Page *pg)
   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)
@@ -624,6 +640,8 @@ void rescale_bg_pixmaps(void)
   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;
@@ -649,10 +667,24 @@ void rescale_bg_pixmaps(void)
         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;
     }
   }
 }
@@ -1591,12 +1623,6 @@ gboolean ok_to_close(void)
   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)
 {
@@ -1622,6 +1648,7 @@ void reset_selection(void)
   update_thickness_buttons();
   update_color_buttons();
   update_font_button();
+  update_cursor();
 }
 
 void move_journal_items_by(GList *itemlist, double dx, double dy,
@@ -1883,6 +1910,8 @@ void allow_all_accels(void)
       "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)
index 4ade904c130e9e278810caaefa7618b7ff8e088f..d966fa4fd660cc62b64c1b42f77138e205c4620d 100644 (file)
@@ -68,7 +68,6 @@ void process_papercolor_activate(GtkMenuItem *menuitem, int color);
 void process_paperstyle_activate(GtkMenuItem *menuitem, int style);
 
 gboolean ok_to_close(void);
-gboolean page_ops_forbidden(void);
 
 void reset_focus(void);
 
index 47fd6137b2c074b597677a628929a93789324f5f..8f6f609ef439f62966a7a179407b1b9a8a07f11f 100644 (file)
@@ -1077,6 +1077,11 @@ void clipboard_paste(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
index 6a89886b868fc965b2155a759370bd136229a32b..cb480b1936d0192b7097337fb4a774f0932547e0 100644 (file)
@@ -711,29 +711,34 @@ int pdf_draw_bitmap_background(struct Page *pg, GString *str,
   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);
@@ -748,6 +753,7 @@ int pdf_draw_bitmap_background(struct Page *pg, GString *str,
   }
   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, 
@@ -1172,8 +1178,6 @@ gboolean print_to_pdf(char *filename)
   struct XrefTable xref;
   GList *pglist;
   struct Page *pg;
-  char *buf;
-  gsize len;
   gboolean annot, uses_pdf;
   gboolean use_hiliter;
   struct PdfInfo pdfinfo;
@@ -1195,11 +1199,9 @@ gboolean print_to_pdf(char *filename)
   }
   
   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) {
@@ -1407,6 +1409,9 @@ void print_background(GnomePrintContext *gpc, struct Page *pg, gboolean *abort)
   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);
@@ -1434,22 +1439,25 @@ void print_background(GnomePrintContext *gpc, struct Page *pg, gboolean *abort)
     }
     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.);
@@ -1459,6 +1467,7 @@ void print_background(GnomePrintContext *gpc, struct Page *pg, gboolean *abort)
     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;
   }
index aadc1ea4a5c23c5d1f19d904f8538351ab504502..f6cc9675342dc538ccc093148a425bcbc95d8697 100644 (file)
@@ -1,7 +1,8 @@
 #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). */
@@ -27,6 +28,7 @@
 #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
 
@@ -53,9 +55,9 @@ typedef struct Background {
   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
@@ -310,35 +312,32 @@ typedef struct UndoItem {
 
 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
 
index 0b01c6e49fb17327528f9ea20c16363ead8d9176..04760607f81d2e99279cfbb25548e15c6831a43f 100644 (file)
 
          <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>
@@ -3681,7 +3680,7 @@ points</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</property>
                  <signal name="value_changed" handler="on_spinZoom_value_changed" last_modification_time="Sat, 22 Jul 2006 21:04:21 GMT"/>
                </widget>
                <packing>