From 41c6f717ad3d0bf27680ee2e60db11b65ca7f2b9 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Thu, 10 Jun 2010 00:09:22 +0000 Subject: - Add a patch to fix confusion between windows (rhbz #533066) --- Stop-confusing-GDK-s-grab-tracking.patch | 200 +++++++++++++++++++++++++++++++ metacity.spec | 8 +- 2 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 Stop-confusing-GDK-s-grab-tracking.patch diff --git a/Stop-confusing-GDK-s-grab-tracking.patch b/Stop-confusing-GDK-s-grab-tracking.patch new file mode 100644 index 0000000..abcca67 --- /dev/null +++ b/Stop-confusing-GDK-s-grab-tracking.patch @@ -0,0 +1,200 @@ +From c81be0bc98ff79fcdba7d60276ae63048e53b7c8 Mon Sep 17 00:00:00 2001 +From: Owen W. Taylor +Date: Wed, 9 Jun 2010 19:38:35 -0400 +Subject: [PATCH] Stop confusing GDK's grab tracking + +With client side windows, mixing GDK event delivery with explicit calls +to XUngrabPointer() can result in GDK losing button release events +it expects to get. This means that GDK thinks there is an implicit +grab in effect when there is none and send events to the wrong window. + +Avoid this by bypassing GDK's event handling for most mouse events. +We do a simplified conversion of the X event into a GdkEvent and send +it to directly to libgtk for delivery. + +We make an exception when a GDK grab is already in effect - this is +needed for the correct operation of menus. + +http://bugzilla.gnome.org/show_bug.cgi?id=599181 +--- + src/core/display-private.h | 7 ++ + src/core/display.c | 131 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 138 insertions(+), 0 deletions(-) + +diff --git a/src/core/display-private.h b/src/core/display-private.h +index 19287f3..8bc00fb 100644 +--- a/src/core/display-private.h ++++ b/src/core/display-private.h +@@ -223,6 +223,13 @@ struct _MetaDisplay + /* Closing down the display */ + int closing; + ++ /* To detect double clicks */ ++ guint button_click_number; ++ Window button_click_window; ++ int button_click_x; ++ int button_click_y; ++ guint32 button_click_time; ++ + /* Managed by group.c */ + GHashTable *groups_by_leader; + +diff --git a/src/core/display.c b/src/core/display.c +index 4c7b4c0..bdd3016 100644 +--- a/src/core/display.c ++++ b/src/core/display.c +@@ -77,6 +77,7 @@ + #include + #endif + #include ++#include + + #define GRAB_OP_IS_WINDOW_SWITCH(g) \ + (g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL || \ +@@ -1396,6 +1397,133 @@ handle_net_restack_window (MetaDisplay* display, + } + #endif + ++/* We do some of our event handling in core/frames.c, which expects ++ * GDK events delivered by GTK+. However, since the transition to ++ * client side windows, we can't let GDK see button events, since the ++ * client-side tracking of implicit and explicit grabs it does will ++ * get confused by our direct use of X grabs. ++ * ++ * So we do a very minimal GDK => GTK event conversion here and send on the ++ * events we care about, and then filter them out so they don't go ++ * through the normal GDK event handling. ++ * ++ * To reduce the amount of code, the only events fields filled out ++ * below are the ones that frames.c uses. If frames.c is modified to ++ * use more fields, more fields need to be filled out below. ++ */ ++ ++static gboolean ++maybe_send_event_to_gtk (MetaDisplay *display, ++ XEvent *xevent) ++{ ++ /* We're always using the default display */ ++ GdkDisplay *gdk_display = gdk_display_get_default (); ++ GdkEvent gdk_event; ++ GdkWindow *gdk_window; ++ Window window; ++ ++ switch (xevent->type) ++ { ++ case ButtonPress: ++ case ButtonRelease: ++ window = xevent->xbutton.window; ++ break; ++ case MotionNotify: ++ window = xevent->xmotion.window; ++ break; ++ case EnterNotify: ++ case LeaveNotify: ++ window = xevent->xcrossing.window; ++ break; ++ default: ++ return FALSE; ++ } ++ ++ gdk_window = gdk_window_lookup_for_display (gdk_display, window); ++ if (gdk_window == NULL) ++ return FALSE; ++ ++ /* If GDK already things it has a grab, we better let it see events; this ++ * is the menu-navigation case and events need to get sent to the appropriate ++ * (client-side) subwindow for individual menu items. ++ */ ++ if (gdk_display_pointer_is_grabbed (gdk_display)) ++ return FALSE; ++ ++ memset (&gdk_event, 0, sizeof (gdk_event)); ++ ++ switch (xevent->type) ++ { ++ case ButtonPress: ++ case ButtonRelease: ++ if (xevent->type == ButtonPress) ++ { ++ GtkSettings *settings = gtk_settings_get_default (); ++ int double_click_time; ++ int double_click_distance; ++ ++ g_object_get (settings, ++ "gtk-double-click-time", &double_click_time, ++ "gtk-double-click-distance", &double_click_distance, ++ NULL); ++ ++ if (xevent->xbutton.button == display->button_click_number && ++ xevent->xbutton.window == display->button_click_window && ++ xevent->xbutton.time < display->button_click_time + double_click_time && ++ ABS (xevent->xbutton.x - display->button_click_x) <= double_click_distance && ++ ABS (xevent->xbutton.y - display->button_click_y) <= double_click_distance) ++ { ++ gdk_event.button.type = GDK_2BUTTON_PRESS; ++ ++ display->button_click_number = 0; ++ } ++ else ++ { ++ gdk_event.button.type = GDK_BUTTON_PRESS; ++ display->button_click_number = xevent->xbutton.button; ++ display->button_click_window = xevent->xbutton.window; ++ display->button_click_time = xevent->xbutton.time; ++ display->button_click_x = xevent->xbutton.x; ++ display->button_click_y = xevent->xbutton.y; ++ } ++ } ++ else ++ { ++ gdk_event.button.type = GDK_BUTTON_RELEASE; ++ } ++ ++ gdk_event.button.window = gdk_window; ++ gdk_event.button.button = xevent->xbutton.button; ++ gdk_event.button.time = xevent->xbutton.time; ++ gdk_event.button.x = xevent->xbutton.x; ++ gdk_event.button.y = xevent->xbutton.y; ++ gdk_event.button.x_root = xevent->xbutton.x_root; ++ gdk_event.button.y_root = xevent->xbutton.y_root; ++ ++ break; ++ case MotionNotify: ++ gdk_event.motion.type = GDK_MOTION_NOTIFY; ++ gdk_event.motion.window = gdk_window; ++ break; ++ case EnterNotify: ++ case LeaveNotify: ++ gdk_event.crossing.type = xevent->type == EnterNotify ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY; ++ gdk_event.crossing.window = gdk_window; ++ gdk_event.crossing.x = xevent->xcrossing.x; ++ gdk_event.crossing.y = xevent->xcrossing.y; ++ break; ++ default: ++ g_assert_not_reached (); ++ break; ++ } ++ ++ /* If we've gotten here, we've filled in the gdk_event and should send it on */ ++ ++ gtk_main_do_event (&gdk_event); ++ ++ return TRUE; ++} ++ + /** + * This is the most important function in the whole program. It is the heart, + * it is the nexus, it is the Grand Central Station of Metacity's world. +@@ -2403,6 +2531,9 @@ event_callback (XEvent *event, + event, + window); + } ++ ++ if (maybe_send_event_to_gtk (display, event)) ++ filter_out_event = TRUE; + + display->current_time = CurrentTime; + return filter_out_event; +-- +1.7.0.1 + diff --git a/metacity.spec b/metacity.spec index 4ed457f..69f7624 100644 --- a/metacity.spec +++ b/metacity.spec @@ -3,7 +3,7 @@ Summary: Unobtrusive window manager Name: metacity Version: 2.30.0 -Release: 2%{?dist} +Release: 3%{?dist} URL: http://download.gnome.org/sources/metacity/ Source0: http://download.gnome.org/sources/metacity/2.30/metacity-%{version}.tar.bz2 # http://bugzilla.gnome.org/show_bug.cgi?id=558723 @@ -41,6 +41,8 @@ Patch25: metacity-2.28-xioerror-unknown-display.patch Patch26: libs.patch # https://bugzilla.gnome.org/show_bug.cgi?id=614592 Patch27: title-click.patch +# https://bugzilla.gnome.org/show_bug.cgi?id=599181 +Patch28: Stop-confusing-GDK-s-grab-tracking.patch License: GPLv2+ Group: User Interface/Desktops @@ -118,6 +120,7 @@ API. This package exists purely for technical reasons. %patch25 -p1 -b .xioerror-unknown-display %patch26 -p1 -b .libs %patch27 -p1 -b .title-click +%patch28 -p1 -b .grab-tracking # force regeneration rm src/metacity.schemas @@ -225,6 +228,9 @@ fi %{_mandir}/man1/metacity-window-demo.1.gz %changelog +* Wed Jun 9 2010 Owen Taylor - 2.30.0-3 +- Add a patch to fix confusion between windows (rhbz #533066) + * Mon Apr 5 2010 Matthias Clasen - 2.30.0-2 - Don't crash on titlebar right-click -- cgit