[mutter/wip/multitouch: 26/73] core: Add XInput2 device map implementation



commit 67018d2d0413764f789509202540c74807b9bef3
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Jun 13 23:29:37 2011 +0200

    core: Add XInput2 device map implementation

 src/Makefile.am           |    2 +
 src/core/device-map-xi2.c |  265 +++++++++++++++++++++++++++++++++++++++++++++
 src/core/device-map-xi2.h |   59 ++++++++++
 src/core/device-map.c     |   51 +++++++++-
 src/core/display.c        |   15 +++
 5 files changed, 391 insertions(+), 1 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index e9420eb..4cec637 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -173,6 +173,8 @@ libmutter_la_SOURCES =				\
 
 if HAVE_XINPUT2
 libmutter_la_SOURCES += 			\
+	core/device-map-xi2.c			\
+	core/device-map-xi2.h			\
 	core/devices-xi2.c			\
 	core/devices-xi2.h
 endif
diff --git a/src/core/device-map-xi2.c b/src/core/device-map-xi2.c
new file mode 100644
index 0000000..10690df
--- /dev/null
+++ b/src/core/device-map-xi2.c
@@ -0,0 +1,265 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* Input device map, XInput2 implementation */
+
+/*
+ * Copyright (C) 2011 Carlos Garnacho
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "device-map-xi2.h"
+#include <X11/extensions/XInput2.h>
+#include "devices-xi2.h"
+
+#define XINPUT2_VERSION_MAJOR 2
+#define XINPUT2_VERSION_MINOR 0
+
+G_DEFINE_TYPE (MetaDeviceMapXI2, meta_device_map_xi2, META_TYPE_DEVICE_MAP)
+
+static gboolean
+meta_device_map_xi2_grab_key (MetaDeviceMap *device_map,
+                              Window         xwindow,
+                              guint          keycode,
+                              guint          modifiers,
+                              gboolean       sync)
+{
+  XIGrabModifiers mods = { modifiers, 0 };
+  MetaDisplay *display;
+  XIEventMask mask;
+  gint retval;
+
+  display = meta_device_map_get_display (device_map);
+
+  mask.deviceid = XIAllMasterDevices;
+  mask.mask = meta_device_xi2_translate_event_mask (KeyPressMask |
+                                                    KeyReleaseMask,
+                                                    &mask.mask_len);
+
+  retval = XIGrabKeycode (display->xdisplay,
+                          XIAllMasterDevices,
+                          keycode, xwindow,
+                          (sync) ? GrabModeSync : GrabModeAsync,
+                          GrabModeAsync, /* Never care about the other device */
+                          True, &mask, 1, &mods);
+
+  return (retval == Success);
+}
+
+static void
+meta_device_map_xi2_ungrab_key (MetaDeviceMap *device_map,
+                                Window         xwindow,
+                                guint          keycode,
+                                guint          modifiers)
+{
+  XIGrabModifiers mods = { modifiers, 0 };
+  MetaDisplay *display;
+
+  display = meta_device_map_get_display (device_map);
+  XIUngrabKeycode (display->xdisplay,
+                   XIAllMasterDevices,
+                   keycode, xwindow,
+                   1, &mods);
+}
+
+static gboolean
+meta_device_map_xi2_grab_button (MetaDeviceMap *device_map,
+                                 Window         xwindow,
+                                 guint          n_button,
+                                 guint          modifiers,
+                                 guint          evmask,
+                                 gboolean       sync)
+{
+  XIGrabModifiers mods = { modifiers, 0 };
+  XIEventMask mask;
+  MetaDisplay *display;
+  int retval;
+
+  display = meta_device_map_get_display (device_map);
+
+  mask.deviceid = XIAllMasterDevices;
+  mask.mask = meta_device_xi2_translate_event_mask (evmask, &mask.mask_len);
+
+  retval = XIGrabButton (display->xdisplay,
+                         XIAllMasterDevices,
+                         n_button, xwindow, None,
+                         (sync) ? GrabModeSync : GrabModeAsync,
+                         GrabModeAsync, /* Never care about the other device */
+                         False, &mask, 1, &mods);
+
+  return (retval == Success);
+}
+
+static void
+meta_device_map_xi2_ungrab_button (MetaDeviceMap *device_map,
+                                   Window         xwindow,
+                                   guint          n_button,
+                                   guint          modifiers)
+{
+  XIGrabModifiers mods = { modifiers, 0 };
+  MetaDisplay *display;
+
+  display = meta_device_map_get_display (device_map);
+  XIUngrabButton (display->xdisplay,
+                  XIAllMasterDevices,
+                  n_button, xwindow, 1, &mods);
+}
+
+static void
+add_device_from_info (MetaDeviceMap *device_map,
+                      gint           use,
+                      gint           device_id)
+{
+  MetaDevice *device;
+  MetaDisplay *display;
+
+  display = meta_device_map_get_display (device_map);
+
+  if (use == XIMasterPointer)
+    device = meta_device_pointer_xi2_new (display, device_id);
+  else if (use == XIMasterKeyboard)
+    device = meta_device_keyboard_xi2_new (display, device_id);
+
+  if (device)
+    {
+      meta_device_map_add_device (device_map, device);
+      g_object_unref (device);
+    }
+}
+
+static void
+pair_devices (gpointer key,
+              gpointer value,
+              gpointer user_data)
+{
+  MetaDevice *device1, *device2;
+  MetaDeviceMap *device_map;
+
+  device_map = user_data;
+  device1 = meta_device_map_lookup (device_map, GPOINTER_TO_INT (key));
+  device2 = meta_device_map_lookup (device_map, GPOINTER_TO_INT (value));
+
+  meta_device_pair_devices (device1, device2);
+}
+
+static void
+meta_device_map_xi2_constructed (GObject *object)
+{
+  MetaDeviceMap *device_map = META_DEVICE_MAP (object);
+  MetaDisplay *display;
+  XIDeviceInfo *info;
+  GHashTable *pairs;
+  int n_devices, i;
+
+  display = meta_device_map_get_display (device_map);
+
+  /* We're only interested in master devices,
+   * detached slave devices are left for applications
+   * to handle.
+   */
+  info = XIQueryDevice (display->xdisplay, XIAllMasterDevices, &n_devices);
+  pairs = g_hash_table_new (NULL, NULL);
+
+  for (i = 0; i < n_devices; i++)
+    {
+      add_device_from_info (device_map, info[i].use, info[i].deviceid);
+      g_hash_table_insert (pairs,
+                           GINT_TO_POINTER (info[i].deviceid),
+                           GINT_TO_POINTER (info[i].attachment));
+    }
+
+  g_hash_table_foreach (pairs, pair_devices, device_map);
+  g_hash_table_destroy (pairs);
+
+  XIFreeDeviceInfo (info);
+}
+
+static void
+meta_device_map_xi2_class_init (MetaDeviceMapXI2Class *klass)
+{
+  MetaDeviceMapClass *device_map_class = META_DEVICE_MAP_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructed = meta_device_map_xi2_constructed;
+
+  device_map_class->grab_key = meta_device_map_xi2_grab_key;
+  device_map_class->ungrab_key = meta_device_map_xi2_ungrab_key;
+  device_map_class->grab_button = meta_device_map_xi2_grab_button;
+  device_map_class->ungrab_button = meta_device_map_xi2_ungrab_button;
+}
+
+static void
+meta_device_map_xi2_init (MetaDeviceMapXI2 *device_map)
+{
+}
+
+gboolean
+meta_device_map_xi2_handle_hierarchy_event (MetaDeviceMapXI2 *device_map,
+                                            XEvent           *ev)
+{
+  MetaDisplay *display;
+
+  display = meta_device_map_get_display (META_DEVICE_MAP (device_map));
+
+  if (ev->type == GenericEvent &&
+      ev->xcookie.extension == display->xinput2_opcode)
+    {
+      XIHierarchyEvent *xev;
+      GHashTable *pairs;
+      gint i;
+
+      g_assert (display->have_xinput2 == TRUE);
+
+      xev = (XIHierarchyEvent *) ev->xcookie.data;
+
+      if (xev->evtype != XI_HierarchyChanged)
+        return FALSE;
+
+      pairs = g_hash_table_new (NULL, NULL);
+
+      for (i = 0; i < xev->num_info; i++)
+        {
+          if (xev->info[i].flags & XIMasterAdded)
+            {
+              add_device_from_info (META_DEVICE_MAP (device_map),
+                                    xev->info[i].use,
+                                    xev->info[i].deviceid);
+              g_hash_table_insert (pairs,
+                                   GINT_TO_POINTER (xev->info[i].deviceid),
+                                   GINT_TO_POINTER (xev->info[i].attachment));
+            }
+          else if (xev->info[i].flags & XIMasterRemoved)
+            {
+              MetaDevice *device;
+
+              device = meta_device_map_lookup (META_DEVICE_MAP (device_map),
+                                               xev->info[i].deviceid);
+
+              if (device)
+                meta_device_map_remove_device (META_DEVICE_MAP (device_map),
+                                               device);
+            }
+        }
+
+      g_hash_table_foreach (pairs, pair_devices, device_map);
+      g_hash_table_destroy (pairs);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
diff --git a/src/core/device-map-xi2.h b/src/core/device-map-xi2.h
new file mode 100644
index 0000000..be3830a
--- /dev/null
+++ b/src/core/device-map-xi2.h
@@ -0,0 +1,59 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/**
+ * \file device-map-xi2.h  device map for XInput2 devices
+ *
+ * Input devices.
+ * This file contains the XInput2 implementation of the device map
+ */
+
+/*
+ * Copyright (C) 2011 Carlos Garnacho
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_DEVICE_MAP_XI2_H
+#define META_DEVICE_MAP_XI2_H
+
+typedef struct _MetaDeviceMapXI2 MetaDeviceMapXI2;
+typedef struct _MetaDeviceMapXI2Class MetaDeviceMapXI2Class;
+
+#include "device-map.h"
+
+#define META_TYPE_DEVICE_MAP_XI2            (meta_device_map_xi2_get_type ())
+#define META_DEVICE_MAP_XI2(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DEVICE_MAP_XI2, MetaDeviceMapXI2))
+#define META_DEVICE_MAP_XI2_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_DEVICE_MAP_XI2, MetaDeviceMapXI2Class))
+#define META_IS_DEVICE_MAP_XI2(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_DEVICE_MAP_XI2))
+#define META_IS_DEVICE_MAP_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_DEVICE_MAP_XI2))
+#define META_DEVICE_MAP_XI2_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_DEVICE_MAP_XI2, MetaDeviceMapXI2Class))
+
+struct _MetaDeviceMapXI2
+{
+  MetaDeviceMap parent_instance;
+};
+
+struct _MetaDeviceMapXI2Class
+{
+  MetaDeviceMapClass parent_class;
+};
+
+GType           meta_device_map_xi2_get_type        (void) G_GNUC_CONST;
+
+gboolean meta_device_map_xi2_handle_hierarchy_event (MetaDeviceMapXI2 *device_map,
+                                                     XEvent           *ev);
+
+#endif /* META_DEVICE_MAP_XI2_H */
diff --git a/src/core/device-map.c b/src/core/device-map.c
index 1f28ed4..df0f0da 100644
--- a/src/core/device-map.c
+++ b/src/core/device-map.c
@@ -25,6 +25,14 @@
 #include "device-map.h"
 #include "device-map-core.h"
 
+#ifdef HAVE_XINPUT2
+#include <X11/extensions/XInput2.h>
+#include "device-map-xi2.h"
+
+#define XINPUT2_VERSION_MAJOR 2
+#define XINPUT2_VERSION_MINOR 0
+#endif
+
 G_DEFINE_TYPE (MetaDeviceMap, meta_device_map, G_TYPE_OBJECT)
 
 typedef struct MetaDeviceMapPrivate MetaDeviceMapPrivate;
@@ -192,11 +200,52 @@ meta_device_map_remove_device (MetaDeviceMap *device_map,
     }
 }
 
+
+#ifdef HAVE_XINPUT2
+
+static gboolean
+initialize_xinput (MetaDisplay *display)
+{
+  int major, minor, opcode;
+  int unused;
+
+  if (!XQueryExtension (display->xdisplay,
+                        "XInputExtension",
+                        &opcode, &unused, &unused))
+    return FALSE;
+
+  major = XINPUT2_VERSION_MAJOR;
+  minor = XINPUT2_VERSION_MINOR;
+
+  XIQueryVersion (display->xdisplay, &major, &minor);
+
+  if (major == XINPUT2_VERSION_MAJOR &&
+      minor == XINPUT2_VERSION_MINOR)
+    {
+      display->have_xinput2 = TRUE;
+      display->xinput2_opcode = opcode;
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+#endif /* HAVE_XINPUT2 */
+
 MetaDeviceMap *
 meta_device_map_new (MetaDisplay *display,
                      gboolean     force_core)
 {
-  return g_object_new (META_TYPE_DEVICE_MAP_CORE,
+  GType type = META_TYPE_DEVICE_MAP_CORE;
+
+#ifdef HAVE_XINPUT2
+  if (!force_core &&
+      initialize_xinput (display))
+    type = META_TYPE_DEVICE_MAP_XI2;
+#endif
+
+  return g_object_new (type,
                        "display", display,
                        NULL);
 }
diff --git a/src/core/display.c b/src/core/display.c
index 604eb9c..22cbf43 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -71,6 +71,10 @@
 #ifdef HAVE_XCURSOR
 #include <X11/Xcursor/Xcursor.h>
 #endif
+#ifdef HAVE_XINPUT2
+#include <X11/extensions/XInput2.h>
+#include "device-map-xi2.h"
+#endif
 #include <X11/extensions/Xrender.h>
 #include <X11/extensions/Xcomposite.h>
 #include <X11/extensions/Xdamage.h>
@@ -1734,6 +1738,17 @@ event_callback (XEvent   *event,
     }
 #endif /* HAVE_SHAPE */
 
+#ifdef HAVE_XINPUT2
+  if (display->have_xinput2 &&
+      meta_device_map_xi2_handle_hierarchy_event (META_DEVICE_MAP_XI2 (display->device_map),
+                                                  event))
+    {
+      /* Let GDK Handle the event too for its own device accounting */
+      filter_out_event = FALSE;
+      bypass_compositor = FALSE;
+    }
+  else
+#endif
   if (meta_input_event_get_type (display, event, &evtype))
     {
       Window xwindow = meta_input_event_get_window (display, event);



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