]> git.donarmstrong.com Git - xournal.git/blobdiff - src/xo-callbacks.c
Print via gtk-print instead of libgnomeprint
[xournal.git] / src / xo-callbacks.c
index 39204f05d4df59ac4ebd9fd3a576062eab8ba160..34a7c89b86cf5306b1c79764a2a92b60e680f23f 100644 (file)
@@ -7,8 +7,8 @@
 #include <gtk/gtk.h>
 #include <libgnomecanvas/libgnomecanvas.h>
 #include <time.h>
-#include <libgnomeprintui/gnome-print-dialog.h>
 #include <glib/gstdio.h>
+#include <gdk/gdkkeysyms.h>
 
 #include "xournal.h"
 #include "xo-callbacks.h"
@@ -18,6 +18,7 @@
 #include "xo-file.h"
 #include "xo-paint.h"
 #include "xo-print.h"
+#include "xo-shapes.h"
 
 void
 on_fileNew_activate                    (GtkMenuItem     *menuitem,
@@ -49,15 +50,15 @@ on_fileNewBackground_activate          (GtkMenuItem     *menuitem,
   reset_focus();
   if (!ok_to_close()) return; // user aborted on save confirmation
   
-  dialog = gtk_file_chooser_dialog_new("Open PDF", GTK_WINDOW (winMain),
+  dialog = gtk_file_chooser_dialog_new(_("Open PDF"), GTK_WINDOW (winMain),
      GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
      GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
      
   filt_all = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_all, "All files");
+  gtk_file_filter_set_name(filt_all, _("All files"));
   gtk_file_filter_add_pattern(filt_all, "*");
   filt_pdf = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_pdf, "PDF files");
+  gtk_file_filter_set_name(filt_pdf, _("PDF files"));
   gtk_file_filter_add_pattern(filt_pdf, "*.pdf");
   gtk_file_filter_add_pattern(filt_pdf, "*.PDF");
   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_pdf);
@@ -65,7 +66,7 @@ on_fileNewBackground_activate          (GtkMenuItem     *menuitem,
 
   if (ui.default_path!=NULL) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER (dialog), ui.default_path);
 
-  attach_opt = gtk_check_button_new_with_label("Attach file to the journal");
+  attach_opt = gtk_check_button_new_with_label(_("Attach file to the journal"));
   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(attach_opt), FALSE);
   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER (dialog), attach_opt);
   
@@ -100,7 +101,7 @@ on_fileNewBackground_activate          (GtkMenuItem     *menuitem,
   
   /* open failed */
   dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
-    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Error opening file '%s'", filename);
+    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error opening file '%s'"), filename);
   gtk_dialog_run(GTK_DIALOG(dialog));
   gtk_widget_destroy(dialog);
   g_free(filename);
@@ -120,15 +121,15 @@ on_fileOpen_activate                   (GtkMenuItem     *menuitem,
   reset_focus();
   if (!ok_to_close()) return; // user aborted on save confirmation
   
-  dialog = gtk_file_chooser_dialog_new("Open Journal", GTK_WINDOW (winMain),
+  dialog = gtk_file_chooser_dialog_new(_("Open Journal"), GTK_WINDOW (winMain),
      GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
      GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
      
   filt_all = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_all, "All files");
+  gtk_file_filter_set_name(filt_all, _("All files"));
   gtk_file_filter_add_pattern(filt_all, "*");
   filt_xoj = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_xoj, "Xournal files");
+  gtk_file_filter_set_name(filt_xoj, _("Xournal files"));
   gtk_file_filter_add_pattern(filt_xoj, "*.xoj");
   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_xoj);
   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_all);
@@ -149,7 +150,7 @@ on_fileOpen_activate                   (GtkMenuItem     *menuitem,
   
   /* open failed */
   dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
-    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Error opening file '%s'", filename);
+    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error opening file '%s'"), filename);
   gtk_dialog_run(GTK_DIALOG(dialog));
   gtk_widget_destroy(dialog);
   g_free(filename);
@@ -178,7 +179,7 @@ on_fileSave_activate                   (GtkMenuItem     *menuitem,
   set_cursor_busy(FALSE);
   /* save failed */
   dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
-    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Error saving file '%s'", ui.filename);
+    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error saving file '%s'"), ui.filename);
   gtk_dialog_run(GTK_DIALOG(dialog));
   gtk_widget_destroy(dialog);
 }
@@ -198,7 +199,7 @@ on_fileSaveAs_activate                 (GtkMenuItem     *menuitem,
   
   end_text();
   reset_focus();
-  dialog = gtk_file_chooser_dialog_new("Save Journal", GTK_WINDOW (winMain),
+  dialog = gtk_file_chooser_dialog_new(_("Save Journal"), GTK_WINDOW (winMain),
      GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
      GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
      
@@ -223,10 +224,10 @@ on_fileSaveAs_activate                 (GtkMenuItem     *menuitem,
   }
      
   filt_all = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_all, "All files");
+  gtk_file_filter_set_name(filt_all, _("All files"));
   gtk_file_filter_add_pattern(filt_all, "*");
   filt_xoj = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_xoj, "Xournal files");
+  gtk_file_filter_set_name(filt_xoj, _("Xournal files"));
   gtk_file_filter_add_pattern(filt_xoj, "*.xoj");
   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_xoj);
   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_all);
