- Add a patch to fix confusion between windows (rhbz #533066)
This commit is contained in:
parent
83db8934b3
commit
7a651cc048
200
Stop-confusing-GDK-s-grab-tracking.patch
Normal file
200
Stop-confusing-GDK-s-grab-tracking.patch
Normal file
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user