From: auroux Date: Mon, 7 Sep 2009 04:34:02 +0000 (+0000) Subject: workaround for GTK+ 2.17 crasher bugs (text edit box, combo box) X-Git-Url: https://git.donarmstrong.com/?p=xournal.git;a=commitdiff_plain;h=13d7457867c57ac5ac826df4d6b478fee795c0a4 workaround for GTK+ 2.17 crasher bugs (text edit box, combo box) --- diff --git a/src/TODO b/src/TODO index e2a8d39..594cf49 100644 --- 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) diff --git a/src/main.c b/src/main.c index b900ed7..129716a 100644 --- a/src/main.c +++ b/src/main.c @@ -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 diff --git a/src/xo-callbacks.c b/src/xo-callbacks.c index c382996..6d38176 100644 --- a/src/xo-callbacks.c +++ b/src/xo-callbacks.c @@ -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); diff --git a/src/xo-callbacks.h b/src/xo-callbacks.h index e42dc95..ebe9b8b 100644 --- a/src/xo-callbacks.h +++ b/src/xo-callbacks.h @@ -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, diff --git a/src/xo-misc.c b/src/xo-misc.c index 0d4abc2..90ff4f5 100644 --- a/src/xo-misc.c +++ b/src/xo-misc.c @@ -7,6 +7,7 @@ #include #include #include +#include #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); +} diff --git a/src/xo-misc.h b/src/xo-misc.h index d966fa4..2bfc753 100644 --- a/src/xo-misc.h +++ b/src/xo-misc.h @@ -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 diff --git a/src/xo-paint.c b/src/xo-paint.c index 8f6f609..32e7504 100644 --- a/src/xo-paint.c +++ b/src/xo-paint.c @@ -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)); diff --git a/src/xournal.h b/src/xournal.h index 8e2aff6..9a387d1 100644 --- a/src/xournal.h +++ b/src/xournal.h @@ -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