]> git.donarmstrong.com Git - xournal.git/commitdiff
workaround for GTK+ 2.17 crasher bugs (text edit box, combo box)
authorauroux <auroux>
Mon, 7 Sep 2009 04:34:02 +0000 (04:34 +0000)
committerauroux <auroux>
Mon, 7 Sep 2009 04:34:02 +0000 (04:34 +0000)
src/TODO
src/main.c
src/xo-callbacks.c
src/xo-callbacks.h
src/xo-misc.c
src/xo-misc.h
src/xo-paint.c
src/xournal.h

index e2a8d391bdeda73f5711d6aa1acd19414a391c47..594cf493a01ffaeec9db0466957a099f8f0a0fe7 100644 (file)
--- a/src/TODO
+++ b/src/TODO
@@ -36,7 +36,9 @@ DONE: Catalan translation (by David Planella); French translation
 
 ****** URGENT: gtkprint; new release by November end for Debian!
   nb: libgnomeprint produces many warnings (spinbutton; gpa assertions)
+  nb: gtkprint includes sft.c or not?? see font generation...
 
+- get GTK+ 2.17 events while editing text to work.
 - prerelease: update help file (remove references to pdftoppm/libgnomeprint
   to poppler/gtkprint
 - remove "antialias bg" flag, useless... see McElrath
@@ -46,6 +48,8 @@ DONE: Catalan translation (by David Planella); French translation
   (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?)
+- option to have buttons *toggle* the tool rather than act as tool
+   (ie button 2 causes button 1 to map to tool 2) [Dylan Thurston]
 ** 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!)
@@ -133,6 +137,7 @@ DONE: Catalan translation (by David Planella); French translation
 - 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?)
+    (also: engineering paper; isometric paper -- Dan Ott  Sep 4 '09)
 - 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)
index b900ed72649d818aeeda79432bd34c304ea7454f..129716ad971de4dafed350c37d83cdf6e83ae775 100644 (file)
@@ -26,21 +26,6 @@ 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;
@@ -161,6 +146,9 @@ void init_stuff (int argc, char *argv[])
   g_signal_connect ((gpointer) canvas, "enter_notify_event",
                     G_CALLBACK (on_canvas_enter_notify_event),
                     NULL);
+  g_signal_connect ((gpointer) canvas, "leave_notify_event",
+                    G_CALLBACK (on_canvas_leave_notify_event),
+                    NULL);
   g_signal_connect ((gpointer) canvas, "expose_event",
                     G_CALLBACK (on_canvas_expose_event),
                     NULL);
@@ -200,6 +188,7 @@ void init_stuff (int argc, char *argv[])
     gtk_widget_set_sensitive(GET_COMPONENT("optionsUseXInput"), FALSE);
 
   ui.use_xinput = ui.allow_xinput && can_xinput;
+  ui.need_emergency_disable_xinput = FALSE;
 
   gtk_check_menu_item_set_active(
     GTK_CHECK_MENU_ITEM(GET_COMPONENT("optionsAntialiasBG")), ui.antialias_bg);
