diff --git a/configure.in b/configure.in index c760c5a30..5cb5f8241 100644 --- a/configure.in +++ b/configure.in @@ -224,6 +224,8 @@ if test x$have_xinput2 = xyes; then AC_DEFINE(HAVE_XINPUT2, , [Building with XInput2 support]) fi +AM_CONDITIONAL(HAVE_XINPUT2, test "$have_xinput2" = "yes") + PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES) # This is used for plugins diff --git a/src/Makefile.am b/src/Makefile.am index a1f321e95..55822b6e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -165,6 +165,12 @@ libmutter_la_SOURCES = \ ui/preview-widget.c \ $(mutter_built_sources) +if HAVE_XINPUT2 +libmutter_la_SOURCES += \ + core/devices-xi2.c \ + core/devices-xi2.h +endif + libmutter_la_LDFLAGS = -no-undefined libmutter_la_LIBADD = $(MUTTER_LIBS) diff --git a/src/core/devices-xi2.c b/src/core/devices-xi2.c new file mode 100644 index 000000000..00c8ffc84 --- /dev/null +++ b/src/core/devices-xi2.c @@ -0,0 +1,307 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* XInput2 devices 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 +#include "devices-xi2.h" +#include "display-private.h" +#include "screen-private.h" +#include + +/* Common functions */ +static void +meta_device_xi2_common_allow_events (MetaDevice *device, + int mode, + Time time) +{ + MetaDisplay *display; + gint device_id; + + display = meta_device_get_display (device); + device_id = meta_device_get_id (device); + + switch (mode) + { + case AsyncPointer: + case AsyncKeyboard: + mode = XIAsyncDevice; + break; + case SyncPointer: + case SyncKeyboard: + mode = XISyncDevice; + break; + case ReplayPointer: + case ReplayKeyboard: + mode = XIReplayDevice; + break; + case AsyncBoth: + mode = XIAsyncPair; + break; + case SyncBoth: + mode = XISyncPair; + break; + } + + XIAllowEvents (display->xdisplay, device_id, mode, time); +} + +static guchar * +translate_event_mask (guint evmask, + gint *len) +{ + guchar *mask; + + *len = XIMaskLen (XI_LASTEVENT); + mask = g_new0 (guchar, *len); + + if (evmask & KeyPressMask) + XISetMask (mask, XI_KeyPress); + if (evmask & KeyReleaseMask) + XISetMask (mask, XI_KeyRelease); + if (evmask & ButtonPressMask) + XISetMask (mask, XI_ButtonPress); + if (evmask & ButtonReleaseMask) + XISetMask (mask, XI_ButtonRelease); + if (evmask & EnterWindowMask) + XISetMask (mask, XI_Enter); + if (evmask & LeaveWindowMask) + XISetMask (mask, XI_Leave); + + /* No motion hints in XI2 at the moment... */ + if (evmask & PointerMotionMask || + evmask & PointerMotionHintMask) + XISetMask (mask, XI_Motion); + + if (evmask & FocusChangeMask) + { + XISetMask (mask, XI_FocusIn); + XISetMask (mask, XI_FocusOut); + } + + return mask; +} + +static gboolean +meta_device_xi2_common_grab (MetaDevice *device, + Window xwindow, + guint evmask, + MetaCursor cursor, + gboolean owner_events, + gboolean sync, + Time time) +{ + MetaDisplay *display; + XIEventMask mask; + gint device_id, retval; + Cursor xcursor; + + display = meta_device_get_display (device); + device_id = meta_device_get_id (device); + xcursor = meta_display_create_x_cursor (display, cursor); + + mask.deviceid = device_id; + mask.mask = translate_event_mask (evmask, &mask.mask_len); + + retval = XIGrabDevice (display->xdisplay, + device_id, xwindow, + time, xcursor, + (sync) ? GrabModeSync : GrabModeAsync, + (sync) ? GrabModeSync : GrabModeAsync, + owner_events, &mask); + + if (xcursor != None) + XFreeCursor (display->xdisplay, xcursor); + + return (retval == Success); +} + +static void +meta_device_xi2_common_ungrab (MetaDevice *device, + Time time) +{ + MetaDisplay *display; + gint device_id; + + display = meta_device_get_display (device); + device_id = meta_device_get_id (device); + + XIUngrabDevice (display->xdisplay, device_id, time); +} + +/* Pointer */ + +G_DEFINE_TYPE (MetaDevicePointerXI2, + meta_device_pointer_xi2, + META_TYPE_DEVICE_POINTER) + +static void +meta_device_pointer_xi2_warp (MetaDevicePointer *pointer, + MetaScreen *screen, + gint x, + gint y) +{ + MetaDisplay *display; + int device_id; + + display = meta_device_get_display (META_DEVICE (pointer)); + device_id = meta_device_get_id (META_DEVICE (pointer)); + + XIWarpPointer (display->xdisplay, + device_id, + None, screen->xroot, + 0, 0, 0, 0, x, y); +} + +static void +meta_device_pointer_xi2_set_window_cursor (MetaDevicePointer *pointer, + Window xwindow, + MetaCursor cursor) +{ + MetaDisplay *display; + Cursor xcursor; + int device_id; + + display = meta_device_get_display (META_DEVICE (pointer)); + device_id = meta_device_get_id (META_DEVICE (pointer)); + xcursor = meta_display_create_x_cursor (display, cursor); + + if (xcursor != None) + { + XIDefineCursor (display->xdisplay, device_id, xwindow, xcursor); + XFreeCursor (display->xdisplay, xcursor); + } + else + XIUndefineCursor (display->xdisplay, device_id, xwindow); +} + +static void +meta_device_pointer_xi2_query_position (MetaDevicePointer *pointer, + Window xwindow, + Window *root_ret, + Window *child_ret, + gint *root_x_ret, + gint *root_y_ret, + gint *x_ret, + gint *y_ret, + guint *mask_ret) +{ + MetaDisplay *display; + XIModifierState mods; + XIGroupState group_unused; + XIButtonState buttons; + gdouble root_x, root_y, x, y; + int device_id; + + display = meta_device_get_display (META_DEVICE (pointer)); + device_id = meta_device_get_id (META_DEVICE (pointer)); + + XIQueryPointer (display->xdisplay, + device_id, xwindow, + root_ret, child_ret, + &root_x, &root_y, &x, &y, + &buttons, &mods, + &group_unused); + if (mask_ret) + { + *mask_ret = mods.effective; + + if (XIMaskIsSet (buttons.mask, 1)) + *mask_ret |= Button1Mask; + else if (XIMaskIsSet (buttons.mask, 2)) + *mask_ret |= Button2Mask; + else if (XIMaskIsSet (buttons.mask, 3)) + *mask_ret |= Button3Mask; + } + + if (root_x_ret) + *root_x_ret = (int) root_x; + + if (root_y_ret) + *root_y_ret = (int) root_y; + + if (x_ret) + *x_ret = (int) x; + + if (y_ret) + *y_ret = (int) y; +} + +static void +meta_device_pointer_xi2_class_init (MetaDevicePointerXI2Class *klass) +{ + MetaDevicePointerClass *pointer_class = META_DEVICE_POINTER_CLASS (klass); + MetaDeviceClass *device_class = META_DEVICE_CLASS (klass); + + device_class->allow_events = meta_device_xi2_common_allow_events; + device_class->grab = meta_device_xi2_common_grab; + device_class->ungrab = meta_device_xi2_common_ungrab; + + pointer_class->warp = meta_device_pointer_xi2_warp; + pointer_class->set_window_cursor = meta_device_pointer_xi2_set_window_cursor; + pointer_class->query_position = meta_device_pointer_xi2_query_position; +} + +static void +meta_device_pointer_xi2_init (MetaDevicePointerXI2 *pointer) +{ +} + +MetaDevice * +meta_device_pointer_xi2_new (MetaDisplay *display, + gint device_id) +{ + return g_object_new (META_TYPE_DEVICE_POINTER_XI2, + "device-id", device_id, + "display", display, + NULL); +} + +/* Keyboard */ + +G_DEFINE_TYPE (MetaDeviceKeyboardXI2, + meta_device_keyboard_xi2, + META_TYPE_DEVICE_KEYBOARD) + +static void +meta_device_keyboard_xi2_class_init (MetaDeviceKeyboardXI2Class *klass) +{ + MetaDeviceClass *device_class = META_DEVICE_CLASS (klass); + + device_class->allow_events = meta_device_xi2_common_allow_events; + device_class->grab = meta_device_xi2_common_grab; + device_class->ungrab = meta_device_xi2_common_ungrab; +} + +static void +meta_device_keyboard_xi2_init (MetaDeviceKeyboardXI2 *keyboard) +{ +} + +MetaDevice * +meta_device_keyboard_xi2_new (MetaDisplay *display, + gint device_id) +{ + return g_object_new (META_TYPE_DEVICE_KEYBOARD_XI2, + "device-id", device_id, + "display", display, + NULL); +} diff --git a/src/core/devices-xi2.h b/src/core/devices-xi2.h new file mode 100644 index 000000000..bc9fbdca7 --- /dev/null +++ b/src/core/devices-xi2.h @@ -0,0 +1,87 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/** + * \file devices-xi2.h XInput2 input devices implementation + * + * Input devices. + * This file contains the XInput2 implementation of input devices. + */ + +/* + * 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_DEVICES_XI2_H +#define META_DEVICES_XI2_H + +#include "device-pointer.h" +#include "device-keyboard.h" + +/* Pointer */ +#define META_TYPE_DEVICE_POINTER_XI2 (meta_device_pointer_xi2_get_type ()) +#define META_DEVICE_POINTER_XI2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DEVICE_POINTER_XI2, MetaDevicePointerXI2)) +#define META_DEVICE_POINTER_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_DEVICE_POINTER_XI2, MetaDevicePointerXI2Class)) +#define META_IS_DEVICE_POINTER_XI2(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_DEVICE_POINTER_XI2)) +#define META_IS_DEVICE_POINTER_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_DEVICE_POINTER_XI2)) +#define META_DEVICE_POINTER_XI2_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_DEVICE_POINTER_XI2, MetaDevicePointerXI2Class)) + +typedef struct _MetaDevicePointerXI2 MetaDevicePointerXI2; +typedef struct _MetaDevicePointerXI2Class MetaDevicePointerXI2Class; + +struct _MetaDevicePointerXI2 +{ + MetaDevicePointer parent_instance; +}; + +struct _MetaDevicePointerXI2Class +{ + MetaDevicePointerClass parent_class; +}; + +GType meta_device_pointer_xi2_get_type (void) G_GNUC_CONST; + +MetaDevice *meta_device_pointer_xi2_new (MetaDisplay *display, + gint device_id); + +/* Keyboard */ +#define META_TYPE_DEVICE_KEYBOARD_XI2 (meta_device_keyboard_xi2_get_type ()) +#define META_DEVICE_KEYBOARD_XI2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_DEVICE_KEYBOARD_XI2, MetaDeviceKeyboardXI2)) +#define META_DEVICE_KEYBOARD_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_DEVICE_KEYBOARD_XI2, MetaDeviceKeyboardXI2Class)) +#define META_IS_DEVICE_KEYBOARD_XI2(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_DEVICE_KEYBOARD_XI2)) +#define META_IS_DEVICE_KEYBOARD_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_DEVICE_KEYBOARD_XI2)) +#define META_DEVICE_KEYBOARD_XI2_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_DEVICE_KEYBOARD_XI2, MetaDeviceKeyboardXI2Class)) + +typedef struct _MetaDeviceKeyboardXI2 MetaDeviceKeyboardXI2; +typedef struct _MetaDeviceKeyboardXI2Class MetaDeviceKeyboardXI2Class; + +struct _MetaDeviceKeyboardXI2 +{ + MetaDeviceKeyboard parent_instance; +}; + +struct _MetaDeviceKeyboardXI2Class +{ + MetaDeviceKeyboardClass parent_class; +}; + +GType meta_device_keyboard_xi2_get_type (void) G_GNUC_CONST; + +MetaDevice *meta_device_keyboard_xi2_new (MetaDisplay *display, + gint device_id); + +#endif /* META_DEVICES_XI2_H */