summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2011-06-13 23:29:37 +0200
committerJasper St. Pierre <jstpierre@mecheye.net>2012-11-03 19:47:34 -0400
commit93c7a221617bf6632003ffcbc9a46fbdf6453427 (patch)
tree2353aef1dcebc2202886fefbaa1e0fdbb57cdce1
parent9f06372e178c4fb55d0d4d09e6f7f1dd205bf468 (diff)
downloadmutter-93c7a221617bf6632003ffcbc9a46fbdf6453427.tar.gz
core: Add XInput2 device map implementation
-rw-r--r--src/Makefile.am2
-rw-r--r--src/core/device-map-xi2.c265
-rw-r--r--src/core/device-map-xi2.h59
-rw-r--r--src/core/device-map.c51
-rw-r--r--src/core/display.c15
5 files changed, 391 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 55822b6e5..fd0107378 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -167,6 +167,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 000000000..7f9cccadc
--- /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 2
+
+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 000000000..be3830a3f
--- /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 1f28ed407..4c972dee4 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 2
+#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 4ed11b035..59551b5dd 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -69,6 +69,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>
@@ -1944,6 +1948,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);