@@ -252,7 +253,7 @@ on_fileSaveAs_activate                 (GtkMenuItem     *menuitem,
     if (warn) {
       warning_dialog = gtk_message_dialog_new(GTK_WINDOW(winMain), 
         GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
-        "Should the file %s be overwritten?", filename);
+        _("Should the file %s be overwritten?"), filename);
       if (gtk_dialog_run(GTK_DIALOG(warning_dialog)) == GTK_RESPONSE_YES)
         warn = FALSE;
       gtk_widget_destroy(warning_dialog);
@@ -271,7 +272,7 @@ on_fileSaveAs_activate                 (GtkMenuItem     *menuitem,
   set_cursor_busy(FALSE);
   /* save failed */
   dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
-    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Error saving file '%s'", filename);
+    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error saving file '%s'"), filename);
   gtk_dialog_run(GTK_DIALOG(dialog));
   gtk_widget_destroy(dialog);
   g_free(filename);
@@ -285,87 +286,57 @@ on_filePrintOptions_activate           (GtkMenuItem     *menuitem,
 
 }
 
-
 void
 on_filePrint_activate                  (GtkMenuItem     *menuitem,
                                         gpointer         user_data)
 {
-  GtkWidget *printDialog, *preview;
-  GnomePrintJob *gpj;
+#if GTK_CHECK_VERSION(2, 10, 0)
+  GtkPrintOperation *print;
+  GtkPrintOperationResult res;
+  
   int fromPage, toPage;
   int response;
-  char *in_fn;
-  guchar *s;
-  GnomePrintConfig *config = gnome_print_config_default();
+  char *in_fn, *p;
 
   end_text();
   reset_focus();
-  if (ui.filename!=NULL) {
-    if (g_str_has_suffix(ui.filename, ".xoj")) {
-      in_fn = g_strdup(ui.filename);
-      g_strlcpy(g_strrstr(in_fn, "xoj"), "pdf", 4);
-    } 
-    else
-      in_fn = g_strdup_printf("%s.pdf", ui.filename);
-    gnome_print_config_set(config, (guchar *)"Printer", (guchar *)"PDF");
-    gnome_print_config_set(config, (guchar *)GNOME_PRINT_KEY_OUTPUT_FILENAME, (guchar *)in_fn);
-    gnome_print_config_set(config, (guchar *)"Settings.Transport.Backend.FileName", (guchar *)in_fn);
-    g_strlcpy(g_strrstr(in_fn, "pdf"), "ps", 3);
-    gnome_print_config_set(config, (guchar *)"Printer", (guchar *)"GENERIC");
-    gnome_print_config_set (config, (guchar *)GNOME_PRINT_KEY_OUTPUT_FILENAME, (guchar *)in_fn);
-    s = gnome_print_config_get(config, (guchar *)"Settings.Transport.Backend.FileName");
-    if (s != NULL) {
-      g_free(s);
-      gnome_print_config_set(config, (guchar *)"Settings.Transport.Backend.FileName", (guchar *)in_fn);
-    }
-    g_free(in_fn);
-  }
-  
-  gpj = gnome_print_job_new(config); /* was NULL */
-  gnome_print_config_unref(config);
-/* end */
-  printDialog = gnome_print_dialog_new(gpj, (guchar *)"Print", GNOME_PRINT_DIALOG_RANGE);
-  gnome_print_dialog_construct_range_page(GNOME_PRINT_DIALOG(printDialog),
-    GNOME_PRINT_RANGE_ALL | GNOME_PRINT_RANGE_RANGE,
-    1, journal.npages, (guchar *)"Current page", (guchar *)"Pages");
-  /* don't have "Current page" as option, else it becomes the default!! */
-  
-  gtk_dialog_set_response_sensitive(GTK_DIALOG(printDialog),
-                         GNOME_PRINT_DIALOG_RESPONSE_PREVIEW, FALSE);
-  /* the print-job-preview "feature" is completely, hopelessly broken */                       
-
-  response = gtk_dialog_run(GTK_DIALOG(printDialog));
-  if (response <= 0) {
-    gtk_widget_destroy(printDialog);
-    return;
-  }
-
+  if (!gtk_check_version(2, 10, 0)) {
+    print = gtk_print_operation_new();
 /*
-  if (response == GNOME_PRINT_DIALOG_RESPONSE_PREVIEW) {
-    print_job_render(gpj, 0, journal.npages-1);
-    gtk_widget_destroy(printDialog);
-    preview = gnome_print_job_preview_new(gpj, (guchar *)"Preview");
-    try_fix_print_preview_ui(preview);
-    gtk_window_set_modal(GTK_WINDOW(preview), TRUE);
-    gtk_widget_show_all(preview);
-  }
+    if (!ui.print_settings)
+      ui.print_settings = gtk_print_settings_new();
+    if (ui.filename!=NULL) {
+      if (g_str_has_suffix(ui.filename, ".xoj")) {
+        in_fn = g_strdup(ui.filename);
+        g_strlcpy(g_strrstr(in_fn, "xoj"), "pdf", 4);
+      } 
+      else in_fn = g_strdup_printf("%s.pdf", ui.filename);
+      gtk_print_settings_set(ui.print_settings, GTK_PRINT_SETTINGS_OUTPUT_URI,
+         g_filename_to_uri(in_fn, NULL, NULL));
+      g_free(in_fn);
+    }
 */
-
-  if (response == GNOME_PRINT_DIALOG_RESPONSE_PRINT) {
-    switch(gnome_print_dialog_get_range(GNOME_PRINT_DIALOG(printDialog))) {
-      case GNOME_PRINT_RANGE_RANGE: 
-        gnome_print_dialog_get_range_page(GNOME_PRINT_DIALOG(printDialog), &fromPage, &toPage);
-        fromPage--;
-        toPage--;
-        break;
-      default: 
-        fromPage = 0; 
-        toPage = journal.npages-1;
+    if (ui.print_settings!=NULL)
+       gtk_print_operation_set_print_settings (print, ui.print_settings);
+    gtk_print_operation_set_n_pages(print, journal.npages);
+    gtk_print_operation_set_current_page(print, ui.pageno);
+    gtk_print_operation_set_show_progress(print, TRUE);
+    if (ui.filename!=NULL) {
+      p = g_utf8_strrchr(ui.filename, -1, '/');
+      if (p==NULL) p = ui.filename;
+      else p++;
+      gtk_print_operation_set_job_name(print, p);
     }
-
-    gtk_widget_destroy(printDialog);
-    print_job_render(gpj, fromPage, toPage);
+    g_signal_connect (print, "draw_page", G_CALLBACK (print_job_render_page), NULL);
+    res = gtk_print_operation_run(print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+                                  GTK_WINDOW(winMain), NULL);
+    if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
+      if (ui.print_settings!=NULL) g_object_unref(ui.print_settings);
+      ui.print_settings = g_object_ref(gtk_print_operation_get_print_settings(print));
+    }
+    g_object_unref(print);
   }
+#endif
 }
 
 
@@ -379,12 +350,11 @@ on_filePrintPDF_activate               (GtkMenuItem     *menuitem,
   char *filename, *in_fn;
   char stime[30];
   time_t curtime;
-  int response;
   gboolean warn;
   
   end_text();
   reset_focus();
-  dialog = gtk_file_chooser_dialog_new("Export to PDF", GTK_WINDOW (winMain),
+  dialog = gtk_file_chooser_dialog_new(_("Export to PDF"), GTK_WINDOW (winMain),
      GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
      GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
      
@@ -407,10 +377,10 @@ on_filePrintPDF_activate               (GtkMenuItem     *menuitem,
   }
      
   filt_all = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_all, "All files");
+  gtk_file_filter_set_name(filt_all, _("All files"));
   gtk_file_filter_add_pattern(filt_all, "*");
   filt_pdf = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_pdf, "PDF files");
+  gtk_file_filter_set_name(filt_pdf, _("PDF files"));
   gtk_file_filter_add_pattern(filt_pdf, "*.pdf");
   gtk_file_filter_add_pattern(filt_pdf, "*.PDF");
   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_pdf);
@@ -428,7 +398,7 @@ on_filePrintPDF_activate               (GtkMenuItem     *menuitem,
     if (warn) {
       warning_dialog = gtk_message_dialog_new(GTK_WINDOW(winMain),
         GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
-        "Should the file %s be overwritten?", filename);
+        _("Should the file %s be overwritten?"), filename);
       if (gtk_dialog_run(GTK_DIALOG(warning_dialog)) == GTK_RESPONSE_YES)
         warn = FALSE;
       gtk_widget_destroy(warning_dialog);
@@ -441,7 +411,7 @@ on_filePrintPDF_activate               (GtkMenuItem     *menuitem,
   if (!print_to_pdf(filename)) {
     set_cursor_busy(FALSE);
     dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
-      GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Error creating file '%s'", filename);
+      GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error creating file '%s'"), filename);
     gtk_dialog_run(GTK_DIALOG(dialog));
     gtk_widget_destroy(dialog);
   }
@@ -472,6 +442,7 @@ on_editUndo_activate                   (GtkMenuItem     *menuitem,
   struct Background *tmp_bg;
   double tmp_x, tmp_y;
   gchar *tmpstr;
+  GnomeCanvasGroup *group;
   
   end_text();
   reset_focus();
@@ -485,7 +456,7 @@ on_editUndo_activate                   (GtkMenuItem     *menuitem,
     undo->layer->items = g_list_remove(undo->layer->items, undo->item);
     undo->layer->nitems--;
   }
-  else if (undo->type == ITEM_ERASURE) {
+  else if (undo->type == ITEM_ERASURE || undo->type == ITEM_RECOGNIZER) {
     for (list = undo->erasurelist; list!=NULL; list = list->next) {
       erasure = (struct UndoErasureData *)list->data;
       // delete all the created items
@@ -574,6 +545,11 @@ on_editUndo_activate                   (GtkMenuItem     *menuitem,
     move_journal_items_by(undo->itemlist, -undo->val_x, -undo->val_y,
                             undo->layer2, undo->layer, undo->auxlist);
   }
+  else if (undo->type == ITEM_RESIZESEL) {
+    resize_journal_items_by(undo->itemlist, 
+      1/undo->scaling_x, 1/undo->scaling_y,
+      -undo->val_x/undo->scaling_x, -undo->val_y/undo->scaling_y);
+  }
   else if (undo->type == ITEM_PASTE) {
     for (itemlist = undo->itemlist; itemlist != NULL; itemlist = itemlist->next) {
       it = (struct Item *)itemlist->data;
@@ -622,10 +598,12 @@ on_editUndo_activate                   (GtkMenuItem     *menuitem,
       g_memmove(&tmp_brush, &(it->brush), sizeof(struct Brush));
       g_memmove(&(it->brush), list->data, sizeof(struct Brush));
       g_memmove(list->data, &tmp_brush, sizeof(struct Brush));
-      if (it->type == ITEM_STROKE && it->canvas_item != NULL)
-        gnome_canvas_item_set(it->canvas_item, 
-          "fill-color-rgba", it->brush.color_rgba,
-          "width-units", it->brush.thickness, NULL);
+      if (it->type == ITEM_STROKE && it->canvas_item != NULL) {
+        // remark: a variable-width item might have lost its variable-width
+        group = (GnomeCanvasGroup *) it->canvas_item->parent;
+        gtk_object_destroy(GTK_OBJECT(it->canvas_item));
+        make_canvas_item_one(group, it);
+      }
       if (it->type == ITEM_TEXT && it->canvas_item != NULL)
         gnome_canvas_item_set(it->canvas_item, 
           "fill-color-rgba", it->brush.color_rgba, NULL);
@@ -678,6 +656,7 @@ on_editRedo_activate                   (GtkMenuItem     *menuitem,
   struct Layer *l;
   double tmp_x, tmp_y;
   gchar *tmpstr;
+  GnomeCanvasGroup *group;
   
   end_text();
   reset_focus();
@@ -690,7 +669,7 @@ on_editRedo_activate                   (GtkMenuItem     *menuitem,
     redo->layer->items = g_list_append(redo->layer->items, redo->item);
     redo->layer->nitems++;
   }
-  else if (redo->type == ITEM_ERASURE) {
+  else if (redo->type == ITEM_ERASURE || redo->type == ITEM_RECOGNIZER) {
     for (list = redo->erasurelist; list!=NULL; list = list->next) {
       erasure = (struct UndoErasureData *)list->data;
       target = g_list_find(redo->layer->items, erasure->item);
@@ -787,6 +766,10 @@ on_editRedo_activate                   (GtkMenuItem     *menuitem,
     move_journal_items_by(redo->itemlist, redo->val_x, redo->val_y,
                             redo->layer, redo->layer2, NULL);
   }
+  else if (redo->type == ITEM_RESIZESEL) {
+    resize_journal_items_by(redo->itemlist, 
+          redo->scaling_x, redo->scaling_y, redo->val_x, redo->val_y);
+  }
   else if (redo->type == ITEM_PASTE) {
     for (itemlist = redo->itemlist; itemlist != NULL; itemlist = itemlist->next) {
       it = (struct Item *)itemlist->data;
@@ -828,10 +811,12 @@ on_editRedo_activate                   (GtkMenuItem     *menuitem,
       g_memmove(&tmp_brush, &(it->brush), sizeof(struct Brush));
       g_memmove(&(it->brush), list->data, sizeof(struct Brush));
       g_memmove(list->data, &tmp_brush, sizeof(struct Brush));
-      if (it->type == ITEM_STROKE && it->canvas_item != NULL)
-        gnome_canvas_item_set(it->canvas_item, 
-          "fill-color-rgba", it->brush.color_rgba,
-          "width-units", it->brush.thickness, NULL);
+      if (it->type == ITEM_STROKE && it->canvas_item != NULL) {
+        // remark: a variable-width item might have lost its variable-width
+        group = (GnomeCanvasGroup *) it->canvas_item->parent;
+        gtk_object_destroy(GTK_OBJECT(it->canvas_item));
+        make_canvas_item_one(group, it);
+      }
       if (it->type == ITEM_TEXT && it->canvas_item != NULL)
         gnome_canvas_item_set(it->canvas_item, 
           "fill-color-rgba", it->brush.color_rgba, NULL);
@@ -1032,7 +1017,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;
   }
@@ -1089,7 +1073,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);
@@ -1111,7 +1094,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);
@@ -1133,7 +1115,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);
@@ -1156,7 +1137,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();
@@ -1463,12 +1443,12 @@ on_journalLoadBackground_activate      (GtkMenuItem     *menuitem,
   
   end_text();
   reset_focus();
-  dialog = gtk_file_chooser_dialog_new("Open Background", GTK_WINDOW (winMain),
+  dialog = gtk_file_chooser_dialog_new(_("Open Background"), GTK_WINDOW (winMain),
      GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
      GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
 
   filt_all = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_all, "All files");
+  gtk_file_filter_set_name(filt_all, _("All files"));
   gtk_file_filter_add_pattern(filt_all, "*");
   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_all);
 
@@ -1476,7 +1456,7 @@ on_journalLoadBackground_activate      (GtkMenuItem     *menuitem,
 
   if (!gtk_check_version(2, 6, 0)) {
     filt_pix = gtk_file_filter_new();
-    gtk_file_filter_set_name(filt_pix, "Bitmap files");
+    gtk_file_filter_set_name(filt_pix, _("Bitmap files"));
     gtk_file_filter_add_pixbuf_formats(filt_pix);
     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_pix);
   }
@@ -1484,14 +1464,14 @@ on_journalLoadBackground_activate      (GtkMenuItem     *menuitem,
 #endif
 
   filt_pspdf = gtk_file_filter_new();
-  gtk_file_filter_set_name(filt_pspdf, "PS/PDF files (as bitmaps)");
+  gtk_file_filter_set_name(filt_pspdf, _("PS/PDF files (as bitmaps)"));
   gtk_file_filter_add_pattern(filt_pspdf, "*.ps");
   gtk_file_filter_add_pattern(filt_pspdf, "*.PS");
   gtk_file_filter_add_pattern(filt_pspdf, "*.pdf");
   gtk_file_filter_add_pattern(filt_pspdf, "*.PDF");
   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_pspdf);
 
-  attach_opt = gtk_check_button_new_with_label("Attach file to the journal");
+  attach_opt = gtk_check_button_new_with_label(_("Attach file to the journal"));
   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(attach_opt), FALSE);
   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER (dialog), attach_opt);
 
@@ -1514,7 +1494,7 @@ on_journalLoadBackground_activate      (GtkMenuItem     *menuitem,
   if (bglist == NULL) {
     dialog = gtk_message_dialog_new(GTK_WINDOW(winMain), GTK_DIALOG_MODAL,
       GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
-      "Error opening background '%s'", filename);
+      _("Error opening background '%s'"), filename);
     gtk_dialog_run(GTK_DIALOG(dialog));
     gtk_widget_destroy(dialog);
     g_free(filename);
@@ -1681,8 +1661,9 @@ on_toolsPen_activate                   (GtkMenuItem     *menuitem,
   reset_focus();
   reset_selection();
   ui.toolno[0] = TOOL_PEN;
-  ui.ruler[0] = FALSE;
   ui.cur_brush = &(ui.brushes[0][TOOL_PEN]);
+  ui.cur_brush->ruler = ui.default_brushes[TOOL_PEN].ruler;
+  ui.cur_brush->recognizer = ui.default_brushes[TOOL_PEN].recognizer;
   update_mapping_linkings(TOOL_PEN);
   update_tool_buttons();
   update_tool_menu();
@@ -1710,7 +1691,6 @@ on_toolsEraser_activate                (GtkMenuItem     *menuitem,
   reset_focus();
   reset_selection();
   ui.toolno[0] = TOOL_ERASER;
-  ui.ruler[0] = FALSE;
   ui.cur_brush = &(ui.brushes[0][TOOL_ERASER]);
   update_mapping_linkings(TOOL_ERASER);
   update_tool_buttons();
@@ -1739,8 +1719,9 @@ on_toolsHighlighter_activate           (GtkMenuItem     *menuitem,
   reset_focus();
   reset_selection();
   ui.toolno[0] = TOOL_HIGHLIGHTER;
-  ui.ruler[0] = FALSE;
   ui.cur_brush = &(ui.brushes[0][TOOL_HIGHLIGHTER]);
+  ui.cur_brush->ruler = ui.default_brushes[TOOL_HIGHLIGHTER].ruler;
+  ui.cur_brush->recognizer = ui.default_brushes[TOOL_HIGHLIGHTER].recognizer;
   update_mapping_linkings(TOOL_HIGHLIGHTER);
   update_tool_buttons();
   update_tool_menu();
@@ -1767,7 +1748,6 @@ on_toolsText_activate                  (GtkMenuItem     *menuitem,
   reset_focus();
   reset_selection();
   ui.toolno[0] = TOOL_TEXT;
-  ui.ruler[0] = FALSE;
   ui.cur_brush = &(ui.brushes[0][TOOL_PEN]);
   update_mapping_linkings(-1);
   update_tool_buttons();
@@ -1803,7 +1783,6 @@ on_toolsSelectRectangle_activate       (GtkMenuItem     *menuitem,
   end_text();
   reset_focus();
   ui.toolno[0] = TOOL_SELECTRECT;
-  ui.ruler[0] = FALSE;
   update_mapping_linkings(-1);
   update_tool_buttons();
   update_tool_menu();
@@ -1831,7 +1810,6 @@ on_toolsVerticalSpace_activate         (GtkMenuItem     *menuitem,
   reset_focus();
   reset_selection();
   ui.toolno[0] = TOOL_VERTSPACE;
-  ui.ruler[0] = FALSE;
   update_mapping_linkings(-1);
   update_tool_buttons();
   update_tool_menu();
@@ -2068,7 +2046,7 @@ on_toolsTextFont_activate              (GtkMenuItem     *menuitem,
   GtkWidget *dialog;
   gchar *str;
   
-  dialog = gtk_font_selection_dialog_new("Select Font");
+  dialog = gtk_font_selection_dialog_new(_("Select Font"));
   str = make_cur_font_name();
   gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(dialog), str);
   g_free(str);
@@ -2093,7 +2071,6 @@ on_toolsDefaultPen_activate            (GtkMenuItem     *menuitem,
   g_memmove(&(ui.brushes[0][TOOL_PEN]), ui.default_brushes+TOOL_PEN, sizeof(struct Brush));
   ui.toolno[0] = TOOL_PEN;
   ui.cur_brush = &(ui.brushes[0][TOOL_PEN]);
-  ui.ruler[0] = FALSE;
   update_mapping_linkings(TOOL_PEN);
   update_tool_buttons();
   update_tool_menu();
@@ -2114,7 +2091,6 @@ on_toolsDefaultEraser_activate         (GtkMenuItem     *menuitem,
   g_memmove(&(ui.brushes[0][TOOL_ERASER]), ui.default_brushes+TOOL_ERASER, sizeof(struct Brush));
   ui.toolno[0] = TOOL_ERASER;
   ui.cur_brush = &(ui.brushes[0][TOOL_ERASER]);
-  ui.ruler[0] = FALSE;
   update_mapping_linkings(TOOL_ERASER);
   update_tool_buttons();
   update_tool_menu();
@@ -2135,7 +2111,6 @@ on_toolsDefaultHighlighter_activate    (GtkMenuItem     *menuitem,
   g_memmove(&(ui.brushes[0][TOOL_HIGHLIGHTER]), ui.default_brushes+TOOL_HIGHLIGHTER, sizeof(struct Brush));
   ui.toolno[0] = TOOL_HIGHLIGHTER;
   ui.cur_brush = &(ui.brushes[0][TOOL_HIGHLIGHTER]);
-  ui.ruler[0] = FALSE;
   update_mapping_linkings(TOOL_HIGHLIGHTER);
   update_tool_buttons();
   update_tool_menu();
@@ -2153,7 +2128,6 @@ on_toolsDefaultText_activate           (GtkMenuItem     *menuitem,
   reset_focus();
   reset_selection();
   ui.toolno[0] = TOOL_TEXT;
-  ui.ruler[0] = FALSE;
   ui.cur_brush = &(ui.brushes[0][TOOL_PEN]);
   ui.cur_brush->color_no = ui.default_brushes[TOOL_PEN].color_no;
   ui.cur_brush->color_rgba = ui.default_brushes[TOOL_PEN].color_rgba;
@@ -2207,7 +2181,7 @@ void
 on_toolsRuler_activate                 (GtkMenuItem     *menuitem,
                                         gpointer         user_data)
 {
-  gboolean active;
+  gboolean active, current;
   
   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_CHECK_MENU_ITEM)
     active = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem));
@@ -2215,11 +2189,12 @@ on_toolsRuler_activate                 (GtkMenuItem     *menuitem,
     active = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem));
 
   if (ui.cur_mapping != 0) return;
-  if (active == ui.ruler[0]) return;
+  current = (ui.toolno[0] == TOOL_PEN || ui.toolno[0] == TOOL_HIGHLIGHTER) && ui.cur_brush->ruler;
+  if (active == current) return;
   
   end_text();
   reset_focus();
-  if (active && (ui.toolno[0]!=TOOL_PEN && ui.toolno[0]!=TOOL_HIGHLIGHTER)) {
+  if (ui.toolno[0]!=TOOL_PEN && ui.toolno[0]!=TOOL_HIGHLIGHTER) {
     reset_selection();
     ui.toolno[0] = TOOL_PEN;
     ui.cur_brush = &(ui.brushes[0][TOOL_PEN]);
@@ -2229,7 +2204,45 @@ on_toolsRuler_activate                 (GtkMenuItem     *menuitem,
     update_cursor();
   }
   
-  ui.ruler[0] = active;
+  ui.cur_brush->ruler = active;
+  if (active) ui.cur_brush->recognizer = FALSE;
+  update_mapping_linkings(ui.toolno[0]);
+  update_ruler_indicator();
+}
+
+
+void
+on_toolsReco_activate                  (GtkMenuItem *menuitem,
+                                        gpointer         user_data)
+{
+  gboolean active, current;
+  
+  if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_CHECK_MENU_ITEM)
+    active = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem));
+  else
+    active = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem));
+
+  if (ui.cur_mapping != 0) return;
+  current = (ui.toolno[0] == TOOL_PEN || ui.toolno[0] == TOOL_HIGHLIGHTER) && ui.cur_brush->recognizer;
+  if (active == current) return;
+  
+  end_text();
+  reset_focus();
+  if (ui.toolno[0]!=TOOL_PEN && ui.toolno[0]!=TOOL_HIGHLIGHTER) {
+    reset_selection();
+    ui.toolno[0] = TOOL_PEN;
+    ui.cur_brush = &(ui.brushes[0][TOOL_PEN]);
+    update_color_menu();
+    update_tool_buttons();
+    update_tool_menu();
+    update_cursor();
+  }
+  
+  ui.cur_brush->recognizer = active;
+  if (active) {
+    ui.cur_brush->ruler = FALSE;
+    reset_recognizer();
+  }
   update_mapping_linkings(ui.toolno[0]);
   update_ruler_indicator();
 }
@@ -2284,7 +2297,6 @@ on_buttonToolDefault_clicked           (GtkToolButton   *toolbutton,
   switch_mapping(0);
   if (ui.toolno[0] < NUM_STROKE_TOOLS) {
     g_memmove(&(ui.brushes[0][ui.toolno[0]]), ui.default_brushes+ui.toolno[0], sizeof(struct Brush));
-    ui.ruler[0] = FALSE;
     update_mapping_linkings(ui.toolno[0]);
     update_thickness_buttons();
     update_color_buttons();
@@ -2343,15 +2355,22 @@ 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);
+#endif
   if (!finite(event->x) || !finite(event->y)) return FALSE; // Xorg 7.3 bug
 
-  if (ui.cur_item_type == ITEM_TEXT && !is_event_within_textview(event))
-    end_text();
+  if (ui.cur_item_type == ITEM_TEXT) {
+    if (!is_event_within_textview(event)) end_text();
+/* // bugfix for GTK+ 2.17, no longer needed as XInput is disabled during text edition
+    else fix_extended_events(ui.cur_item->widget, (GdkEvent *)event,
+            gtk_text_view_get_window(GTK_TEXT_VIEW(ui.cur_item->widget), GTK_TEXT_WINDOW_TEXT));
+*/
+  }
   if (ui.cur_item_type == ITEM_STROKE && ui.is_corestroke && !is_core &&
       ui.cur_path.num_points == 1) { 
       // Xorg 7.3+ sent core event before XInput event: fix initial point 
@@ -2391,12 +2410,12 @@ on_canvas_button_press_event           (GtkWidget       *widget,
   if (ui.cur_layer == NULL) {
     /* warn */
     dialog = gtk_message_dialog_new(GTK_WINDOW(winMain), GTK_DIALOG_MODAL,
-      GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Drawing is not allowed on the "
-      "background layer.\n Switching to Layer 1.");
+      GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("Drawing is not allowed on the "
+      "background layer.\n Switching to Layer 1."));
     gtk_dialog_run(GTK_DIALOG(dialog));
     gtk_widget_destroy(dialog);
     on_viewShowLayer_activate(NULL, NULL);
-    return;
+    return FALSE;
   }
 
   // switch mappings if needed
@@ -2414,7 +2433,8 @@ on_canvas_button_press_event           (GtkWidget       *widget,
     }
   }
 
-  // if this can be a selection move, then it takes precedence over anything else  
+  // if this can be a selection move or resize, then it takes precedence over anything else  
+  if (start_resizesel((GdkEvent *)event)) return FALSE;
   if (start_movesel((GdkEvent *)event)) return FALSE;
   
   if (ui.toolno[mapping] != TOOL_SELECTREGION && ui.toolno[mapping] != TOOL_SELECTRECT)
@@ -2468,6 +2488,7 @@ on_canvas_button_release_event         (GtkWidget       *widget,
 
   if (ui.cur_item_type == ITEM_STROKE) {
     finalize_stroke();
+    if (ui.cur_brush->recognizer) recognize_patterns();
   }
   else if (ui.cur_item_type == ITEM_ERASURE) {
     finalize_erasure();
@@ -2478,6 +2499,9 @@ on_canvas_button_release_event         (GtkWidget       *widget,
   else if (ui.cur_item_type == ITEM_MOVESEL || ui.cur_item_type == ITEM_MOVESEL_VERT) {
     finalize_movesel();
   }
+  else if (ui.cur_item_type == ITEM_RESIZESEL) {
+    finalize_resizesel();
+  }
   else if (ui.cur_item_type == ITEM_HAND) {
     ui.cur_item_type = ITEM_NONE;
   }
@@ -2496,6 +2520,21 @@ on_canvas_enter_notify_event           (GtkWidget       *widget,
   return FALSE;
 }
 
+gboolean
+on_canvas_leave_notify_event           (GtkWidget       *widget,
+                                        GdkEventCrossing *event,
+                                        gpointer         user_data)
+{
+#ifdef INPUT_DEBUG
+  printf("DEBUG: leave notify\n");
+#endif
+  if (ui.need_emergency_disable_xinput) {
+    gtk_widget_set_extension_events(GTK_WIDGET (canvas), GDK_EXTENSION_EVENTS_NONE);
+    ui.need_emergency_disable_xinput = FALSE;
+  }
+  return FALSE;
+}
+
 
 gboolean
 on_canvas_expose_event                 (GtkWidget       *widget,
@@ -2512,6 +2551,30 @@ on_canvas_key_press_event              (GtkWidget       *widget,
                                         GdkEventKey     *event,
                                         gpointer         user_data)
 {
+  // Esc leaves text edition, or leaves fullscreen mode
+  if (event->keyval == GDK_Escape) {
+    if (ui.cur_item_type == ITEM_TEXT) { end_text(); reset_focus(); }
+    else if (ui.fullscreen) do_fullscreen(FALSE);
+  }
+  
+  // If zoomed-out and in single page mode, switch pages with PgUp/PgDn.
+  if (!ui.view_continuous && 
+      (0.96 * ui.zoom * ui.cur_page->height < 
+       GTK_WIDGET(canvas)->allocation.height)) {
+    if (event->keyval == GDK_Page_Down) {
+      end_text();
+      reset_focus();
+      if (ui.pageno == journal.npages-1) { return FALSE; }
+      do_switch_page(ui.pageno+1, TRUE, FALSE);
+    }
+    if (event->keyval == GDK_Page_Up) {
+      end_text();
+      reset_focus();
+      if (ui.pageno == 0) { return FALSE; }
+      do_switch_page(ui.pageno-1, TRUE, FALSE);
+    }
+  }
+
   return FALSE;
 }
 
@@ -2523,21 +2586,37 @@ on_canvas_motion_notify_event          (GtkWidget       *widget,
 {
   gboolean looks_wrong, is_core;
   double pt[2];
-  
-  if (ui.cur_item_type == ITEM_NONE) return FALSE; // we don't care
+
+  /* we don't care about this event unless some operation is in progress;
+     or if there's a selection (then we might want to change the mouse
+     cursor to indicate the possibility of resizing) */  
+  if (ui.cur_item_type == ITEM_NONE && ui.selection==NULL) return FALSE;
 
   is_core = (event->device == gdk_device_get_core_pointer());
   if (!ui.use_xinput && !is_core) return FALSE;
-  if (ui.use_xinput && is_core && !ui.is_corestroke) return FALSE;
   if (!is_core) fix_xinput_coords((GdkEvent *)event);
   if (!finite(event->x) || !finite(event->y)) return FALSE; // Xorg 7.3 bug
+
+  if (ui.selection!=NULL && ui.cur_item_type == ITEM_NONE) {
+    get_pointer_coords((GdkEvent *)event, pt);
+    update_cursor_for_resize(pt);
+    return FALSE;
+  }
+
+  if (ui.use_xinput && is_core && !ui.is_corestroke) return FALSE;
   if (!is_core) ui.is_corestroke = FALSE;
 
+#ifdef INPUT_DEBUG
+  printf("DEBUG: MotionNotify (%s) (x,y)=(%.2f,%.2f)\n", 
+    is_core?"core":"xinput", event->x, event->y);
+#endif
+  
   looks_wrong = !(event->state & (1<<(7+ui.which_mouse_button)));
   
   if (looks_wrong) { /* mouse button shouldn't be up... give up */
     if (ui.cur_item_type == ITEM_STROKE) {
       finalize_stroke();
+      if (ui.cur_brush->recognizer) recognize_patterns();
     }
     else if (ui.cur_item_type == ITEM_ERASURE) {
       finalize_erasure();
@@ -2548,6 +2627,9 @@ on_canvas_motion_notify_event          (GtkWidget       *widget,
     else if (ui.cur_item_type == ITEM_MOVESEL || ui.cur_item_type == ITEM_MOVESEL_VERT) {
       finalize_movesel();
     }
+    else if (ui.cur_item_type == ITEM_RESIZESEL) {
+      finalize_resizesel();
+    }
     switch_mapping(0);
     return FALSE;
   }
@@ -2569,6 +2651,9 @@ on_canvas_motion_notify_event          (GtkWidget       *widget,
   else if (ui.cur_item_type == ITEM_MOVESEL || ui.cur_item_type == ITEM_MOVESEL_VERT) {
     continue_movesel((GdkEvent *)event);
   }
+  else if (ui.cur_item_type == ITEM_RESIZESEL) {
+    continue_resizesel((GdkEvent *)event);
+  }
   else if (ui.cur_item_type == ITEM_HAND) {
     do_hand((GdkEvent *)event);
   }
@@ -2629,7 +2714,9 @@ on_optionsUseXInput_activate           (GtkMenuItem     *menuitem,
   ui.allow_xinput = ui.use_xinput =
     gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem));
 
-/* Important note: we'd like ONLY the canvas window itself to receive
+/* HOW THINGS USED TO BE:
+
+   We'd like ONLY the canvas window itself to receive
    XInput events, while its child window in the GDK hierarchy (also
    associated to the canvas widget) receives the core events.
    This way on_canvas_... will get both types of events -- otherwise,
@@ -2641,12 +2728,21 @@ on_optionsUseXInput_activate           (GtkMenuItem     *menuitem,
    also traverses GDK child windows that belong to the widget
    and sets their extension events too. We want to avoid that.
    So we use gdk_input_set_extension_events() directly on the canvas.
+
+   As much as possible, we'd like to keep doing this, though GTK+ 2.17
+   is making our life harder (crasher bugs require us to disable XInput
+   while editing text or using the layers combo box, but disabling
+   XInput while in a XInput-aware window causes the interface to become
+   non-responsive). 
 */
-   
-/*  // this causes GTK+ 2.11 bugs
-    gtk_widget_set_extension_events(GTK_WIDGET (canvas), 
+
+  // this causes core events to be discarded... unwanted!
+/*
+   gtk_widget_set_extension_events(GTK_WIDGET (canvas), 
       ui.use_xinput?GDK_EXTENSION_EVENTS_ALL:GDK_EXTENSION_EVENTS_NONE);
 */
+
+  // this version only activates extension events on the canvas's parent GdkWindow
   gdk_input_set_extension_events(GTK_WIDGET(canvas)->window, 
     GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK,
     ui.use_xinput?GDK_EXTENSION_EVENTS_ALL:GDK_EXTENSION_EVENTS_NONE);
@@ -2703,7 +2799,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;
   }
@@ -2894,18 +2989,7 @@ on_viewFullscreen_activate             (GtkMenuItem     *menuitem,
     active = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem));
 
   if (active == ui.fullscreen) return;
-  end_text();
-  reset_focus();
-  ui.fullscreen = active;
-  gtk_check_menu_item_set_active(
-    GTK_CHECK_MENU_ITEM(GET_COMPONENT("viewFullscreen")), ui.fullscreen);
-  gtk_toggle_tool_button_set_active(
-    GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonFullscreen")), ui.fullscreen);
-
-  if (ui.fullscreen) gtk_window_fullscreen(GTK_WINDOW(winMain));
-  else gtk_window_unfullscreen(GTK_WINDOW(winMain));
-  
-  update_vbox_order(ui.vertical_order[ui.fullscreen?1:0]);
+  do_fullscreen(active);
 }
 
 
@@ -2975,7 +3059,7 @@ on_mru_activate                        (GtkMenuItem     *menuitem,
 
   /* open failed */
   dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
-    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Error opening file '%s'", ui.mru[which]);
+    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error opening file '%s'"), ui.mru[which]);
   gtk_dialog_run(GTK_DIALOG(dialog));
   gtk_widget_destroy(dialog);
   delete_mru_entry(which);
@@ -3066,9 +3150,6 @@ on_button2CopyBrush_activate           (GtkMenuItem     *menuitem,
   }
   ui.linked_brush[1] = BRUSH_COPIED;
   g_memmove(&(ui.brushes[1][ui.toolno[1]]), &(ui.brushes[0][ui.toolno[1]]), sizeof(struct Brush));
-  ui.ruler[1] = ui.ruler[0];
-  if (ui.toolno[1]!=TOOL_PEN && ui.toolno[1]!=TOOL_HIGHLIGHTER)
-    ui.ruler[1] = FALSE;
 }
 
 
@@ -3156,9 +3237,6 @@ on_button3CopyBrush_activate           (GtkMenuItem     *menuitem,
   }
   ui.linked_brush[2] = BRUSH_COPIED;
   g_memmove(&(ui.brushes[2][ui.toolno[2]]), &(ui.brushes[0][ui.toolno[2]]), sizeof(struct Brush));
-  ui.ruler[2] = ui.ruler[0];
-  if (ui.toolno[2]!=TOOL_PEN && ui.toolno[2]!=TOOL_HIGHLIGHTER)
-    ui.ruler[2] = FALSE;
 }
 
 // the set zoom dialog
@@ -3288,7 +3366,6 @@ on_toolsHand_activate                  (GtkMenuItem     *menuitem,
   reset_focus();
   reset_selection();
   ui.toolno[0] = TOOL_HAND;
-  ui.ruler[0] = FALSE;
   update_mapping_linkings(-1);
   update_tool_buttons();
   update_tool_menu();
@@ -3398,3 +3475,17 @@ on_optionsAutoSavePrefs_activate       (GtkMenuItem     *menuitem,
   ui.auto_save_prefs = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem));
 }
 
+void
+on_optionsPressureSensitive_activate   (GtkMenuItem     *menuitem,
+                                        gpointer         user_data)
+{
+  int i;
+  end_text();
+  reset_focus();
+  ui.pressure_sensitivity =
+    gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem));
+  for (i=0; i<=NUM_BUTTONS; i++)
+    ui.brushes[i][TOOL_PEN].variable_width = ui.pressure_sensitivity;
+  update_mappings_menu();
+}
+