From e73e2fe95dab3e0048b24d16327adbe54326ff3f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 14 Sep 2011 22:33:57 -0700 Subject: Implement support for XI 2.2 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 Signed-off-by: Peter Hutterer --- 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 @@ -144,6 +144,14 @@ typedef struct int flags; } XIScrollClassInfo; +typedef struct +{ + int type; + int sourceid; + int mode; + int num_touches; +} XITouchClassInfo; + typedef struct { int deviceid; @@ -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; @@ -1263,6 +1286,22 @@ copyPropertyEvent(XGenericEventCookie *cookie_in, return True; } +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 #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..ac17c01 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, XIGrabModeTouch, + 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 *); -- cgit v1.2.1