[PATCH libXi] Implement support for XI 2.2

Peter Hutterer peter.hutterer at who-t.net
Sun Dec 18 16:04:16 PST 2011


Adds support for the new TouchClass for multitouch-capable servers/devices.

New events:
  XITouchOwnershipEvent

New event types handled:
  XITouchBegin, XITouchUpdate, XITouchEnd
  XIRawTouchBegin, XIRawTouchUpdate, XIRawTouchEnd

New functions:
  XIGrabTouchBegin ... passive grabs on touches
  XIUngrabTouchBegin
  XIAllowTouchEvents ... Allow/reject touch event sequences

New XIQueryDevice classes:
  XITouchClassInfo

Requires libX11 1.5 for GetReqSized

Co-authored by: Chase Douglas <chase.douglas at canonical.com>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 configure.ac                     |    2 +-
 include/X11/extensions/XInput2.h |   51 +++++++++++++++++++++
 man/XIGrabButton.txt             |   60 ++++++++++++++++---------
 man/XIQueryDevice.txt            |   30 ++++++++++++-
 src/XExtInt.c                    |   91 +++++++++++++++++++++++++++++++++++++-
 src/XIAllowEvents.c              |   46 ++++++++++++++++++-
 src/XIPassiveGrab.c              |   33 ++++++++++++++
 src/XIint.h                      |    1 +
 8 files changed, 286 insertions(+), 28 deletions(-)

diff --git a/configure.ac b/configure.ac
index c6565a8..0a7bdfa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,7 +28,7 @@ XORG_WITH_ASCIIDOC(8.4.5)
 XORG_CHECK_MALLOC_ZERO
 
 # Obtain compiler/linker options for depedencies
-PKG_CHECK_MODULES(XI, [xproto >= 7.0.13] [x11 >= 1.2.99.1] [xextproto >= 7.0.3] [xext >= 1.0.99.1] [inputproto >= 2.0.99.1])
+PKG_CHECK_MODULES(XI, [xproto >= 7.0.13] [x11 >= 1.4.99.1] [xextproto >= 7.0.3] [xext >= 1.0.99.1] [inputproto >= 2.1.99.3])
 
 # Check for xmlto and asciidoc for man page conversion
 # (only needed by people building tarballs)