@@ -234,7 +223,7 @@ void init_stuff (int argc, char *argv[])
   /* 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)) {
+  if (!gtk_check_version(2, 16, 0)) {
     g_signal_connect (
       GET_COMPONENT("menubar"),
       "event", G_CALLBACK (filter_extended_events),
@@ -259,6 +248,10 @@ void init_stuff (int argc, char *argv[])
       (gpointer)(gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(w))),
       "event", G_CALLBACK (filter_extended_events),
       NULL);
+    g_signal_connect (
+      GET_COMPONENT("comboLayer"),
+      "notify::popup-shown", G_CALLBACK (combobox_popup_disable_xinput),
+      NULL);
   }
 #endif
 
index c38299659be2ee8879e32c4ccca16f20d4be8404..6d38176e20afed678de470fee2602c5994b229ba 100644 (file)
@@ -2395,8 +2395,13 @@ on_canvas_button_press_event           (GtkWidget       *widget,
 #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 
@@ -2546,6 +2551,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,
@@ -2719,7 +2739,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,
@@ -2731,12 +2753,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);
index e42dc95d97bfe9595fb78d03b0e6929611b4b7dd..ebe9b8bf834b4b274c42bc48fb2d597a325e433b 100644 (file)
@@ -403,6 +403,11 @@ on_canvas_enter_notify_event           (GtkWidget       *widget,
                                         GdkEventCrossing *event,
                                         gpointer         user_data);
 
+gboolean
+on_canvas_leave_notify_event           (GtkWidget       *widget,
+                                        GdkEventCrossing *event,
+                                        gpointer         user_data);
+
 gboolean
 on_canvas_expose_event                 (GtkWidget       *widget,
                                         GdkEventExpose  *event,
index 0d4abc2e01fbec3358b5641ff319d040eb020b29..90ff4f59e16c2198b3c143807a3c7e45eda2d87a 100644 (file)
@@ -7,6 +7,7 @@
 #include <gtk/gtk.h>
 #include <libgnomecanvas/libgnomecanvas.h>
 #include <gdk/gdkkeysyms.h>
+#include <X11/Xlib.h>
 
 #include "xournal.h"
 #include "xo-interface.h"
@@ -1975,3 +1976,78 @@ void hide_unimplemented(void)
     gtk_widget_hide(GET_COMPONENT("optionsSavePreferences"));
   }
 }  
+
+/* attempt to work around GTK+ 2.16/2.17 bugs where random interface
+   elements receive XInput events that they can't handle properly    */
+
+// prevent interface items from getting bogus XInput events
+
+gboolean filter_extended_events (GtkWidget *widget, GdkEvent *event,
+                                   gpointer user_data)
+{
+  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;
+}
+
+/* Code to turn an extended input event into a core event and send it to
+   a different GdkWindow -- e.g. could be used when a click in a text edit box
+   gets sent to the canvas instead due to incorrect event translation.
+   We now turn off xinput altogether while editing text under GTK+ 2.17, so
+   this isn't needed any more... but could become useful again someday!
+*/
+
+/*  
+gboolean fix_extended_events (GtkWidget *widget, GdkEvent *event,
+                                   gpointer user_data)
+{
+  int ix, iy;
+  GdkWindow *window;
+
+  if (user_data) window = (GdkWindow *)user_data;
+  else window = widget->window;
+
+  if (event->type == GDK_MOTION_NOTIFY &&
+      event->motion.device != gdk_device_get_core_pointer()) {
+//    printf("fixing motion\n");
+    gdk_window_get_pointer(window, &ix, &iy, NULL);
+    event->motion.x = ix; event->motion.y = iy;
+    event->motion.device = gdk_device_get_core_pointer();
+    g_object_unref(event->motion.window);
+    event->motion.window = g_object_ref(window);
+    gtk_widget_event(widget, event);
+    return TRUE;
+  }
+  if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
+      event->button.device != gdk_device_get_core_pointer()) {
+//    printf("fixing button from pos = %f, %f\n", event->button.x, event->button.y);
+    gdk_window_get_pointer(window, &ix, &iy, NULL);
+    event->button.x = ix; event->button.y = iy;
+    event->button.device = gdk_device_get_core_pointer();
+    g_object_unref(event->button.window);
+    event->button.window = g_object_ref(window);
+//    printf("fixing button to pos = %f, %f\n", event->button.x, event->button.y);
+    gtk_widget_event(widget, event);
+    return TRUE;
+  }
+  return FALSE;
+}
+*/
+
+// disable xinput when layer combo box is popped up, to avoid crash
+
+gboolean combobox_popup_disable_xinput (GtkWidget *widget, GdkEvent *event,
+                                   gpointer user_data)
+{
+  gboolean is_shown;
+  
+  g_object_get(G_OBJECT(widget), "popup-shown", &is_shown, NULL);
+  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 && !is_shown)?GDK_EXTENSION_EVENTS_ALL:GDK_EXTENSION_EVENTS_NONE);
+}
index d966fa4fd660cc62b64c1b42f77138e205c4620d..2bfc75334dbbd16b9781a72f57bd02592af04022 100644 (file)
@@ -94,6 +94,11 @@ gboolean is_event_within_textview(GdkEventButton *event);
 
 void hide_unimplemented(void);
 
+// fix GTK+ 2.16/2.17 issues with XInput events
+gboolean filter_extended_events(GtkWidget *widget, GdkEvent *event, gpointer user_data);
+// gboolean fix_extended_events(GtkWidget *widget, GdkEvent *event, gpointer user_data);
+gboolean combobox_popup_disable_xinput(GtkWidget *widget, GdkEvent *event, gpointer user_data);
+
 // defines for paper rulings
 
 #define RULING_MARGIN_COLOR 0xff0080ff
index 8f6f609ef439f62966a7a179407b1b9a8a07f11f..32e7504ea136707e130185b05b12d012292bcc78 100644 (file)
@@ -1215,6 +1215,17 @@ void start_text(GdkEvent *event, struct Item *item)
   get_pointer_coords(event, pt);
   ui.cur_item_type = ITEM_TEXT;
 
+  // HACK TO BYPASS GTK+ 2.17 issues
+  if (!gtk_check_version(2, 17, 0)) {
+    /* first we make *all* canvas subwindows become XInput aware, 
+       so that it'll be safe to disable XInput later on... (!!!) */
+    gtk_widget_set_extension_events(GTK_WIDGET (canvas), 
+       ui.use_xinput?GDK_EXTENSION_EVENTS_ALL:GDK_EXTENSION_EVENTS_NONE);
+    /* then we ask the canvas's leave-notify handler to disable 
+       xinput when it's safe to do so... */
+    ui.need_emergency_disable_xinput = TRUE;
+  }
+
   if (item==NULL) {
     item = g_new(struct Item, 1);
     item->text = NULL;
@@ -1277,6 +1288,14 @@ void end_text(void)
   GnomeCanvasItem *tmpitem;
 
   if (ui.cur_item_type!=ITEM_TEXT) return; // nothing for us to do!
+
+  // HACK TO BYPASS GTK+ 2.17 issues
+  if (!gtk_check_version(2, 17, 0)) {
+    // re-enable XInput if needed (we disabled it during text edition)
+    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);
+  }
   
   // finalize the text that's been edited... 
   buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ui.cur_item->widget));
index 8e2aff618342384bc35698e46f34a6ecf87d0379..9a387d189b8e3ac16ec61d62f8e96f56d5f1bc11 100644 (file)
@@ -274,6 +274,7 @@ typedef struct UIData {
   gboolean shorten_menus; // shorten menus ?
   gchar *shorten_menu_items; // which items to hide
   gboolean is_sel_cursor; // displaying a selection-related cursor
+  gboolean need_emergency_disable_xinput; // need to disable xinput to avoid GTK+ 2.17 bug ?
 } UIData;
 
 #define BRUSH_LINKED 0