[Xfce4-commits] [xfce/xfwm4] 31/32: device: Implement XI2 event handling

noreply at xfce.org noreply at xfce.org
Tue Dec 5 09:22:17 CET 2017


This is an automated email from the git hooks/post-receive script.

o   l   i   v   i   e   r       p   u   s   h   e   d       a       c   o   m   m   i   t       t   o       b   r   a   n   c   h       m   a   s   t   e   r   
   in repository xfce/xfwm4.

commit 6013f1ee9b3831991db6a0fb896f20537532b6ce
Author: Viktor Odintsev <ninetls at xfce.org>
Date:   Mon Nov 27 16:30:50 2017 +0300

    device: Implement XI2 event handling
---
 configure.ac.in    |   9 +
 src/Makefile.am    |   2 +
 src/client.c       |   4 +
 src/device.c       | 627 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/device.h       | 186 ++++++++++++++++
 src/display.c      |   5 +
 src/display.h      |   1 +
 src/event_filter.c |   8 +-
 src/event_filter.h |   7 +-
 src/main.c         |   7 +-
 src/mywindow.c     |  10 +
 src/screen.c       |   2 +-
 12 files changed, 863 insertions(+), 5 deletions(-)

diff --git a/configure.ac.in b/configure.ac.in
index fb06b57..d31839d 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -91,6 +91,15 @@ AC_CHECK_LIB([Xext], [XShapeCombineShape],
     fi
   ], [], [$LIBX11_CFLAGS $LIBX11_LDFLAGS $LIBX11_LIBS])
 
+dnl Check for Xi library
+AC_CHECK_LIB([Xi], [XISelectEvents],
+  [
+    if ! echo $LIBX11_LIBS | grep -q -- '-lXi'; then
+      LIBX11_LIBS="$LIBX11_LIBS -lXi"
+      AC_DEFINE([HAVE_XI2], [1], [Define to enable XI2])
+    fi
+  ], [], [$LIBX11_CFLAGS $LIBX11_LDFLAGS $LIBX11_LIBS])
+
 XDT_CHECK_PACKAGE([GTK], [gtk+-3.0], [gtk_minimum_version])
 XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [xfce_minimum_version])
 XDT_CHECK_PACKAGE([LIBXFCE4UI], libxfce4ui-2, [libxfce4ui_minimum_version])
diff --git a/src/Makefile.am b/src/Makefile.am
index 8a6309e..af9dea4 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 db61862..735dcf5 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 0000000..b1e33ae
--- /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 0000000..7cebdd3
--- /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 e3ddcd9..29a932d 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 0babd34..882b2b3 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 c0f5edd..c1340c3 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 953775e..8ee2153 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 8546fa7..28136e1 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 b829a5e..819e4c5 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 02ce61d..3e8695a 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);

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list