diff --git a/include/X11/extensions/XInput2.h b/include/X11/extensions/XInput2.h
index 910b25f..26de695 100644
--- a/include/X11/extensions/XInput2.h
+++ b/include/X11/extensions/XInput2.h
@@ -146,6 +146,14 @@ typedef struct
 
 typedef struct
 {
+    int         type;
+    int         sourceid;
+    int         mode;
+    int         num_touches;
+} XITouchClassInfo;
+
+typedef struct
+{
     int                 deviceid;
     char                *name;
     int                 use;
@@ -303,6 +311,23 @@ typedef struct {
     int           what;
 } XIPropertyEvent;
 
+typedef struct {
+    int           type;         /* GenericEvent */
+    unsigned long serial;       /* # of last request processed by server */
+    Bool          send_event;   /* true if this came from a SendEvent request */
+    Display       *display;     /* Display the event was read from */
+    int           extension;    /* XI extension offset */
+    int           evtype;
+    Time          time;
+    int           deviceid;
+    int           sourceid;
+    unsigned int  touchid;
+    Window        root;
+    Window        event;
+    Window        child;
+    int           flags;
+} XITouchOwnershipEvent;
+
 _XFUNCPROTOBEGIN
 
 extern Bool     XIQueryPointer(
@@ -426,6 +451,14 @@ extern Status XIAllowEvents(
     Time                time
 );
 
+extern Status XIAllowTouchEvents(
+    Display*            display,
+    int                 deviceid,
+    unsigned int        touchid,
+    Window              grab_window,
+    int                 event_mode
+);
+
 extern int XIGrabButton(
     Display*            display,
     int                 deviceid,
@@ -477,6 +510,17 @@ extern int XIGrabFocusIn(
     int                 num_modifiers,
     XIGrabModifiers     *modifiers_inout
 );
+
+extern int XIGrabTouchBegin(
+    Display*            display,
+    int                 deviceid,
+    Window              grab_window,
+    int                 owner_events,
+    XIEventMask         *mask,
+    int                 num_modifiers,
+    XIGrabModifiers     *modifiers_inout
+);
+
 extern Status XIUngrabButton(
     Display*            display,
     int                 deviceid,
@@ -511,6 +555,13 @@ extern Status XIUngrabFocusIn(
     XIGrabModifiers     *modifiers
 );
 
+extern Status XIUngrabTouchBegin(
+    Display*            display,
+    int                 deviceid,
+    Window              grab_window,
+    int                 num_modifiers,
+    XIGrabModifiers     *modifiers
+);
 
 extern Atom *XIListProperties(
     Display*            display,
diff --git a/man/XIGrabButton.txt b/man/XIGrabButton.txt
index 45ac25e..a046ac7 100644
--- a/man/XIGrabButton.txt
+++ b/man/XIGrabButton.txt
@@ -49,6 +49,20 @@ SYNOPSIS
                         int num_modifiers,
                         XIGrabModifiers *modifiers);
 
+   int XIGrabTouchBegin( Display *display,
+                         int deviceid,
+                         Window grab_window,
+                         Bool owner_events,
+                         XIEventMask *mask,
+                         int num_modifiers,
+                         XIGrabModifiers *modifiers_inout);
+
+   int XIUngrabTouchBegin( Display *display,
+                           int deviceid,
+                           Window grab_window,
+                           int num_modifiers,
+                           XIGrabModifiers *modifiers);
+
    display
           Specifies the connection to the X server.
 
@@ -101,8 +115,8 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-   XIGrabButton and XIGrabKeycode establishes a passive grab. The
-   modifier device for a button grab is the paired master device
+   XIGrabButton, XIGrabKeycode and XIGrabTouchBegin establish a passive
+   grab. The modifier device for a button grab is the paired master device
    if deviceid specifies a master pointer. Otherwise, the modifier
    device is the device specified with deviceid. In the future,
    the device is actively grabbed (as for XIGrabDevice, the
@@ -110,9 +124,9 @@ DESCRIPTION
    was pressed and the XI_ButtonPress or XI_KeyPress event is
    reported if all of the following conditions are true:
      * The device is not grabbed, and the specified button or
-       keycode is logically pressed when the specified modifier
-       keys are logically down on the modifier device and no other
-       buttons or modifier keys are logically down.
+       keycode is logically pressed or a touch event occurs when the
+       specified modifier keys are logically down on the modifier device
+       and no other buttons or modifier keys are logically down.
      * Either the grab window is an ancestor of (or is) the focus
        window, OR the grab window is a descendent of the focus
        window and contains the device.
@@ -156,35 +170,36 @@ DESCRIPTION
    combination. XIGrabButton and XIGrabKeycode have no effect on an
    active grab.
 
-   On success, XIGrabButton and XIGrabKeycode return 0;
+   On success, XIGrabButton, XIGrabKeycode and XIGrabTouchBegin return 0;
    If one or more modifier combinations could not be grabbed,
-   XIGrabButton and XIGrabKeycode return the number of failed
-   combinations and modifiers_inout contains the failed combinations
+   XIGrabButton, XIGrabKeycode and XIGrabTouchBegin return the number of
+   failed combinations and modifiers_inout contains the failed combinations
    and their respective error codes.
 
-   XIGrabButton and XIGrabKeycode can generate BadClass, BadDevice,
-   BadMatch, BadValue, and BadWindow errors.
+   XIGrabButton, XIGrabKeycode and XIGrabTouchBegin can generate BadClass,
+   BadDevice, BadMatch, BadValue, and BadWindow errors.
 
-   XIUngrabButton and XIUngrabKeycode releases the passive grab for
-   a button/modifier or keycode/modifier combination on the
-   specified window if it was grabbed by this client. A modifier
-   of XIAnyModifier is equivalent to issuing the ungrab request
+   XIUngrabButton, XIUngrabKeycode and XIUngrabTouchBegin release the
+   passive grab for a button/modifier, keycode/modifier or touch/modifier
+   combination on the specified window if it was grabbed by this client. A
+   modifier of XIAnyModifier is equivalent to issuing the ungrab request
    for all possible modifier combinations, including the
    combination of no modifiers. A button of XIAnyButton is
    equivalent to issuing the request for all possible buttons.
    XIUngrabButton and XIUngrabKeycode have no effect on an active
    grab.
 
-   XIUngrabButton and XIUngrabKeycode can generate BadDevice,
-   BadMatch, BadValue and BadWindow errors.
+   XIUngrabButton, XIUngrabKeycode and XIUngrabTouchBegin can generate
+   BadDevice, BadMatch, BadValue and BadWindow errors.
 
 RETURN VALUE
 ------------
-   XIGrabButton and XIGrabKeycode return the number of modifier combination
-   that could not establish a passive grab. The modifiers are returned in
-   modifiers_inout, along with the respective error for this modifier
-   combination. If XIGrabButton or XIGrabKeycode return zero, passive grabs
-   with all requested modifier combinations were established successfully.
+   XIGrabButton, XIGrabKeycode and XIGrabTouchBegin return the number of
+   modifier combination that could not establish a passive grab. The
+   modifiers are returned in modifiers_inout, along with the respective
+   error for this modifier combination. If XIGrabButton, XIGrabKeycode
+   or XIGrabTouchBegin return zero, passive grabs with all requested
+   modifier combinations were established successfully.
 
 DIAGNOSTICS
 -----------
@@ -195,7 +210,8 @@ DIAGNOSTICS
    BadMatch
           This error may occur if XIGrabButton specified a device
           that has no buttons, or XIGrabKeycode specified a device
-          that has no keys.
+          that has no keys, or XIGrabTouchBegin specified a device
+          that is not touch-capable.
 
    BadValue
           Some numeric value falls outside the range of values
diff --git a/man/XIQueryDevice.txt b/man/XIQueryDevice.txt
index 6b5a622..e5e8251 100644
--- a/man/XIQueryDevice.txt
+++ b/man/XIQueryDevice.txt
@@ -100,7 +100,8 @@ DESCRIPTION
 
    The type field specifies the type of the input class.
    Currently, the following types are defined:
-       XIKeyClass, XIButtonClass, XIValuatorClass, XIScrollClass
+       XIKeyClass, XIButtonClass, XIValuatorClass, XIScrollClass,
+       XITouchClass
 
    In the future, additional types may be added. Clients are
    required to ignore unknown input classes.
@@ -231,6 +232,33 @@ DESCRIPTION
    the emulation of XI_Motion events when the driver submits
    legacy scroll button events.
 
+               typedef struct
+               {
+                   int         type;
+                   int         sourceid;
+                   int         mode;
+                   int         num_touches;
+               } XITouchClassInfo;
+
+   A device may have zero or one XITouchClassInfo, denoting
+   multi-touch capability on the device. A device with a XITouchClassInfo
+   may send TouchBegin, TouchUpdate, TouchEnd and TouchOwnership events.
+
+   The mode field is either XIDirectTouch for direct-input touch devices
+   such as touchscreens or XIDependentTouch for indirect input devices such
+   as touchpads. For XIDirectTouch devices, touch events are sent to window
+   at the position the touch occured. For XIDependentTouch devices, touch
+   events are sent to the window at the position of the device's sprite.
+
+   The num_touches field defines the maximum number of simultaneous touches
+   the device supports. A num_touches of 0 means the maximum number of
+   simultaneous touches is undefined or unspecified. This field should be
+   used as a guide only, devices will lie about their capabilities.
+
+   A device with an XITouchClassInfo may still send pointer events. The
+   valuators must be defined with the respective XIValuatorClass
+   classes. A valuator may send both pointer and touch-events.
+
    XIQueryDevice can generate a BadDevice error.
 
    XIFreeDeviceInfo frees the information returned by
diff --git a/src/XExtInt.c b/src/XExtInt.c
index 29ecfa3..b12886d 100644
--- a/src/XExtInt.c
+++ b/src/XExtInt.c
@@ -150,6 +150,9 @@ static int
 wireToEnterLeave(xXIEnterEvent *in, XGenericEventCookie *cookie);
 static int
 wireToPropertyEvent(xXIPropertyEvent *in, XGenericEventCookie *cookie);
+static int
+wireToTouchOwnershipEvent(xXITouchOwnershipEvent *in,
+                          XGenericEventCookie *cookie);
 
 static /* const */ XEvent emptyevent;
 
@@ -275,7 +278,8 @@ static XExtensionVersion versions[] = { {XI_Absent, 0, 0},
 {XI_Present, XI_Add_DeviceProperties_Major,
  XI_Add_DeviceProperties_Minor},
 {XI_Present, 2, 0},
-{XI_Present, 2, 1}
+{XI_Present, 2, 1},
+{XI_Present, 2, 2}
 };
 
 /***********************************************************************
@@ -928,6 +932,9 @@ XInputWireToCookie(
         case XI_ButtonRelease:
         case XI_KeyPress:
         case XI_KeyRelease:
+        case XI_TouchBegin:
+        case XI_TouchUpdate:
+        case XI_TouchEnd:
             *cookie = *(XGenericEventCookie*)save;
             if (!wireToDeviceEvent((xXIDeviceEvent*)event, cookie))
             {
@@ -954,12 +961,25 @@ XInputWireToCookie(
                 break;
             }
             return ENQUEUE_EVENT;
+        case XI_TouchOwnership:
+            *cookie = *(XGenericEventCookie*)save;
+            if (!wireToTouchOwnershipEvent((xXITouchOwnershipEvent*)event,
+                                           cookie))
+            {
+                printf("XInputWireToCookie: CONVERSION FAILURE!  evtype=%d\n",
+                        ge->evtype);
+                break;
+            }
+            return ENQUEUE_EVENT;
 
         case XI_RawKeyPress:
         case XI_RawKeyRelease:
         case XI_RawButtonPress:
         case XI_RawButtonRelease:
         case XI_RawMotion:
+        case XI_RawTouchBegin:
+        case XI_RawTouchUpdate:
+        case XI_RawTouchEnd:
             *cookie = *(XGenericEventCookie*)save;
             if (!wireToRawEvent((xXIRawEvent*)event, cookie))
             {
@@ -1046,6 +1066,9 @@ sizeDeviceClassType(int type, int num_elements)
         case XIScrollClass:
             l = sizeof(XIScrollClassInfo);
             break;
+        case XITouchClass:
+            l = sizeof(XITouchClassInfo);
+            break;
         default:
             printf("sizeDeviceClassType: unknown type %d\n", type);
             break;
@@ -1264,6 +1287,22 @@ copyPropertyEvent(XGenericEventCookie *cookie_in,
 }
 
 static Bool
+copyTouchOwnershipEvent(XGenericEventCookie *cookie_in,
+                        XGenericEventCookie *cookie_out)
+{
+    XITouchOwnershipEvent *in, *out;
+
+    in = cookie_in->data;
+
+    out = cookie_out->data = malloc(sizeof(XITouchOwnershipEvent));
+    if (!out)
+        return False;
+
+    *out = *in;
+    return True;
+}
+
+static Bool
 copyRawEvent(XGenericEventCookie *cookie_in,
              XGenericEventCookie *cookie_out)
 {
@@ -1322,6 +1361,9 @@ XInputCopyCookie(Display *dpy, XGenericEventCookie *in, XGenericEventCookie *out
         case XI_ButtonRelease:
         case XI_KeyPress:
         case XI_KeyRelease:
+        case XI_TouchBegin:
+        case XI_TouchUpdate:
+        case XI_TouchEnd:
             ret = copyDeviceEvent(in, out);
             break;
         case XI_DeviceChanged:
@@ -1339,6 +1381,9 @@ XInputCopyCookie(Display *dpy, XGenericEventCookie *in, XGenericEventCookie *out
         case XI_PropertyEvent:
             ret = copyPropertyEvent(in, out);
             break;
+        case XI_TouchOwnership:
+            ret = copyTouchOwnershipEvent(in, out);
+            break;
         case XI_RawKeyPress:
         case XI_RawKeyRelease:
         case XI_RawButtonPress:
@@ -1455,6 +1500,9 @@ size_classes(xXIAnyInfo* from, int nclasses)
             case XIScrollClass:
                 l = sizeDeviceClassType(XIScrollClass, 0);
                 break;
+            case XITouchClass:
+                l = sizeDeviceClassType(XITouchClass, 0);
+                break;
         }
 
         len += l;
@@ -1586,6 +1634,22 @@ copy_classes(XIDeviceInfo* to, xXIAnyInfo* from, int *nclasses)
                     to->classes[cls_idx++] = any_lib;
                 }
                 break;
+            case XITouchClass:
+                {
+                    XITouchClassInfo *cls_lib;
+                    xXITouchInfo *cls_wire;
+
+                    cls_wire = (xXITouchInfo*)any_wire;
+                    cls_lib = next_block(&ptr_lib, sizeof(XITouchClassInfo));
+
+                    cls_lib->type = cls_wire->type;
+                    cls_lib->sourceid = cls_wire->sourceid;
+                    cls_lib->mode = cls_wire->mode;
+                    cls_lib->num_touches = cls_wire->num_touches;
+
+                    to->classes[cls_idx++] = any_lib;
+                }
+                break;
         }
         len += any_wire->length * 4;
         ptr_wire += any_wire->length * 4;
@@ -1780,3 +1844,28 @@ wireToPropertyEvent(xXIPropertyEvent *in, XGenericEventCookie *cookie)
 
     return 1;
 }
+
+static int
+wireToTouchOwnershipEvent(xXITouchOwnershipEvent *in,
+                          XGenericEventCookie *cookie)
+{
+    XITouchOwnershipEvent *out = malloc(sizeof(XITouchOwnershipEvent));
+
+    cookie->data = out;
+
+    out->type           = in->type;
+    out->display        = cookie->display;
+    out->extension      = in->extension;
+    out->evtype         = in->evtype;
+    out->send_event     = ((in->type & 0x80) != 0);
+    out->time           = in->time;
+    out->deviceid       = in->deviceid;
+    out->sourceid       = in->sourceid;
+    out->touchid        = in->touchid;
+    out->root           = in->root;
+    out->event          = in->event;
+    out->child          = in->child;
+    out->flags          = in->flags;
+
+    return 1;
+}
diff --git a/src/XIAllowEvents.c b/src/XIAllowEvents.c
index d4da6d0..d987549 100644
--- a/src/XIAllowEvents.c
+++ b/src/XIAllowEvents.c
@@ -33,9 +33,12 @@
 #include <X11/extensions/extutil.h>
 #include "XIint.h"
 
-Status
-XIAllowEvents(Display *dpy, int deviceid, int event_mode, Time time)
+static Status
+_XIAllowEvents(Display *dpy, int deviceid, int event_mode, Time time,
+                    unsigned int touchid, Window grab_window)
 {
+    Bool have_XI22 = True;
+    int req_len = sz_xXIAllowEventsReq; /* in bytes */
     xXIAllowEventsReq *req;
 
     XExtDisplayInfo *extinfo = XInput_find_display(dpy);
@@ -44,14 +47,51 @@ XIAllowEvents(Display *dpy, int deviceid, int event_mode, Time time)
     if (_XiCheckExtInit(dpy, XInput_2_0, extinfo) == -1)
 	return (NoSuchExtension);
 
-    GetReq(XIAllowEvents, req);
+    /* 2.2's XIAllowEvents is 8 bytes longer than 2.0 */
+    if (_XiCheckExtInit(dpy, XInput_2_2, extinfo) == -1) {
+        req_len -= 8;
+        have_XI22 = False;
+    }
+
+    GetReqSized(XIAllowEvents, req_len, req);
+
     req->reqType = extinfo->codes->major_opcode;
     req->ReqType = X_XIAllowEvents;
     req->deviceid = deviceid;
     req->mode = event_mode;
     req->time = time;
 
+    if (have_XI22) {
+        req->touchid = touchid;
+        req->grab_window = grab_window;
+    }
+
     UnlockDisplay(dpy);
     SyncHandle();
     return Success;
 }
+
+Status
+XIAllowEvents(Display *dpy, int deviceid, int event_mode, Time time)
+{
+    return _XIAllowEvents(dpy, deviceid, event_mode, time, 0, None);
+}
+
+Status
+XIAllowTouchEvents(Display *dpy, int deviceid, unsigned int touchid,
+                   Window grab_window, int event_mode)
+{
+    int status;
+    XExtDisplayInfo *extinfo = XInput_find_display(dpy);
+
+    LockDisplay(dpy);
+    if (_XiCheckExtInit(dpy, XInput_2_2, extinfo) == -1)
+	return (NoSuchExtension);
+
+    status = _XIAllowEvents(dpy, deviceid, event_mode, CurrentTime, touchid, grab_window);
+
+    UnlockDisplay(dpy);
+    SyncHandle();
+
+    return status;
+}
diff --git a/src/XIPassiveGrab.c b/src/XIPassiveGrab.c
index 7625521..f8eafed 100644
--- a/src/XIPassiveGrab.c
+++ b/src/XIPassiveGrab.c
@@ -148,6 +148,25 @@ XIGrabFocusIn(Display *dpy, int deviceid, Window grab_window, int grab_mode,
                                 modifiers_inout);
 }
 
+int
+XIGrabTouchBegin(Display *dpy, int deviceid, Window grab_window,
+                 Bool owner_events, XIEventMask *mask,
+                 int num_modifiers, XIGrabModifiers *modifiers_inout)
+{
+    XExtDisplayInfo *extinfo = XInput_find_display(dpy);
+
+    LockDisplay(dpy);
+    if (_XiCheckExtInit(dpy, XInput_2_2, extinfo) == -1)
+	return -1;
+
+    /* FIXME: allow selection of GrabMode for paired devices? */
+    return _XIPassiveGrabDevice(dpy, deviceid, XIGrabtypeTouchBegin, 0,
+                                grab_window, None, GrabModeAsync,
+                                GrabModeAsync, owner_events, mask,
+                                num_modifiers, modifiers_inout);
+}
+
+
 static int
 _XIPassiveUngrabDevice(Display* dpy, int deviceid, int grabtype, int detail,
                        Window grab_window, int num_modifiers, XIGrabModifiers *modifiers)
@@ -211,3 +230,17 @@ XIUngrabFocusIn(Display* display, int deviceid, Window grab_window,
     return _XIPassiveUngrabDevice(display, deviceid, XIGrabtypeFocusIn, 0,
                                   grab_window, num_modifiers, modifiers);
 }
+
+int
+XIUngrabTouchBegin(Display* display, int deviceid, Window grab_window,
+                   int num_modifiers, XIGrabModifiers *modifiers)
+{
+    XExtDisplayInfo *extinfo = XInput_find_display(display);
+
+    LockDisplay(display);
+    if (_XiCheckExtInit(display, XInput_2_2, extinfo) == -1)
+	return -1;
+
+    return _XIPassiveUngrabDevice(display, deviceid, XIGrabtypeTouchBegin, 0,
+                                  grab_window, num_modifiers, modifiers);
+}
diff --git a/src/XIint.h b/src/XIint.h
index 41d99b3..cc46754 100644
--- a/src/XIint.h
+++ b/src/XIint.h
@@ -21,6 +21,7 @@
 #define XInput_2_0			7
 #endif
 #define XInput_2_1			8
+#define XInput_2_2			9
 
 extern XExtDisplayInfo *XInput_find_display(Display *);
 
-- 
1.7.7.1


More information about the xorg-devel mailing list