|
|
8063f1 |
From ab0428a82f8233829c36e2a3ac0ed0848571c59d Mon Sep 17 00:00:00 2001
|
|
|
8063f1 |
From: "Owen W. Taylor" <otaylor@fishsoup.net>
|
|
|
8063f1 |
Date: Wed, 9 Jun 2010 19:38:35 -0400
|
|
|
8063f1 |
Subject: [PATCH] Stop confusing GDK's grab tracking
|
|
|
8063f1 |
|
|
|
8063f1 |
With client side windows, mixing GDK event delivery with explicit calls
|
|
|
8063f1 |
to XUngrabPointer() can result in GDK losing button release events
|
|
|
8063f1 |
it expects to get. This means that GDK thinks there is an implicit
|
|
|
8063f1 |
grab in effect when there is none and send events to the wrong window.
|
|
|
8063f1 |
|
|
|
8063f1 |
Avoid this by bypassing GDK's event handling for most mouse events.
|
|
|
8063f1 |
We do a simplified conversion of the X event into a GdkEvent and send
|
|
|
8063f1 |
it to directly to libgtk for delivery.
|
|
|
8063f1 |
|
|
|
8063f1 |
We make an exception when a GDK grab is already in effect - this is
|
|
|
8063f1 |
needed for the correct operation of menus.
|
|
|
8063f1 |
|
|
|
8063f1 |
http://bugzilla.gnome.org/show_bug.cgi?id=599181
|
|
|
8063f1 |
---
|
|
|
8063f1 |
src/core/display-private.h | 7 ++
|
|
|
8063f1 |
src/core/display.c | 131 ++++++++++++++++++++++++++++++++++++++++++++
|
|
|
8063f1 |
2 files changed, 138 insertions(+), 0 deletions(-)
|
|
|
8063f1 |
|
|
|
8063f1 |
diff --git a/src/core/display-private.h b/src/core/display-private.h
|
|
|
8063f1 |
index fee321c..7f779fd 100644
|
|
|
8063f1 |
--- a/src/core/display-private.h
|
|
|
8063f1 |
+++ b/src/core/display-private.h
|
|
|
8063f1 |
@@ -232,6 +232,13 @@ struct _MetaDisplay
|
|
|
8063f1 |
/* Closing down the display */
|
|
|
8063f1 |
int closing;
|
|
|
8063f1 |
|
|
|
8063f1 |
+ /* To detect double clicks */
|
|
|
8063f1 |
+ guint button_click_number;
|
|
|
8063f1 |
+ Window button_click_window;
|
|
|
8063f1 |
+ int button_click_x;
|
|
|
8063f1 |
+ int button_click_y;
|
|
|
8063f1 |
+ guint32 button_click_time;
|
|
|
8063f1 |
+
|
|
|
8063f1 |
/* Managed by group.c */
|
|
|
8063f1 |
GHashTable *groups_by_leader;
|
|
|
8063f1 |
|
|
|
8063f1 |
diff --git a/src/core/display.c b/src/core/display.c
|
|
|
8063f1 |
index 5bcf025..0c5f61d 100644
|
|
|
8063f1 |
--- a/src/core/display.c
|
|
|
8063f1 |
+++ b/src/core/display.c
|
|
|
8063f1 |
@@ -77,6 +77,7 @@
|
|
|
8063f1 |
#include <X11/extensions/Xfixes.h>
|
|
|
8063f1 |
#endif
|
|
|
8063f1 |
#include <string.h>
|
|
|
8063f1 |
+#include <gtk/gtk.h>
|
|
|
8063f1 |
|
|
|
8063f1 |
#define GRAB_OP_IS_WINDOW_SWITCH(g) \
|
|
|
8063f1 |
(g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL || \
|
|
|
8063f1 |
@@ -1362,6 +1363,133 @@ meta_display_queue_autoraise_callback (MetaDisplay *display,
|
|
|
8063f1 |
display->autoraise_window = window;
|
|
|
8063f1 |
}
|
|
|
8063f1 |
|
|
|
8063f1 |
+/* We do some of our event handling in core/frames.c, which expects
|
|
|
8063f1 |
+ * GDK events delivered by GTK+. However, since the transition to
|
|
|
8063f1 |
+ * client side windows, we can't let GDK see button events, since the
|
|
|
8063f1 |
+ * client-side tracking of implicit and explicit grabs it does will
|
|
|
8063f1 |
+ * get confused by our direct use of X grabs.
|
|
|
8063f1 |
+ *
|
|
|
8063f1 |
+ * So we do a very minimal GDK => GTK event conversion here and send on the
|
|
|
8063f1 |
+ * events we care about, and then filter them out so they don't go
|
|
|
8063f1 |
+ * through the normal GDK event handling.
|
|
|
8063f1 |
+ *
|
|
|
8063f1 |
+ * To reduce the amount of code, the only events fields filled out
|
|
|
8063f1 |
+ * below are the ones that frames.c uses. If frames.c is modified to
|
|
|
8063f1 |
+ * use more fields, more fields need to be filled out below.
|
|
|
8063f1 |
+ */
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+static gboolean
|
|
|
8063f1 |
+maybe_send_event_to_gtk (MetaDisplay *display,
|
|
|
8063f1 |
+ XEvent *xevent)
|
|
|
8063f1 |
+{
|
|
|
8063f1 |
+ /* We're always using the default display */
|
|
|
8063f1 |
+ GdkDisplay *gdk_display = gdk_display_get_default ();
|
|
|
8063f1 |
+ GdkEvent gdk_event;
|
|
|
8063f1 |
+ GdkWindow *gdk_window;
|
|
|
8063f1 |
+ Window window;
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ switch (xevent->type)
|
|
|
8063f1 |
+ {
|
|
|
8063f1 |
+ case ButtonPress:
|
|
|
8063f1 |
+ case ButtonRelease:
|
|
|
8063f1 |
+ window = xevent->xbutton.window;
|
|
|
8063f1 |
+ break;
|
|
|
8063f1 |
+ case MotionNotify:
|
|
|
8063f1 |
+ window = xevent->xmotion.window;
|
|
|
8063f1 |
+ break;
|
|
|
8063f1 |
+ case EnterNotify:
|
|
|
8063f1 |
+ case LeaveNotify:
|
|
|
8063f1 |
+ window = xevent->xcrossing.window;
|
|
|
8063f1 |
+ break;
|
|
|
8063f1 |
+ default:
|
|
|
8063f1 |
+ return FALSE;
|
|
|
8063f1 |
+ }
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ gdk_window = gdk_window_lookup_for_display (gdk_display, window);
|
|
|
8063f1 |
+ if (gdk_window == NULL)
|
|
|
8063f1 |
+ return FALSE;
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ /* If GDK already things it has a grab, we better let it see events; this
|
|
|
8063f1 |
+ * is the menu-navigation case and events need to get sent to the appropriate
|
|
|
8063f1 |
+ * (client-side) subwindow for individual menu items.
|
|
|
8063f1 |
+ */
|
|
|
8063f1 |
+ if (gdk_display_pointer_is_grabbed (gdk_display))
|
|
|
8063f1 |
+ return FALSE;
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ memset (&gdk_event, 0, sizeof (gdk_event));
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ switch (xevent->type)
|
|
|
8063f1 |
+ {
|
|
|
8063f1 |
+ case ButtonPress:
|
|
|
8063f1 |
+ case ButtonRelease:
|
|
|
8063f1 |
+ if (xevent->type == ButtonPress)
|
|
|
8063f1 |
+ {
|
|
|
8063f1 |
+ GtkSettings *settings = gtk_settings_get_default ();
|
|
|
8063f1 |
+ int double_click_time;
|
|
|
8063f1 |
+ int double_click_distance;
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ g_object_get (settings,
|
|
|
8063f1 |
+ "gtk-double-click-time", &double_click_time,
|
|
|
8063f1 |
+ "gtk-double-click-distance", &double_click_distance,
|
|
|
8063f1 |
+ NULL);
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ if (xevent->xbutton.button == display->button_click_number &&
|
|
|
8063f1 |
+ xevent->xbutton.window == display->button_click_window &&
|
|
|
8063f1 |
+ xevent->xbutton.time < display->button_click_time + double_click_time &&
|
|
|
8063f1 |
+ ABS (xevent->xbutton.x - display->button_click_x) <= double_click_distance &&
|
|
|
8063f1 |
+ ABS (xevent->xbutton.y - display->button_click_y) <= double_click_distance)
|
|
|
8063f1 |
+ {
|
|
|
8063f1 |
+ gdk_event.button.type = GDK_2BUTTON_PRESS;
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ display->button_click_number = 0;
|
|
|
8063f1 |
+ }
|
|
|
8063f1 |
+ else
|
|
|
8063f1 |
+ {
|
|
|
8063f1 |
+ gdk_event.button.type = GDK_BUTTON_PRESS;
|
|
|
8063f1 |
+ display->button_click_number = xevent->xbutton.button;
|
|
|
8063f1 |
+ display->button_click_window = xevent->xbutton.window;
|
|
|
8063f1 |
+ display->button_click_time = xevent->xbutton.time;
|
|
|
8063f1 |
+ display->button_click_x = xevent->xbutton.x;
|
|
|
8063f1 |
+ display->button_click_y = xevent->xbutton.y;
|
|
|
8063f1 |
+ }
|
|
|
8063f1 |
+ }
|
|
|
8063f1 |
+ else
|
|
|
8063f1 |
+ {
|
|
|
8063f1 |
+ gdk_event.button.type = GDK_BUTTON_RELEASE;
|
|
|
8063f1 |
+ }
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ gdk_event.button.window = gdk_window;
|
|
|
8063f1 |
+ gdk_event.button.button = xevent->xbutton.button;
|
|
|
8063f1 |
+ gdk_event.button.time = xevent->xbutton.time;
|
|
|
8063f1 |
+ gdk_event.button.x = xevent->xbutton.x;
|
|
|
8063f1 |
+ gdk_event.button.y = xevent->xbutton.y;
|
|
|
8063f1 |
+ gdk_event.button.x_root = xevent->xbutton.x_root;
|
|
|
8063f1 |
+ gdk_event.button.y_root = xevent->xbutton.y_root;
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ break;
|
|
|
8063f1 |
+ case MotionNotify:
|
|
|
8063f1 |
+ gdk_event.motion.type = GDK_MOTION_NOTIFY;
|
|
|
8063f1 |
+ gdk_event.motion.window = gdk_window;
|
|
|
8063f1 |
+ break;
|
|
|
8063f1 |
+ case EnterNotify:
|
|
|
8063f1 |
+ case LeaveNotify:
|
|
|
8063f1 |
+ gdk_event.crossing.type = xevent->type == EnterNotify ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
|
|
|
8063f1 |
+ gdk_event.crossing.window = gdk_window;
|
|
|
8063f1 |
+ gdk_event.crossing.x = xevent->xcrossing.x;
|
|
|
8063f1 |
+ gdk_event.crossing.y = xevent->xcrossing.y;
|
|
|
8063f1 |
+ break;
|
|
|
8063f1 |
+ default:
|
|
|
8063f1 |
+ g_assert_not_reached ();
|
|
|
8063f1 |
+ break;
|
|
|
8063f1 |
+ }
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ /* If we've gotten here, we've filled in the gdk_event and should send it on */
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ gtk_main_do_event (&gdk_event);
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ return TRUE;
|
|
|
8063f1 |
+}
|
|
|
8063f1 |
+
|
|
|
8063f1 |
/**
|
|
|
8063f1 |
* This is the most important function in the whole program. It is the heart,
|
|
|
8063f1 |
* it is the nexus, it is the Grand Central Station of Metacity's world.
|
|
|
8063f1 |
@@ -2387,6 +2515,9 @@ event_callback (XEvent *event,
|
|
|
8063f1 |
event,
|
|
|
8063f1 |
window);
|
|
|
8063f1 |
}
|
|
|
8063f1 |
+
|
|
|
8063f1 |
+ if (maybe_send_event_to_gtk (display, event))
|
|
|
8063f1 |
+ filter_out_event = TRUE;
|
|
|
8063f1 |
|
|
|
8063f1 |
display->current_time = CurrentTime;
|
|
|
8063f1 |
return filter_out_event;
|
|
|
8063f1 |
--
|
|
|
8063f1 |
1.7.9
|
|
|
8063f1 |
|