summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/client.c4
-rw-r--r--src/device.c627
-rw-r--r--src/device.h186
-rw-r--r--src/display.c5
-rw-r--r--src/display.h1
-rw-r--r--src/event_filter.c8
-rw-r--r--src/event_filter.h7
-rw-r--r--src/main.c7
-rw-r--r--src/mywindow.c10
-rw-r--r--src/screen.c2
11 files changed, 854 insertions, 5 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8a6309e62..af9dea45d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,6 +7,8 @@ xfwm4_SOURCES = \
compositor.h \
cycle.c \
cycle.h \
+ device.c \
+ device.h \
display.c \
display.h \
event_filter.c \
diff --git a/src/client.c b/src/client.c
index db61862b1..735dcf5b2 100644
--- a/src/client.c
+++ b/src/client.c
@@ -1872,6 +1872,10 @@ clientFrame (DisplayInfo *display_info, Window w, gboolean recapture)
c->frame =
XCreateWindow (display_info->dpy, screen_info->xroot, 0, 0, 1, 1, 0,
c->depth, InputOutput, c->visual, valuemask, &attributes);
+#ifdef HAVE_XI2
+ xfwm_device_configure_xi2_event_mask (display_info->devices, display_info->dpy,
+ c->frame, attributes.event_mask);
+#endif
XSelectInput (display_info->dpy, c->window, NoEventMask);
XSetWindowBorderWidth (display_info->dpy, c->window, 0);
diff --git a/src/device.c b/src/device.c
new file mode 100644
index 000000000..b1e33ae2f
--- /dev/null
+++ b/src/device.c
@@ -0,0 +1,627 @@
+/* $Id$
+
+ 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, 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., Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+
+ device.c - (c) 2017 Viktor Odintsev
+
+ */
+
+#include "device.h"
+
+#include <gdk/gdkx.h>
+#ifdef HAVE_XI2
+#include <X11/extensions/XInput2.h>
+#endif
+
+#ifdef HAVE_XI2
+static const struct
+{
+ guint core_mask;
+ guint xi2_event;
+} core_to_xi2[] =
+{
+ { KeyPressMask, XI_KeyPress },
+ { KeyReleaseMask, XI_KeyRelease },
+ { ButtonPressMask, XI_ButtonPress },
+ { ButtonReleaseMask, XI_ButtonRelease },
+ { PointerMotionMask | ButtonMotionMask, XI_Motion },
+ { EnterWindowMask, XI_Enter },
+ { LeaveWindowMask, XI_Leave }
+};
+#endif
+
+#define xfwm_device_fill_meta(evtype, evwindow, evdevice) \
+{ \
+ if (event == NULL) \
+ { \
+ event = g_new0 (XfwmEvent, 1); \
+ } \
+ event->meta.type = evtype; \
+ event->meta.window = evwindow; \
+ event->meta.device = evdevice; \
+ event->meta.x = xevent; \
+}
+
+#ifdef HAVE_XI2
+static guint
+xfwm_device_obtain_state_xi2 (XIButtonState *buttons, XIModifierState *mods, XIGroupState *group)
+{
+ guint result;
+ gint i, count;
+
+ result = mods->effective | (group->effective << 13);
+ count = MIN (3, buttons->mask_len / 8);
+ for (i = 0; i < count; i++)
+ {
+ /* check first 3 buttons as GDK does */
+ if (XIMaskIsSet (buttons->mask, i + 1))
+ {
+ result |= 1 << (8 + i);
+ }
+ }
+
+ return result;
+}
+#endif
+
+static XfwmEvent *
+xfwm_device_translate_event_key_core (XEvent *xevent, XfwmEvent *event)
+{
+ xfwm_device_fill_meta (XFWM_EVENT_KEY, xevent->xany.window, None);
+
+ event->key.root = xevent->xkey.root;
+ event->key.pressed = xevent->type == KeyPress;
+ event->key.keycode = xevent->xkey.keycode;
+ event->key.state = xevent->xkey.state;
+ event->key.time = xevent->xkey.time;
+
+ return (XfwmEvent *)event;
+}
+
+#ifdef HAVE_XI2
+static XfwmEvent *
+xfwm_device_translate_event_key_xi2 (XEvent *xevent, XIDeviceEvent *xievent, XfwmEvent *event)
+{
+ xfwm_device_fill_meta (XFWM_EVENT_KEY, xievent->event, xievent->deviceid);
+
+ event->key.root = xievent->root;
+ event->key.pressed = xievent->evtype == XI_KeyPress;
+ event->key.keycode = xievent->detail;
+ event->key.state = xfwm_device_obtain_state_xi2 (&xievent->buttons,
+ &xievent->mods,
+ &xievent->group);
+ event->key.time = xievent->time;
+
+ return (XfwmEvent *)event;
+}
+#endif
+
+static XfwmEvent *
+xfwm_device_translate_event_button_core (XEvent *xevent, XfwmEvent *event)
+{
+ xfwm_device_fill_meta (XFWM_EVENT_BUTTON, xevent->xany.window, None);
+
+ event->button.root = xevent->xbutton.root;
+ event->button.subwindow = xevent->xbutton.subwindow;
+ event->button.pressed = xevent->type == ButtonPress;
+ event->button.button = xevent->xbutton.button;
+ event->button.state = xevent->xbutton.state;
+ event->button.x = xevent->xbutton.x;
+ event->button.y = xevent->xbutton.y;
+ event->button.x_root = xevent->xbutton.x_root;
+ event->button.y_root = xevent->xbutton.y_root;
+ event->button.time = xevent->xbutton.time;
+
+ return (XfwmEvent *)event;
+}
+
+#ifdef HAVE_XI2
+static XfwmEvent *
+xfwm_device_translate_event_button_xi2 (XEvent *xevent, XIDeviceEvent *xievent, XfwmEvent *event)
+{
+ xfwm_device_fill_meta (XFWM_EVENT_BUTTON, xievent->event, xievent->deviceid);
+
+ event->button.root = xievent->root;
+ event->button.subwindow = xievent->child;
+ event->button.pressed = xievent->evtype == XI_ButtonPress;
+ event->button.button = xievent->detail;
+ event->button.state = xfwm_device_obtain_state_xi2 (&xievent->buttons,
+ &xievent->mods,
+ &xievent->group);
+ event->button.x = xievent->event_x;
+ event->button.y = xievent->event_y;
+ event->button.x_root = xievent->root_x;
+ event->button.y_root = xievent->root_y;
+ event->button.time = xievent->time;
+
+ return (XfwmEvent *)event;
+}
+#endif
+
+static XfwmEvent *
+xfwm_device_translate_event_motion_core (XEvent *xevent, XfwmEvent *event)
+{
+ xfwm_device_fill_meta (XFWM_EVENT_MOTION, xevent->xany.window, None);
+
+ event->motion.x = xevent->xbutton.x;
+ event->motion.y = xevent->xbutton.y;
+ event->motion.x_root = xevent->xbutton.x_root;
+ event->motion.y_root = xevent->xbutton.y_root;
+ event->motion.time = xevent->xbutton.time;
+
+ return (XfwmEvent *)event;
+}
+
+#ifdef HAVE_XI2
+static XfwmEvent *
+xfwm_device_translate_event_motion_xi2 (XEvent *xevent, XIDeviceEvent *xievent, XfwmEvent *event)
+{
+ xfwm_device_fill_meta (XFWM_EVENT_MOTION, xievent->event, xievent->deviceid);
+
+ event->motion.x = xievent->event_x;
+ event->motion.y = xievent->event_y;
+ event->motion.x_root = xievent->root_x;
+ event->motion.y_root = xievent->root_y;
+ event->motion.time = xievent->time;
+
+ return (XfwmEvent *)event;
+}
+#endif
+
+static XfwmEvent *
+xfwm_device_translate_event_crossing_core (XEvent *xevent, XfwmEvent *event)
+{
+ xfwm_device_fill_meta (XFWM_EVENT_CROSSING, xevent->xany.window, None);
+
+ event->crossing.root = xevent->xcrossing.root;
+ event->crossing.enter = xevent->type == EnterNotify;
+ event->crossing.mode = xevent->xcrossing.mode;
+ event->crossing.detail = xevent->xcrossing.detail;
+ event->crossing.x_root = xevent->xcrossing.x_root;
+ event->crossing.y_root = xevent->xcrossing.y_root;
+ event->crossing.time = xevent->xcrossing.time;
+
+ return (XfwmEvent *)event;
+}
+
+#ifdef HAVE_XI2
+static XfwmEvent *
+xfwm_device_translate_event_crossing_xi2 (XEvent *xevent, XIEnterEvent *xievent, XfwmEvent *event)
+{
+ xfwm_device_fill_meta (XFWM_EVENT_CROSSING, xievent->event, xievent->deviceid);
+
+ event->crossing.root = xievent->root;
+ event->crossing.enter = xievent->evtype == XI_Enter;
+ event->crossing.mode = xievent->mode;
+ event->crossing.detail = xievent->detail;
+ event->crossing.x_root = xievent->root_x;
+ event->crossing.y_root = xievent->root_y;
+ event->crossing.time = xievent->time;
+
+ return (XfwmEvent *)event;
+}
+#endif
+
+static XfwmEvent *
+xfwm_device_translate_event_common (XEvent *xevent, XfwmEvent *event)
+{
+ xfwm_device_fill_meta (XFWM_EVENT_X, xevent->xany.window, None);
+
+ return event;
+}
+
+XfwmEvent *
+xfwm_device_translate_event (XfwmDevices *devices, XEvent *xevent, XfwmEvent *event)
+{
+ switch (xevent->type)
+ {
+ case KeyPress:
+ case KeyRelease:
+ return xfwm_device_translate_event_key_core (xevent, event);
+ case ButtonPress:
+ case ButtonRelease:
+ return xfwm_device_translate_event_button_core (xevent, event);
+ case MotionNotify:
+ return xfwm_device_translate_event_motion_core (xevent, event);
+ case EnterNotify:
+ case LeaveNotify:
+ return xfwm_device_translate_event_crossing_core (xevent, event);
+#ifdef HAVE_XI2
+ case GenericEvent:
+ if (devices->xi2_available &&
+ xevent->xgeneric.extension == devices->xi2_opcode &&
+ xevent->xcookie.data != NULL)
+ {
+ XIEvent *xievent = xevent->xcookie.data;
+
+ switch (xievent->evtype)
+ {
+ case XI_KeyPress:
+ case XI_KeyRelease:
+ return xfwm_device_translate_event_key_xi2 (xevent, (XIDeviceEvent *)xievent, event);
+ case XI_ButtonPress:
+ case XI_ButtonRelease:
+ return xfwm_device_translate_event_button_xi2 (xevent, (XIDeviceEvent *)xievent, event);
+ case XI_Motion:
+ return xfwm_device_translate_event_motion_xi2 (xevent, (XIDeviceEvent *)xievent, event);
+ case XI_Enter:
+ case XI_Leave:
+ return xfwm_device_translate_event_crossing_xi2 (xevent, (XIEnterEvent *)xievent, event);
+ }
+ }
+ break;
+#endif
+ }
+
+ return xfwm_device_translate_event_common (xevent, event);
+}
+
+void
+xfwm_device_free_event (XfwmEvent *event)
+{
+ g_free (event);
+}
+
+void
+xfwm_device_button_update_window (XfwmEventButton *event, Window window)
+{
+ event->meta.window = window;
+#ifdef HAVE_XI2
+ if (event->meta.device != None)
+ {
+ ((XIDeviceEvent *)event->meta.x->xcookie.data)->event = window;
+ }
+ else
+#endif
+ {
+ event->meta.x->xany.window = window;
+ }
+}
+
+#ifdef HAVE_XI2
+static void
+xfwm_device_fill_xi2_event_mask (XIEventMask *xievent_mask, gulong core_mask)
+{
+ gint len = XIMaskLen (XI_LASTEVENT);
+ guchar *mask = g_new0 (guchar, len);
+ guint i;
+
+ xievent_mask->deviceid = XIAllMasterDevices;
+ xievent_mask->mask_len = sizeof (mask);
+ xievent_mask->mask = mask;
+
+ for (i = 0; i < G_N_ELEMENTS (core_to_xi2); i++)
+ {
+ if ((core_mask & core_to_xi2[i].core_mask) == core_to_xi2[i].core_mask)
+ {
+ XISetMask (mask, core_to_xi2[i].xi2_event);
+ }
+ }
+
+ #undef xi2_set_mask
+}
+#endif
+
+#ifdef HAVE_XI2
+void
+xfwm_device_configure_xi2_event_mask (XfwmDevices *devices, Display *dpy,
+ Window window, gulong core_mask)
+{
+ if (devices->xi2_available)
+ {
+ XIEventMask xievent_mask;
+ xfwm_device_fill_xi2_event_mask (&xievent_mask, core_mask);
+ XISelectEvents (dpy, window, &xievent_mask, 1);
+ g_free (xievent_mask.mask);
+ }
+}
+#endif
+
+#ifdef HAVE_XI2
+#define xi2_modifier_mask(core_mask) \
+ ((((core_mask) & AnyModifier) == AnyModifier) \
+ ? (((core_mask) & ~AnyModifier) | XIAnyModifier) \
+ : (core_mask))
+#endif
+
+gboolean
+xfwm_device_grab (XfwmDevices *devices, XfwmDevice *device, Display *display,
+ Window grab_window, gboolean owner_events, guint event_mask,
+ gint grab_mode, Window confine_to, Cursor cursor, Time time)
+{
+ gboolean result;
+ Status status;
+#ifdef HAVE_XI2
+ XIEventMask xievent_mask;
+#endif
+
+#ifdef HAVE_XI2
+ if (device->xi2_device != None)
+ {
+ xfwm_device_fill_xi2_event_mask (&xievent_mask, event_mask);
+ status = XIGrabDevice (display, device->xi2_device, grab_window, time, cursor,
+ grab_mode, grab_mode, owner_events, &xievent_mask);
+ g_free (xievent_mask.mask);
+ result = (status == XIGrabSuccess);
+ }
+ else
+#endif
+ if (device->keyboard)
+ {
+ status = XGrabKeyboard (display, grab_window, owner_events,
+ grab_mode, grab_mode, time);
+ result = (status == GrabSuccess);
+ }
+ else
+ {
+ status = XGrabPointer (display, grab_window, owner_events, event_mask,
+ grab_mode, grab_mode, confine_to, cursor, time);
+ result = (status == GrabSuccess);
+ }
+ return result;
+}
+
+void
+xfwm_device_ungrab (XfwmDevices *devices, XfwmDevice *device, Display *display, Time time)
+{
+#ifdef HAVE_XI2
+ if (device->xi2_device != None)
+ {
+ XIUngrabDevice (display, device->xi2_device, time);
+ }
+ else
+#endif
+ if (device->keyboard)
+ {
+ XUngrabKeyboard (display, time);
+ }
+ else
+ {
+ XUngrabPointer (display, time);
+ }
+}
+
+gboolean
+xfwm_device_grab_button (XfwmDevices *devices, Display *display,
+ guint button, guint modifiers, Window grab_window,
+ gboolean owner_events, guint event_mask,
+ gint grab_mode, gint paired_device_mode,
+ Window confine_to, Cursor cursor)
+{
+ gboolean result;
+ Status status;
+#ifdef HAVE_XI2
+ XIGrabModifiers xi2_modifiers;
+ XIEventMask xievent_mask;
+#endif
+
+#ifdef HAVE_XI2
+ if (devices->xi2_available)
+ {
+ xi2_modifiers.modifiers = xi2_modifier_mask (modifiers);
+ xi2_modifiers.status = 0;
+
+ xfwm_device_fill_xi2_event_mask (&xievent_mask, event_mask);
+ status = XIGrabButton (display, devices->pointer.xi2_device, button, grab_window,
+ cursor, grab_mode, paired_device_mode, owner_events,
+ &xievent_mask, 1, &xi2_modifiers);
+ g_free (xievent_mask.mask);
+ result = (status == XIGrabSuccess);
+ }
+ else
+#endif
+ {
+ status = XGrabButton (display, button, modifiers, grab_window,
+ owner_events, event_mask, grab_mode, paired_device_mode,
+ confine_to, cursor);
+ result = (status == GrabSuccess);
+ }
+ return result;
+}
+
+void
+xfwm_device_ungrab_button (XfwmDevices *devices, Display *display,
+ guint button, guint modifiers, Window grab_window)
+{
+#ifdef HAVE_XI2
+ XIGrabModifiers xi2_modifiers;
+#endif
+
+#ifdef HAVE_XI2
+ if (devices->xi2_available)
+ {
+ xi2_modifiers.modifiers = xi2_modifier_mask (modifiers);
+ xi2_modifiers.status = 0;
+
+ XIUngrabButton (display, devices->pointer.xi2_device, button,
+ grab_window, 1, &xi2_modifiers);
+ }
+ else
+#endif
+ {
+ XUngrabButton (display, button, modifiers, grab_window);
+ }
+}
+
+gboolean
+xfwm_device_grab_keycode (XfwmDevices *devices, Display *display,
+ gint keycode, guint modifiers, Window grab_window,
+ gboolean owner_events, guint event_mask,
+ gint grab_mode, gint paired_device_mode)
+{
+ gboolean result;
+ Status status;
+#ifdef HAVE_XI2
+ XIGrabModifiers xi2_modifiers;
+ XIEventMask xievent_mask;
+#endif
+
+#ifdef HAVE_XI2
+ if (devices->xi2_available)
+ {
+ xi2_modifiers.modifiers = xi2_modifier_mask (modifiers);
+ xi2_modifiers.status = 0;
+
+ xfwm_device_fill_xi2_event_mask (&xievent_mask, event_mask);
+ status = XIGrabKeycode (display, devices->keyboard.xi2_device, keycode, grab_window,
+ grab_mode, paired_device_mode, owner_events,
+ &xievent_mask, 1, &xi2_modifiers);
+ g_free (xievent_mask.mask);
+ result = (status == XIGrabSuccess);
+ }
+ else
+#endif
+ {
+ status = XGrabKey (display, keycode, modifiers, grab_window,
+ owner_events, grab_mode, paired_device_mode);
+ result = (status == GrabSuccess);
+ }
+ return result;
+}
+
+void
+xfwm_device_ungrab_keycode (XfwmDevices *devices, Display *display,
+ gint keycode, guint modifiers, Window grab_window)
+{
+#ifdef HAVE_XI2
+ XIGrabModifiers xi2_modifiers;
+#endif
+
+#ifdef HAVE_XI2
+ if (devices->xi2_available)
+ {
+ xi2_modifiers.modifiers = xi2_modifier_mask (modifiers);
+ xi2_modifiers.status = 0;
+
+ XIUngrabKeycode (display, devices->keyboard.xi2_device, keycode,
+ grab_window, 1, &xi2_modifiers);
+ }
+ else
+#endif
+ {
+ XUngrabKey (display, keycode, modifiers, grab_window);
+ }
+}
+
+#ifdef HAVE_XI2
+typedef struct
+{
+ XfwmDevices *devices;
+ XfwmEvent *event;
+ XIEventMask xievent_mask;
+} XI2CheckMaskContext;
+
+static gboolean
+xfwm_device_check_mask_event_xi2_predicate (Display *display, XEvent *xevent, XPointer user_data)
+{
+ XI2CheckMaskContext *context = (void *)user_data;
+
+ if (xevent->type == GenericEvent &&
+ xevent->xgeneric.extension == context->devices->xi2_opcode &&
+ XIMaskIsSet (context->xievent_mask.mask, xevent->xgeneric.evtype))
+ {
+ /* GDK holds XI2 event data which we are replacing so it should be released here */
+ XFreeEventData (display, &context->event->meta.x->xcookie);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
+gboolean
+xfwm_device_check_mask_event (XfwmDevices *devices, Display *display,
+ guint event_mask, XfwmEvent *event)
+{
+ gboolean result;
+#ifdef HAVE_XI2
+ XI2CheckMaskContext context;
+#endif
+
+#ifdef HAVE_XI2
+ if (devices->xi2_available && event->meta.device != None)
+ {
+ context.devices = devices;
+ context.event = event;
+ xfwm_device_fill_xi2_event_mask (&context.xievent_mask, event_mask);
+ result = XCheckIfEvent (display, event->meta.x,
+ xfwm_device_check_mask_event_xi2_predicate, (XPointer)&context);
+ g_free (context.xievent_mask.mask);
+
+ if (result)
+ {
+ /* Previos data was released in predicate, allocate a new data for the new event */
+ XGetEventData (display, &event->meta.x->xcookie);
+ }
+ }
+ else
+#endif
+ {
+ result = XCheckMaskEvent (display, event_mask, event->meta.x);
+ }
+
+ if (result)
+ {
+ xfwm_device_translate_event (devices, event->meta.x, event);
+ }
+
+ return result;
+}
+
+XfwmDevices *
+xfwm_devices_new (GdkDisplay *display)
+{
+ XfwmDevices *devices;
+#ifdef HAVE_XI2
+ GdkSeat *seat;
+ GdkDevice *pointer_device;
+ GdkDevice *keyboard_device;
+ gint firstevent, firsterror;
+#endif
+
+ devices = g_new0 (XfwmDevices, 1);
+ devices->xi2_available = FALSE;
+ devices->xi2_opcode = 0;
+
+ devices->pointer.keyboard = FALSE;
+ devices->pointer.xi2_device = None;
+
+ devices->keyboard.keyboard = TRUE;
+ devices->keyboard.xi2_device = None;
+
+#ifdef HAVE_XI2
+ seat = gdk_display_get_default_seat (display);
+ pointer_device = gdk_seat_get_pointer (seat);
+ keyboard_device = gdk_seat_get_keyboard (seat);
+
+ if (GDK_IS_X11_DEVICE_XI2 (pointer_device) || GDK_IS_X11_DEVICE_XI2 (keyboard_device))
+ {
+ /* GDK uses XI2, let's use it too */
+
+ /* Obtain XI2 opcode */
+ if (XQueryExtension (gdk_x11_display_get_xdisplay (display), "XInputExtension",
+ &devices->xi2_opcode, &firstevent, &firsterror))
+ {
+ devices->xi2_available = TRUE;
+ devices->pointer.xi2_device = gdk_x11_device_get_id (pointer_device);
+ devices->keyboard.xi2_device = gdk_x11_device_get_id (keyboard_device);
+ }
+ }
+#endif
+
+ return devices;
+}
diff --git a/src/device.h b/src/device.h
new file mode 100644
index 000000000..7cebdd3e2
--- /dev/null
+++ b/src/device.h
@@ -0,0 +1,186 @@
+/* $Id$
+
+ 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, 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., Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+
+ device.h - (c) 2017 Viktor Odintsev
+
+ */
+
+#ifndef INC_DEVICE_H
+#define INC_DEVICE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/Xlib.h>
+#include <gdk/gdk.h>
+
+typedef enum
+{
+ XFWM_EVENT_X,
+ XFWM_EVENT_KEY,
+ XFWM_EVENT_BUTTON,
+ XFWM_EVENT_MOTION,
+ XFWM_EVENT_CROSSING
+} XfwmEventType;
+
+typedef struct
+{
+ XfwmEventType type;
+ Window window;
+ gint device;
+ XEvent *x;
+} XfwmEventMeta;
+
+typedef struct
+{
+ XfwmEventMeta meta;
+
+ Window root;
+ gboolean pressed;
+ guint keycode;
+ guint state;
+ Time time;
+} XfwmEventKey;
+
+typedef struct
+{
+ XfwmEventMeta meta;
+
+ Window root;
+ Window subwindow;
+ gboolean pressed;
+ guint button;
+ guint state;
+ gint x;
+ gint y;
+ gint x_root;
+ gint y_root;
+ Time time;
+} XfwmEventButton;
+
+typedef struct
+{
+ XfwmEventMeta meta;
+
+ gint x;
+ gint y;
+ gint x_root;
+ gint y_root;
+ Time time;
+} XfwmEventMotion;
+
+typedef struct
+{
+ XfwmEventMeta meta;
+
+ Window root;
+ gboolean enter;
+ gint mode;
+ gint detail;
+ gint x_root;
+ gint y_root;
+ Time time;
+} XfwmEventCrossing;
+
+typedef union
+{
+ XfwmEventMeta meta;
+ XfwmEventKey key;
+ XfwmEventButton button;
+ XfwmEventMotion motion;
+ XfwmEventCrossing crossing;
+} XfwmEvent;
+
+typedef struct
+{
+ gboolean keyboard;
+ gint xi2_device;
+} XfwmDevice;
+
+typedef struct {
+ XfwmDevice pointer;
+ XfwmDevice keyboard;
+
+ gboolean xi2_available;
+ gint xi2_opcode;
+} XfwmDevices;
+
+XfwmEvent *xfwm_device_translate_event (XfwmDevices *,
+ XEvent *,
+ XfwmEvent *);
+void xfwm_device_free_event (XfwmEvent *);
+void xfwm_device_button_update_window (XfwmEventButton *,
+ Window);
+#ifdef HAVE_XI2
+void xfwm_device_configure_xi2_event_mask (XfwmDevices *,
+ Display *,
+ Window,
+ gulong);
+#endif
+gboolean xfwm_device_grab (XfwmDevices *,
+ XfwmDevice *,
+ Display *,
+ Window,
+ gboolean,
+ guint,
+ gint,
+ Window,
+ Cursor,
+ Time);
+void xfwm_device_ungrab (XfwmDevices *,
+ XfwmDevice *,
+ Display *,
+ Time);
+gboolean xfwm_device_grab_button (XfwmDevices *,
+ Display *,
+ guint,
+ guint,
+ Window,
+ gboolean,
+ guint,
+ gint,
+ gint,
+ Window,
+ Cursor);
+void xfwm_device_ungrab_button (XfwmDevices *,
+ Display *,
+ guint,
+ guint,
+ Window);
+gboolean xfwm_device_grab_keycode (XfwmDevices *,
+ Display *,
+ gint,
+ guint,
+ Window,
+ gboolean,
+ guint,
+ gint,
+ gint);
+void xfwm_device_ungrab_keycode (XfwmDevices *,
+ Display *,
+ gint,
+ guint,
+ Window);
+gboolean xfwm_device_check_mask_event (XfwmDevices *,
+ Display *,
+ guint,
+ XfwmEvent *);
+XfwmDevices *xfwm_devices_new (GdkDisplay *);
+
+#endif /* INC_DEVICE_H */
diff --git a/src/display.c b/src/display.c
index e3ddcd915..29a932d84 100644
--- a/src/display.c
+++ b/src/display.c
@@ -231,6 +231,8 @@ myDisplayInit (GdkDisplay *gdisplay)
g_warning ("Some internal atoms were not properly created.");
}
+ display->devices = xfwm_devices_new (gdisplay);
+
/* Test XShape extension support */
major = 0;
minor = 0;
@@ -368,6 +370,9 @@ myDisplayClose (DisplayInfo *display)
g_slist_free (display->screens);
display->screens = NULL;
+ g_free (display->devices);
+ display->devices = NULL;
+
return display;
}
diff --git a/src/display.h b/src/display.h
index 0babd34b5..882b2b37d 100644
--- a/src/display.h
+++ b/src/display.h
@@ -299,6 +299,7 @@ struct _DisplayInfo
Atom atoms[ATOM_COUNT];
eventFilterSetup *xfilter;
+ XfwmDevices *devices;
GSList *screens;
GSList *clients;
diff --git a/src/event_filter.c b/src/event_filter.c
index c0f5edd36..c1340c3c2 100644
--- a/src/event_filter.c
+++ b/src/event_filter.c
@@ -200,7 +200,7 @@ eventFilterPop (eventFilterSetup *setup)
}
GdkWindow *
-eventFilterAddWin (GdkScreen *gscr, long event_mask)
+eventFilterAddWin (GdkScreen *gscr, XfwmDevices *devices, long event_mask)
{
XWindowAttributes attribs;
Display *dpy;
@@ -220,6 +220,9 @@ eventFilterAddWin (GdkScreen *gscr, long event_mask)
XGetWindowAttributes (dpy, xroot, &attribs);
XSelectInput (dpy, xroot, attribs.your_event_mask | event_mask);
+#ifdef HAVE_XI2
+ xfwm_device_configure_xi2_event_mask (devices, dpy, xroot, attribs.your_event_mask | event_mask);
+#endif
gdk_x11_ungrab_server ();
gdk_flush ();
@@ -235,12 +238,13 @@ eventFilterAddWin (GdkScreen *gscr, long event_mask)
}
eventFilterSetup *
-eventFilterInit (gpointer data)
+eventFilterInit (XfwmDevices *devices, gpointer data)
{
eventFilterSetup *setup;
setup = g_new0 (eventFilterSetup, 1);
setup->filterstack = NULL;
+ setup->devices = devices;
eventFilterPush (setup, default_event_filter, data);
gdk_window_add_filter (NULL, eventXfwmFilter, (gpointer) setup);
diff --git a/src/event_filter.h b/src/event_filter.h
index 953775e72..8ee215332 100644
--- a/src/event_filter.h
+++ b/src/event_filter.h
@@ -31,6 +31,8 @@
#include <gdk/gdk.h>
#include <X11/Xlib.h>
+#include "device.h"
+
/* this formatting is needed by glib-mkenums */
typedef enum {
EVENT_FILTER_STOP = 0x0,
@@ -53,16 +55,19 @@ eventFilterStack;
typedef struct eventFilterSetup
{
eventFilterStack *filterstack;
+ XfwmDevices *devices;
}
eventFilterSetup;
GdkWindow *eventFilterAddWin (GdkScreen *,
+ XfwmDevices *,
long);
eventFilterStack *eventFilterPush (eventFilterSetup *,
XfwmFilter,
gpointer );
eventFilterStack *eventFilterPop (eventFilterSetup *);
-eventFilterSetup *eventFilterInit (gpointer);
+eventFilterSetup *eventFilterInit (XfwmDevices *,
+ gpointer);
void eventFilterClose (eventFilterSetup *);
#endif /* INC_EVENT_FILTER_H */
diff --git a/src/main.c b/src/main.c
index 8546fa72d..28136e155 100644
--- a/src/main.c
+++ b/src/main.c
@@ -615,7 +615,7 @@ initialize (gint compositor_mode, gboolean replace_wm)
{
return -1;
}
- display_info->xfilter = eventFilterInit ((gpointer) display_info);
+ display_info->xfilter = eventFilterInit (display_info->devices, (gpointer) display_info);
eventFilterPush (display_info->xfilter, xfwm4_event_filter, (gpointer) display_info);
initPerDisplayCallbacks (display_info);
@@ -673,6 +673,11 @@ main (int argc, char **argv)
xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
+#ifndef HAVE_XI2
+ /* Disable XI2 in GDK */
+ gdk_disable_multidevice ();
+#endif
+
context = g_option_context_new (_("[ARGUMENTS...]"));
g_option_context_add_main_entries (context, option_entries, GETTEXT_PACKAGE);
g_option_context_add_group (context, gtk_get_option_group (FALSE));
diff --git a/src/mywindow.c b/src/mywindow.c
index b829a5e40..819e4c57b 100644
--- a/src/mywindow.c
+++ b/src/mywindow.c
@@ -124,6 +124,11 @@ xfwmWindowCreate (ScreenInfo * screen_info, Visual *visual, gint depth, Window p
#ifdef HAVE_RENDER
win->pict_format = XRenderFindVisualFormat (myScreenGetXDisplay (screen_info), win->visual);
#endif
+#ifdef HAVE_XI2
+ xfwm_device_configure_xi2_event_mask (screen_info->display_info->devices,
+ screen_info->display_info->dpy,
+ win->window, eventmask);
+#endif
}
void
@@ -266,6 +271,11 @@ xfwmWindowTemp (ScreenInfo *screen_info, Visual *visual,
win->width = width;
win->height = height;
xfwmWindowSetVisual (win, visual, depth);
+#ifdef HAVE_XI2
+ xfwm_device_configure_xi2_event_mask (screen_info->display_info->devices,
+ screen_info->display_info->dpy,
+ win->window, eventmask);
+#endif
}
#ifdef HAVE_RENDER
diff --git a/src/screen.c b/src/screen.c
index 02ce61d8b..3e8695a16 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -219,7 +219,7 @@ myScreenInit (DisplayInfo *display_info, GdkScreen *gscr, unsigned long event_ma
return NULL;
}
- event_win = eventFilterAddWin (gscr, event_mask);
+ event_win = eventFilterAddWin (gscr, display_info->devices, event_mask);
if (!event_win)
{
gtk_widget_destroy (screen_info->gtk_win);