summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@fedoraproject.org>2010-06-24 01:36:14 +0000
committerOwen Taylor <otaylor@fedoraproject.org>2010-06-24 01:36:14 +0000
commit7a651cc048552ca0afd6e246e3fea629c41d453a (patch)
tree0bf52871459aa14c7227c3b4f51ea6c38a61449c
parent83db8934b3c9b5530e6447c9efb3d95a70a2a545 (diff)
downloadmetacity-7a651cc048552ca0afd6e246e3fea629c41d453a.tar.gz
metacity-7a651cc048552ca0afd6e246e3fea629c41d453a.tar.xz
metacity-7a651cc048552ca0afd6e246e3fea629c41d453a.zip
- Add a patch to fix confusion between windows (rhbz #533066)metacity-2_30_0-5_fc14
-rw-r--r--Stop-confusing-GDK-s-grab-tracking.patch200
1 files changed, 200 insertions, 0 deletions
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 <otaylor@fishsoup.net>
+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 <X11/extensions/Xfixes.h>
+ #endif
+ #include <string.h>
++#include <gtk/gtk.h>
+
+ #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
+