core: Add XInput2 device map implementation

This commit is contained in:
Carlos Garnacho 2011-06-13 23:29:37 +02:00
parent 3f7193e558
commit f0705e142c
5 changed files with 391 additions and 1 deletions

View File

@ -170,6 +170,8 @@ libmutter_la_SOURCES = \
if HAVE_XINPUT2 if HAVE_XINPUT2
libmutter_la_SOURCES += \ libmutter_la_SOURCES += \
core/device-map-xi2.c \
core/device-map-xi2.h \
core/devices-xi2.c \ core/devices-xi2.c \
core/devices-xi2.h core/devices-xi2.h
endif endif

265
src/core/device-map-xi2.c Normal file
View File

@ -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;
}

59
src/core/device-map-xi2.h Normal file
View File

@ -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 */

View File

@ -25,6 +25,14 @@
#include "device-map.h" #include "device-map.h"
#include "device-map-core.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) G_DEFINE_TYPE (MetaDeviceMap, meta_device_map, G_TYPE_OBJECT)
typedef struct MetaDeviceMapPrivate MetaDeviceMapPrivate; 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 * MetaDeviceMap *
meta_device_map_new (MetaDisplay *display, meta_device_map_new (MetaDisplay *display,
gboolean force_core) 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, "display", display,
NULL); NULL);
} }

View File

@ -71,6 +71,10 @@
#ifdef HAVE_XCURSOR #ifdef HAVE_XCURSOR
#include <X11/Xcursor/Xcursor.h> #include <X11/Xcursor/Xcursor.h>
#endif #endif
#ifdef HAVE_XINPUT2
#include <X11/extensions/XInput2.h>
#include "device-map-xi2.h"
#endif
#include <X11/extensions/Xrender.h> #include <X11/extensions/Xrender.h>
#include <X11/extensions/Xcomposite.h> #include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h> #include <X11/extensions/Xdamage.h>
@ -1725,6 +1729,17 @@ event_callback (XEvent *event,
} }
#endif /* HAVE_SHAPE */ #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)) if (meta_input_event_get_type (display, event, &evtype))
{ {
Window xwindow = meta_input_event_get_window (display, event); Window xwindow = meta_input_event_get_window (display, event);