]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkdevice-xi2.c
x11: Simplify XI2 mods state
[~andy/gtk] / gdk / x11 / gdkdevice-xi2.c
index f64896ca5e33cbc92394780d37ea386b3058f32c..6e496261ebbe6ca3792dfb5e630b3e6c79950ea2 100644 (file)
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
 
-#include <X11/extensions/XInput2.h>
-#include "gdkdevice-xi2.h"
+#include "gdkx11device-xi2.h"
+#include "gdkdeviceprivate.h"
+
 #include "gdkintl.h"
-#include "gdkx.h"
+#include "gdkasync.h"
+#include "gdkprivate-x11.h"
+
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XInput2.h>
+
+
+typedef struct _ScrollValuator ScrollValuator;
+
+struct _ScrollValuator
+{
+  guint n_valuator       : 4;
+  guint direction        : 4;
+  guint last_value_valid : 1;
+  gdouble last_value;
+};
 
+struct _GdkX11DeviceXI2
+{
+  GdkDevice parent_instance;
 
-struct _GdkDeviceXI2Private
+  gint device_id;
+  GArray *scroll_valuators;
+};
+
+struct _GdkX11DeviceXI2Class
 {
-  int device_id;
+  GdkDeviceClass parent_class;
 };
 
-static void gdk_device_xi2_get_property (GObject      *object,
-                                         guint         prop_id,
-                                         GValue       *value,
-                                         GParamSpec   *pspec);
-static void gdk_device_xi2_set_property (GObject      *object,
-                                         guint         prop_id,
-                                         const GValue *value,
-                                         GParamSpec   *pspec);
-
-static void gdk_device_xi2_get_state (GdkDevice       *device,
-                                      GdkWindow       *window,
-                                      gdouble         *axes,
-                                      GdkModifierType *mask);
-static void gdk_device_xi2_set_window_cursor (GdkDevice *device,
-                                              GdkWindow *window,
-                                              GdkCursor *cursor);
-static void gdk_device_xi2_warp (GdkDevice *device,
-                                 GdkScreen *screen,
-                                 gint       x,
-                                 gint       y);
-static gboolean gdk_device_xi2_query_state (GdkDevice        *device,
-                                            GdkWindow        *window,
-                                            GdkWindow       **root_window,
-                                            GdkWindow       **child_window,
-                                            gint             *root_x,
-                                            gint             *root_y,
-                                            gint             *win_x,
-                                            gint             *win_y,
-                                            GdkModifierType  *mask);
-
-static GdkGrabStatus gdk_device_xi2_grab   (GdkDevice     *device,
-                                            GdkWindow     *window,
-                                            gboolean       owner_events,
-                                            GdkEventMask   event_mask,
-                                            GdkWindow     *confine_to,
-                                            GdkCursor     *cursor,
-                                            guint32        time_);
-static void          gdk_device_xi2_ungrab (GdkDevice     *device,
-                                            guint32        time_);
-
-static GdkWindow * gdk_device_xi2_window_at_position (GdkDevice       *device,
-                                                      gint            *win_x,
-                                                      gint            *win_y,
-                                                      GdkModifierType *mask,
-                                                      gboolean         get_toplevel);
-static void  gdk_device_xi2_select_window_events (GdkDevice    *device,
-                                                  GdkWindow    *window,
-                                                  GdkEventMask  event_mask);
-
-
-G_DEFINE_TYPE (GdkDeviceXI2, gdk_device_xi2, GDK_TYPE_DEVICE)
+G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
+
+
+static void gdk_x11_device_xi2_finalize     (GObject      *object);
+static void gdk_x11_device_xi2_get_property (GObject      *object,
+                                             guint         prop_id,
+                                             GValue       *value,
+                                             GParamSpec   *pspec);
+static void gdk_x11_device_xi2_set_property (GObject      *object,
+                                             guint         prop_id,
+                                             const GValue *value,
+                                             GParamSpec   *pspec);
+
+static void gdk_x11_device_xi2_get_state (GdkDevice       *device,
+                                          GdkWindow       *window,
+                                          gdouble         *axes,
+                                          GdkModifierType *mask);
+static void gdk_x11_device_xi2_set_window_cursor (GdkDevice *device,
+                                                  GdkWindow *window,
+                                                  GdkCursor *cursor);
+static void gdk_x11_device_xi2_warp (GdkDevice *device,
+                                     GdkScreen *screen,
+                                     gint       x,
+                                     gint       y);
+static gboolean gdk_x11_device_xi2_query_state (GdkDevice        *device,
+                                                GdkWindow        *window,
+                                                GdkWindow       **root_window,
+                                                GdkWindow       **child_window,
+                                                gint             *root_x,
+                                                gint             *root_y,
+                                                gint             *win_x,
+                                                gint             *win_y,
+                                                GdkModifierType  *mask);
+
+static GdkGrabStatus gdk_x11_device_xi2_grab   (GdkDevice     *device,
+                                                GdkWindow     *window,
+                                                gboolean       owner_events,
+                                                GdkEventMask   event_mask,
+                                                GdkWindow     *confine_to,
+                                                GdkCursor     *cursor,
+                                                guint32        time_);
+static void          gdk_x11_device_xi2_ungrab (GdkDevice     *device,
+                                                guint32        time_);
+
+static GdkWindow * gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
+                                                          gint            *win_x,
+                                                          gint            *win_y,
+                                                          GdkModifierType *mask,
+                                                          gboolean         get_toplevel);
+static void  gdk_x11_device_xi2_select_window_events (GdkDevice    *device,
+                                                      GdkWindow    *window,
+                                                      GdkEventMask  event_mask);
+
 
 enum {
   PROP_0,
@@ -88,58 +113,61 @@ enum {
 };
 
 static void
-gdk_device_xi2_class_init (GdkDeviceXI2Class *klass)
+gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
 
-  object_class->get_property = gdk_device_xi2_get_property;
-  object_class->set_property = gdk_device_xi2_set_property;
+  object_class->finalize = gdk_x11_device_xi2_finalize;
+  object_class->get_property = gdk_x11_device_xi2_get_property;
+  object_class->set_property = gdk_x11_device_xi2_set_property;
 
-  device_class->get_state = gdk_device_xi2_get_state;
-  device_class->set_window_cursor = gdk_device_xi2_set_window_cursor;
-  device_class->warp = gdk_device_xi2_warp;
-  device_class->query_state = gdk_device_xi2_query_state;
-  device_class->grab = gdk_device_xi2_grab;
-  device_class->ungrab = gdk_device_xi2_ungrab;
-  device_class->window_at_position = gdk_device_xi2_window_at_position;
-  device_class->select_window_events = gdk_device_xi2_select_window_events;
+  device_class->get_state = gdk_x11_device_xi2_get_state;
+  device_class->set_window_cursor = gdk_x11_device_xi2_set_window_cursor;
+  device_class->warp = gdk_x11_device_xi2_warp;
+  device_class->query_state = gdk_x11_device_xi2_query_state;
+  device_class->grab = gdk_x11_device_xi2_grab;
+  device_class->ungrab = gdk_x11_device_xi2_ungrab;
+  device_class->window_at_position = gdk_x11_device_xi2_window_at_position;
+  device_class->select_window_events = gdk_x11_device_xi2_select_window_events;
 
   g_object_class_install_property (object_class,
-                                  PROP_DEVICE_ID,
-                                  g_param_spec_int ("device-id",
+                                   PROP_DEVICE_ID,
+                                   g_param_spec_int ("device-id",
                                                      P_("Device ID"),
                                                      P_("Device identifier"),
                                                      0, G_MAXINT, 0,
                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
 
-  g_type_class_add_private (object_class, sizeof (GdkDeviceXI2Private));
+static void
+gdk_x11_device_xi2_init (GdkX11DeviceXI2 *device)
+{
+  device->scroll_valuators = g_array_new (FALSE, FALSE, sizeof (ScrollValuator));
 }
 
 static void
-gdk_device_xi2_init (GdkDeviceXI2 *device)
+gdk_x11_device_xi2_finalize (GObject *object)
 {
-  GdkDeviceXI2Private *priv;
+  GdkX11DeviceXI2 *device = GDK_X11_DEVICE_XI2 (object);
 
-  device->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
-                                                     GDK_TYPE_DEVICE_XI2,
-                                                     GdkDeviceXI2Private);
+  g_array_free (device->scroll_valuators, TRUE);
+
+  G_OBJECT_CLASS (gdk_x11_device_xi2_parent_class)->finalize (object);
 }
 
 static void
-gdk_device_xi2_get_property (GObject    *object,
-                             guint       prop_id,
-                             GValue     *value,
-                             GParamSpec *pspec)
+gdk_x11_device_xi2_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
 {
-  GdkDeviceXI2Private *priv;
-
-  priv = GDK_DEVICE_XI2 (object)->priv;
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (object);
 
   switch (prop_id)
     {
     case PROP_DEVICE_ID:
-      g_value_set_int (value, priv->device_id);
+      g_value_set_int (value, device_xi2->device_id);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -148,19 +176,17 @@ gdk_device_xi2_get_property (GObject    *object,
 }
 
 static void
-gdk_device_xi2_set_property (GObject      *object,
-                             guint         prop_id,
-                             const GValue *value,
-                             GParamSpec   *pspec)
+gdk_x11_device_xi2_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
 {
-  GdkDeviceXI2Private *priv;
-
-  priv = GDK_DEVICE_XI2 (object)->priv;
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (object);
 
   switch (prop_id)
     {
     case PROP_DEVICE_ID:
-      priv->device_id = g_value_get_int (value);
+      device_xi2->device_id = g_value_get_int (value);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -169,25 +195,27 @@ gdk_device_xi2_set_property (GObject      *object,
 }
 
 static void
-gdk_device_xi2_get_state (GdkDevice       *device,
-                          GdkWindow       *window,
-                          gdouble         *axes,
-                          GdkModifierType *mask)
+gdk_x11_device_xi2_get_state (GdkDevice       *device,
+                              GdkWindow       *window,
+                              gdouble         *axes,
+                              GdkModifierType *mask)
 {
-  GdkDeviceXI2Private *priv;
-  GdkDisplay *display;
-  XIDeviceInfo *info;
-  gint i, j, ndevices;
-
-  priv = GDK_DEVICE_XI2 (device)->priv;
-  display = gdk_device_get_display (device);
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
 
   if (axes)
     {
-      info = XIQueryDevice(GDK_DISPLAY_XDISPLAY (display),
-                           priv->device_id, &ndevices);
+      GdkDisplay *display;
+      XIDeviceInfo *info;
+      gint i, j, ndevices;
+
+      display = gdk_device_get_display (device);
 
-      for (i = 0, j = 0; i < info->num_classes; i++)
+      gdk_x11_display_error_trap_push (display);
+      info = XIQueryDevice (GDK_DISPLAY_XDISPLAY (display),
+                            device_xi2->device_id, &ndevices);
+      gdk_x11_display_error_trap_pop_ignored (display);
+
+      for (i = 0, j = 0; info && i < info->num_classes; i++)
         {
           XIAnyClassInfo *class_info = info->classes[i];
           GdkAxisUse use;
@@ -197,14 +225,14 @@ gdk_device_xi2_get_state (GdkDevice       *device,
             continue;
 
           value = ((XIValuatorClassInfo *) class_info)->value;
-          use = _gdk_device_get_axis_use (device, j);
+          use = gdk_device_get_axis_use (device, j);
 
           switch (use)
             {
             case GDK_AXIS_X:
             case GDK_AXIS_Y:
             case GDK_AXIS_IGNORE:
-              if (device->mode == GDK_MODE_WINDOW)
+              if (gdk_device_get_mode (device) == GDK_MODE_WINDOW)
                 _gdk_device_translate_window_coord (device, window, j, value, &axes[j]);
               else
                 {
@@ -226,77 +254,71 @@ gdk_device_xi2_get_state (GdkDevice       *device,
           j++;
         }
 
-      XIFreeDeviceInfo (info);
+      if (info)
+        XIFreeDeviceInfo (info);
     }
 
   if (mask)
-    gdk_device_xi2_query_state (device, window,
-                                NULL, NULL,
-                                NULL, NULL,
-                                NULL, NULL,
-                                mask);
+    gdk_x11_device_xi2_query_state (device, window,
+                                    NULL, NULL,
+                                    NULL, NULL,
+                                    NULL, NULL,
+                                    mask);
 }
 
 static void
-gdk_device_xi2_set_window_cursor (GdkDevice *device,
-                                  GdkWindow *window,
-                                  GdkCursor *cursor)
+gdk_x11_device_xi2_set_window_cursor (GdkDevice *device,
+                                      GdkWindow *window,
+                                      GdkCursor *cursor)
 {
-  GdkDeviceXI2Private *priv;
-  GdkCursorPrivate *cursor_private;
-
-  priv = GDK_DEVICE_XI2 (device)->priv;
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
 
   /* Non-master devices don't have a cursor */
   if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
     return;
 
   if (cursor)
-    {
-      cursor_private = (GdkCursorPrivate*) cursor;
-
-      XIDefineCursor (GDK_WINDOW_XDISPLAY (window),
-                      priv->device_id,
-                      GDK_WINDOW_XWINDOW (window),
-                      cursor_private->xcursor);
-    }
+    XIDefineCursor (GDK_WINDOW_XDISPLAY (window),
+                    device_xi2->device_id,
+                    GDK_WINDOW_XID (window),
+                    gdk_x11_cursor_get_xcursor (cursor));
   else
     XIUndefineCursor (GDK_WINDOW_XDISPLAY (window),
-                      priv->device_id,
-                      GDK_WINDOW_XWINDOW (window));
+                      device_xi2->device_id,
+                      GDK_WINDOW_XID (window));
 }
 
 static void
-gdk_device_xi2_warp (GdkDevice *device,
-                     GdkScreen *screen,
-                     gint       x,
-                     gint       y)
+gdk_x11_device_xi2_warp (GdkDevice *device,
+                         GdkScreen *screen,
+                         gint       x,
+                         gint       y)
 {
-  GdkDeviceXI2Private *priv;
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
   Window dest;
 
-  priv = GDK_DEVICE_XI2 (device)->priv;
-  dest = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
+  dest = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
 
   XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
-                 priv->device_id,
+                 device_xi2->device_id,
                  None, dest,
                  0, 0, 0, 0, x, y);
 }
 
 static gboolean
-gdk_device_xi2_query_state (GdkDevice        *device,
-                            GdkWindow        *window,
-                            GdkWindow       **root_window,
-                            GdkWindow       **child_window,
-                            gint             *root_x,
-                            gint             *root_y,
-                            gint             *win_x,
-                            gint             *win_y,
-                            GdkModifierType  *mask)
+gdk_x11_device_xi2_query_state (GdkDevice        *device,
+                                GdkWindow        *window,
+                                GdkWindow       **root_window,
+                                GdkWindow       **child_window,
+                                gint             *root_x,
+                                gint             *root_y,
+                                gint             *win_x,
+                                gint             *win_y,
+                                GdkModifierType  *mask)
 {
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
   GdkDisplay *display;
-  GdkDeviceXI2Private *priv;
+  GdkScreen *default_screen;
   Window xroot_window, xchild_window;
   gdouble xroot_x, xroot_y, xwin_x, xwin_y;
   XIButtonState button_state;
@@ -306,30 +328,53 @@ gdk_device_xi2_query_state (GdkDevice        *device,
   if (!window || GDK_WINDOW_DESTROYED (window))
     return FALSE;
 
-  priv = GDK_DEVICE_XI2 (device)->priv;
   display = gdk_window_get_display (window);
+  default_screen = gdk_display_get_default_screen (display);
 
-  if (!XIQueryPointer (GDK_WINDOW_XDISPLAY (window),
-                       priv->device_id,
-                       GDK_WINDOW_XID (window),
-                       &xroot_window,
-                       &xchild_window,
-                       &xroot_x,
-                       &xroot_y,
-                       &xwin_x,
-                       &xwin_y,
-                       &button_state,
-                       &mod_state,
-                       &group_state))
+  if (G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
     {
-      return FALSE;
+      if (!XIQueryPointer (GDK_WINDOW_XDISPLAY (window),
+                           device_xi2->device_id,
+                           GDK_WINDOW_XID (window),
+                           &xroot_window,
+                           &xchild_window,
+                           &xroot_x, &xroot_y,
+                           &xwin_x, &xwin_y,
+                           &button_state,
+                           &mod_state,
+                           &group_state))
+        return FALSE;
+    }
+  else
+    {
+      XSetWindowAttributes attributes;
+      Display *xdisplay;
+      Window xwindow, w;
+
+      /* FIXME: untrusted clients not multidevice-safe */
+      xdisplay = GDK_SCREEN_XDISPLAY (default_screen);
+      xwindow = GDK_SCREEN_XROOTWIN (default_screen);
+
+      w = XCreateWindow (xdisplay, xwindow, 0, 0, 1, 1, 0,
+                         CopyFromParent, InputOnly, CopyFromParent,
+                         0, &attributes);
+      XIQueryPointer (xdisplay, device_xi2->device_id,
+                      w,
+                      &xroot_window,
+                      &xchild_window,
+                      &xroot_x, &xroot_y,
+                      &xwin_x, &xwin_y,
+                      &button_state,
+                      &mod_state,
+                      &group_state);
+      XDestroyWindow (xdisplay, w);
     }
 
   if (root_window)
-    *root_window = gdk_window_lookup_for_display (display, xroot_window);
+    *root_window = gdk_x11_window_lookup_for_display (display, xroot_window);
 
   if (child_window)
-    *child_window = gdk_window_lookup_for_display (display, xchild_window);
+    *child_window = gdk_x11_window_lookup_for_display (display, xchild_window);
 
   if (root_x)
     *root_x = (gint) xroot_x;
@@ -344,29 +389,32 @@ gdk_device_xi2_query_state (GdkDevice        *device,
     *win_y = (gint) xwin_y;
 
   if (mask)
-    *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
+    *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
+
+  free (button_state.mask);
 
   return TRUE;
 }
 
 static GdkGrabStatus
-gdk_device_xi2_grab (GdkDevice    *device,
-                     GdkWindow    *window,
-                     gboolean      owner_events,
-                     GdkEventMask  event_mask,
-                     GdkWindow    *confine_to,
-                     GdkCursor    *cursor,
-                     guint32       time_)
+gdk_x11_device_xi2_grab (GdkDevice    *device,
+                         GdkWindow    *window,
+                         gboolean      owner_events,
+                         GdkEventMask  event_mask,
+                         GdkWindow    *confine_to,
+                         GdkCursor    *cursor,
+                         guint32       time_)
 {
-  GdkDeviceXI2Private *priv;
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
+  GdkX11DeviceManagerXI2 *device_manager_xi2;
   GdkDisplay *display;
   XIEventMask mask;
   Window xwindow;
   Cursor xcursor;
-  int status;
+  gint status;
 
-  priv = GDK_DEVICE_XI2 (device)->priv;
   display = gdk_device_get_display (device);
+  device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
 
   /* FIXME: confine_to is actually unused */
 
@@ -377,14 +425,21 @@ gdk_device_xi2_grab (GdkDevice    *device,
   else
     {
       _gdk_x11_cursor_update_theme (cursor);
-      xcursor = ((GdkCursorPrivate *) cursor)->xcursor;
+      xcursor = gdk_x11_cursor_get_xcursor (cursor);
     }
 
-  mask.deviceid = priv->device_id;
-  mask.mask = gdk_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
+  mask.deviceid = device_xi2->device_id;
+  mask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
+                                                        event_mask,
+                                                        &mask.mask_len);
 
+#ifdef G_ENABLE_DEBUG
+  if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
+    status = GrabSuccess;
+  else
+#endif
   status = XIGrabDevice (GDK_DISPLAY_XDISPLAY (display),
-                         priv->device_id,
+                         device_xi2->device_id,
                          xwindow,
                          time_,
                          xcursor,
@@ -394,43 +449,45 @@ gdk_device_xi2_grab (GdkDevice    *device,
 
   g_free (mask.mask);
 
+  _gdk_x11_display_update_grab_info (display, device, status);
+
   return _gdk_x11_convert_grab_status (status);
 }
 
 static void
-gdk_device_xi2_ungrab (GdkDevice *device,
-                       guint32    time_)
+gdk_x11_device_xi2_ungrab (GdkDevice *device,
+                           guint32    time_)
 {
-  GdkDeviceXI2Private *priv;
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
   GdkDisplay *display;
+  gulong serial;
 
-  priv = GDK_DEVICE_XI2 (device)->priv;
   display = gdk_device_get_display (device);
+  serial = NextRequest (GDK_DISPLAY_XDISPLAY (display));
 
-  XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display),
-                  priv->device_id,
-                  time_);
+  XIUngrabDevice (GDK_DISPLAY_XDISPLAY (display), device_xi2->device_id, time_);
+
+  _gdk_x11_display_update_grab_info_ungrab (display, device, time_, serial);
 }
 
 static GdkWindow *
-gdk_device_xi2_window_at_position (GdkDevice       *device,
-                                   gint            *win_x,
-                                   gint            *win_y,
-                                   GdkModifierType *mask,
-                                   gboolean         get_toplevel)
+gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
+                                       gint            *win_x,
+                                       gint            *win_y,
+                                       GdkModifierType *mask,
+                                       gboolean         get_toplevel)
 {
-  GdkDeviceXI2Private *priv;
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
   GdkDisplay *display;
   GdkScreen *screen;
   Display *xdisplay;
   GdkWindow *window;
   Window xwindow, root, child, last = None;
   gdouble xroot_x, xroot_y, xwin_x, xwin_y;
-  XIButtonState button_state;
+  XIButtonState button_state = { 0 };
   XIModifierState mod_state;
   XIGroupState group_state;
 
-  priv = GDK_DEVICE_XI2 (device)->priv;
   display = gdk_device_get_display (device);
   screen = gdk_display_get_default_screen (display);
 
@@ -444,26 +501,109 @@ gdk_device_xi2_window_at_position (GdkDevice       *device,
   xdisplay = GDK_SCREEN_XDISPLAY (screen);
   xwindow = GDK_SCREEN_XROOTWIN (screen);
 
-  XIQueryPointer (xdisplay,
-                  priv->device_id,
-                  xwindow,
-                  &root, &child,
-                  &xroot_x, &xroot_y,
-                  &xwin_x, &xwin_y,
-                  &button_state,
-                  &mod_state,
-                  &group_state);
-
-  if (root == xwindow)
-    xwindow = child;
+  if (G_LIKELY (GDK_X11_DISPLAY (display)->trusted_client))
+    {
+      XIQueryPointer (xdisplay,
+                      device_xi2->device_id,
+                      xwindow,
+                      &root, &child,
+                      &xroot_x, &xroot_y,
+                      &xwin_x, &xwin_y,
+                      &button_state,
+                      &mod_state,
+                      &group_state);
+
+      if (root == xwindow)
+        xwindow = child;
+      else
+        xwindow = root;
+    }
   else
-    xwindow = root;
+    {
+      gint i, screens, width, height;
+      GList *toplevels, *list;
+      Window pointer_window, root, child;
+
+      /* FIXME: untrusted clients case not multidevice-safe */
+      pointer_window = None;
+      screens = gdk_display_get_n_screens (display);
+
+      for (i = 0; i < screens; ++i)
+        {
+          screen = gdk_display_get_screen (display, i);
+          toplevels = gdk_screen_get_toplevel_windows (screen);
+          for (list = toplevels; list != NULL; list = g_list_next (list))
+            {
+              window = GDK_WINDOW (list->data);
+              xwindow = GDK_WINDOW_XID (window);
+
+              /* Free previous button mask, if any */
+              g_free (button_state.mask);
+
+              gdk_x11_display_error_trap_push (display);
+              XIQueryPointer (xdisplay,
+                              device_xi2->device_id,
+                              xwindow,
+                              &root, &child,
+                              &xroot_x, &xroot_y,
+                              &xwin_x, &xwin_y,
+                              &button_state,
+                              &mod_state,
+                              &group_state);
+              if (gdk_x11_display_error_trap_pop (display))
+                continue;
+              if (child != None)
+                {
+                  pointer_window = child;
+                  break;
+                }
+              gdk_window_get_geometry (window, NULL, NULL, &width, &height);
+              if (xwin_x >= 0 && xwin_y >= 0 && xwin_x < width && xwin_y < height)
+                {
+                  /* A childless toplevel, or below another window? */
+                  XSetWindowAttributes attributes;
+                  Window w;
+
+                  free (button_state.mask);
+
+                  w = XCreateWindow (xdisplay, xwindow, (int)xwin_x, (int)xwin_y, 1, 1, 0,
+                                     CopyFromParent, InputOnly, CopyFromParent,
+                                     0, &attributes);
+                  XMapWindow (xdisplay, w);
+                  XIQueryPointer (xdisplay,
+                                  device_xi2->device_id,
+                                  xwindow,
+                                  &root, &child,
+                                  &xroot_x, &xroot_y,
+                                  &xwin_x, &xwin_y,
+                                  &button_state,
+                                  &mod_state,
+                                  &group_state);
+                  XDestroyWindow (xdisplay, w);
+                  if (child == w)
+                    {
+                      pointer_window = xwindow;
+                      break;
+                    }
+                }
+            }
+
+          g_list_free (toplevels);
+          if (pointer_window != None)
+            break;
+        }
+
+      xwindow = pointer_window;
+    }
 
   while (xwindow)
     {
       last = xwindow;
+      free (button_state.mask);
+
+      gdk_x11_display_error_trap_push (display);
       XIQueryPointer (xdisplay,
-                      priv->device_id,
+                      device_xi2->device_id,
                       xwindow,
                       &root, &xwindow,
                       &xroot_x, &xroot_y,
@@ -471,9 +611,11 @@ gdk_device_xi2_window_at_position (GdkDevice       *device,
                       &button_state,
                       &mod_state,
                       &group_state);
+      if (gdk_x11_display_error_trap_pop (display))
+        break;
 
       if (get_toplevel && last != root &&
-          (window = gdk_window_lookup_for_display (display, last)) != NULL &&
+          (window = gdk_x11_window_lookup_for_display (display, last)) != NULL &&
           GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
         {
           xwindow = last;
@@ -483,7 +625,7 @@ gdk_device_xi2_window_at_position (GdkDevice       *device,
 
   gdk_x11_display_ungrab (display);
 
-  window = gdk_window_lookup_for_display (display, last);
+  window = gdk_x11_window_lookup_for_display (display, last);
 
   if (win_x)
     *win_x = (window) ? (gint) xwin_x : -1;
@@ -492,36 +634,47 @@ gdk_device_xi2_window_at_position (GdkDevice       *device,
     *win_y = (window) ? (gint) xwin_y : -1;
 
   if (mask)
-    *mask = gdk_device_xi2_translate_state (&mod_state, &button_state);
+    *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
+
+  free (button_state.mask);
 
   return window;
 }
 
 static void
-gdk_device_xi2_select_window_events (GdkDevice    *device,
-                                     GdkWindow    *window,
-                                     GdkEventMask  event_mask)
+gdk_x11_device_xi2_select_window_events (GdkDevice    *device,
+                                         GdkWindow    *window,
+                                         GdkEventMask  event_mask)
 {
-  GdkDeviceXI2Private *priv;
+  GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
+  GdkX11DeviceManagerXI2 *device_manager_xi2;
+  GdkDisplay *display;
   XIEventMask evmask;
 
-  priv = GDK_DEVICE_XI2 (device)->priv;
+  display = gdk_device_get_display (device);
+  device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
 
-  evmask.deviceid = priv->device_id;
-  evmask.mask = gdk_device_xi2_translate_event_mask (event_mask, &evmask.mask_len);
+  evmask.deviceid = device_xi2->device_id;
+  evmask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
+                                                          event_mask,
+                                                          &evmask.mask_len);
 
   XISelectEvents (GDK_WINDOW_XDISPLAY (window),
-                  GDK_WINDOW_XWINDOW (window),
+                  GDK_WINDOW_XID (window),
                   &evmask, 1);
 
   g_free (evmask.mask);
 }
 
 guchar *
-gdk_device_xi2_translate_event_mask (GdkEventMask  event_mask,
-                                     int          *len)
+_gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
+                                          GdkEventMask            event_mask,
+                                          gint                   *len)
 {
   guchar *mask;
+  gint minor;
+
+  g_object_get (device_manager_xi2, "minor", &minor, NULL);
 
   *len = XIMaskLen (XI_LASTEVENT);
   mask = g_new0 (guchar, *len);
@@ -570,17 +723,29 @@ gdk_device_xi2_translate_event_mask (GdkEventMask  event_mask,
       XISetMask (mask, XI_FocusOut);
     }
 
+#ifdef XINPUT_2_2
+  /* XInput 2.2 includes multitouch support */
+  if (minor >= 2 &&
+      event_mask & GDK_TOUCH_MASK)
+    {
+      XISetMask (mask, XI_TouchBegin);
+      XISetMask (mask, XI_TouchUpdate);
+      XISetMask (mask, XI_TouchEnd);
+    }
+#endif /* XINPUT_2_2 */
+
   return mask;
 }
 
 guint
-gdk_device_xi2_translate_state (XIModifierState *mods_state,
-                                XIButtonState   *buttons_state)
+_gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
+                                     XIButtonState   *buttons_state,
+                                     XIGroupState    *group_state)
 {
   guint state = 0;
 
   if (mods_state)
-    state = (guint) mods_state->effective;
+    state = mods_state->effective;
 
   if (buttons_state)
     {
@@ -617,5 +782,93 @@ gdk_device_xi2_translate_state (XIModifierState *mods_state,
         }
     }
 
+  if (group_state)
+    state |= (group_state->effective) << 13;
+
   return state;
 }
+
+void
+_gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2    *device,
+                                         guint               n_valuator,
+                                         GdkScrollDirection  direction)
+{
+  ScrollValuator scroll;
+
+  g_return_if_fail (GDK_IS_X11_DEVICE_XI2 (device));
+  g_return_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)));
+
+  scroll.n_valuator = n_valuator;
+  scroll.direction = direction;
+  scroll.last_value_valid = FALSE;
+
+  g_array_append_val (device->scroll_valuators, scroll);
+}
+
+gboolean
+_gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2    *device,
+                                      guint               n_valuator,
+                                      gdouble             valuator_value,
+                                      GdkScrollDirection *direction_ret,
+                                      gdouble            *delta_ret)
+{
+  guint i;
+
+  g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), FALSE);
+  g_return_val_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)), FALSE);
+
+  for (i = 0; i < device->scroll_valuators->len; i++)
+    {
+      ScrollValuator *scroll;
+
+      scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
+
+      if (scroll->n_valuator == n_valuator)
+        {
+          if (direction_ret)
+            *direction_ret = scroll->direction;
+
+          if (delta_ret)
+            *delta_ret = 0;
+
+          if (scroll->last_value_valid)
+            {
+              if (delta_ret)
+                *delta_ret = valuator_value - scroll->last_value;
+
+              scroll->last_value = valuator_value;
+            }
+          else
+            {
+              scroll->last_value = valuator_value;
+              scroll->last_value_valid = TRUE;
+            }
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+void
+_gdk_device_xi2_reset_scroll_valuators (GdkX11DeviceXI2 *device)
+{
+  guint i;
+
+  for (i = 0; i < device->scroll_valuators->len; i++)
+    {
+      ScrollValuator *scroll;
+
+      scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
+      scroll->last_value_valid = FALSE;
+    }
+}
+
+gint
+_gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device)
+{
+  g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), 0);
+
+  return device->device_id;
+}