[gtk+] DND: Work better with XI2



commit 633918158b8c2e0ba4a0cd0c0a812338a8ac83cf
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Oct 20 20:59:50 2011 -0400

    DND: Work better with XI2
    
    It turns out that simply using XIGrabKeycode instead of XGrabKey
    makes the DND keyboard support mostly work (there seem to be some
    minor issues with modifiers). This means we no longer grab the
    keyboard actively during DND, which in turn makes Alt-Tab and
    other window manager shortcuts work again during DND.
    
    At the same time, bring the DND key handling code into the
    multi-backend work, by checking for X11 and XI2 at runtime,
    in addition to compile time.

 gtk/gtkdnd.c |  130 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 113 insertions(+), 17 deletions(-)
---
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c
index a1f455f..1b8baa4 100644
--- a/gtk/gtkdnd.c
+++ b/gtk/gtkdnd.c
@@ -36,6 +36,9 @@
 #include <X11/Xlib.h>
 #include <X11/keysym.h>
 #include "gdk/x11/gdkx.h"
+#ifdef XINPUT_2
+#include <X11/extensions/XInput2.h>
+#endif
 #endif
 
 #include "gtkdnd.h"
@@ -396,12 +399,7 @@ gtk_drag_get_ipc_widget (GtkWidget *widget)
   return result;
 }
 
-/* FIXME: modifying the XEvent window as in root_key_filter() isn't
- * going to work with XGE/XI2, since the actual event to handle would
- * be allocated/freed before GDK gets to translate the event.
- * Active grabs on the keyboard are used instead at the moment...
- */
-#if defined (GDK_WINDOWING_X11) && !defined (XINPUT_2)
+#if defined (GDK_WINDOWING_X11)
 
 /*
  * We want to handle a handful of keys during DND, e.g. Escape to abort.
@@ -466,8 +464,34 @@ grab_dnd_keys (GtkWidget *widget,
   guint i;
   GdkWindow *window, *root;
   gint keycode;
+#ifdef XINPUT_2
+  gint deviceid;
+  XIGrabModifiers mods;
+  gint num_mods;
+  XIEventMask evmask;
+  unsigned char mask[(XI_LASTEVENT + 7)/8];
+  gboolean using_xi2;
+
+  deviceid = gdk_x11_device_get_id (device);
+
+  if (GDK_IS_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (gtk_widget_get_display (widget))))
+    using_xi2 = TRUE;
+  else
+    using_xi2 = FALSE;
+#endif
 
   window = gtk_widget_get_window (widget);
+  if (!GDK_IS_X11_WINDOW (window))
+    {
+      gdk_device_grab (device,
+                       gtk_widget_get_window (widget),
+                       GDK_OWNERSHIP_APPLICATION, FALSE,
+                       GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+                       NULL, time);
+      return;
+    }
+
+
   root = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
 
   gdk_error_trap_push ();
@@ -477,12 +501,45 @@ grab_dnd_keys (GtkWidget *widget,
       keycode = XKeysymToKeycode (GDK_WINDOW_XDISPLAY (window), grab_keys[i].keysym);
       if (keycode == NoSymbol)
         continue;
-      XGrabKey (GDK_WINDOW_XDISPLAY (window),
-   	        keycode, grab_keys[i].modifiers,
-	        GDK_WINDOW_XID (root),
-	        FALSE,
-	        GrabModeAsync,
-	        GrabModeAsync);
+
+#ifdef XINPUT_2
+      if (using_xi2)
+        {
+          memset (mask, 0, sizeof (mask));
+          XISetMask (mask, XI_KeyPress);
+          XISetMask (mask, XI_KeyRelease);
+
+          evmask.deviceid = deviceid;
+          evmask.mask_len = sizeof (mask);
+          evmask.mask = mask;
+
+          if (grab_keys[i].modifiers != 0)
+            {
+              num_mods = 1;
+              mods.modifiers = grab_keys[i].modifiers;
+            }
+          else
+            num_mods = 0;
+
+          XIGrabKeycode (GDK_WINDOW_XDISPLAY (window),
+                         deviceid,
+                         keycode,
+                         GDK_WINDOW_XID (root),
+                         GrabModeAsync,
+                         GrabModeAsync,
+                         False,
+                         &evmask,
+                         num_mods,
+                         &mods);
+        }
+      else
+#endif
+        XGrabKey (GDK_WINDOW_XDISPLAY (window),
+                  keycode, grab_keys[i].modifiers,
+                  GDK_WINDOW_XID (root),
+                  FALSE,
+                  GrabModeAsync,
+                  GrabModeAsync);
     }
 
   gdk_flush ();
@@ -499,8 +556,26 @@ ungrab_dnd_keys (GtkWidget *widget,
   guint i;
   GdkWindow *window, *root;
   gint keycode;
+#ifdef XINPUT_2
+  XIGrabModifiers mods;
+  gint num_mods;
+  gint deviceid;
+  gboolean using_xi2;
+
+  deviceid = gdk_x11_device_get_id (device);
+  if (GDK_IS_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (gtk_widget_get_display (widget))))
+    using_xi2 = TRUE;
+  else
+    using_xi2 = FALSE;
+#endif
 
   window = gtk_widget_get_window (widget);
+  if (!GDK_IS_X11_WINDOW (window))
+    {
+      gdk_device_ungrab (device, time);
+      return;
+    }
+
   root = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
 
   gdk_window_remove_filter (NULL, root_key_filter, (gpointer) GDK_WINDOW_XID (window));
@@ -512,16 +587,37 @@ ungrab_dnd_keys (GtkWidget *widget,
       keycode = XKeysymToKeycode (GDK_WINDOW_XDISPLAY (window), grab_keys[i].keysym);
       if (keycode == NoSymbol)
         continue;
-      XUngrabKey (GDK_WINDOW_XDISPLAY (window),
-      	          keycode, grab_keys[i].modifiers,
-                  GDK_WINDOW_XID (root));
+
+#ifdef XINPUT_2
+      if (using_xi2)
+        {
+          if (grab_keys[i].modifiers != 0)
+            {
+              num_mods = 1;
+              mods.modifiers = grab_keys[i].modifiers;
+            }
+          else
+            num_mods = 0;
+
+          XIUngrabKeycode (GDK_WINDOW_XDISPLAY (window),
+                           deviceid,
+                           keycode,
+                           GDK_WINDOW_XID (root),
+                           num_mods,
+                           &mods);
+        }
+      else
+#endif
+        XUngrabKey (GDK_WINDOW_XDISPLAY (window),
+                    keycode, grab_keys[i].modifiers,
+                    GDK_WINDOW_XID (root));
     }
 
   gdk_flush ();
   gdk_error_trap_pop_ignored ();
 }
 
-#else /* GDK_WINDOWING_X11 && !XINPUT_2 */
+#else /* !GDK_WINDOWING_X11 */
 
 static void
 grab_dnd_keys (GtkWidget *widget,
@@ -4316,7 +4412,7 @@ gtk_drag_key_cb (GtkWidget         *widget,
   if (event->type == GDK_KEY_PRESS)
     {
       switch (event->keyval)
-{
+        {
         case GDK_KEY_Escape:
           gtk_drag_cancel (info, GTK_DRAG_RESULT_USER_CANCELLED, event->time);
           return TRUE;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]