diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2009-12-09 13:59:57 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2010-02-22 13:19:13 +1000 |
commit | 299de21b2ab3cfa2078823215f84da67e7b3d1a3 (patch) | |
tree | 03b47b6d386c1a7baa56654e6dd658da26eb871b | |
parent | 4debc545611edd35f8fd35a52f4adf4263e49200 (diff) |
Initialize extension with the right number of events.
If the server supports a lower XI version than the client, the Xlib-internal
event vector may be smashed. See libXext for more details.
http://cgit.freedesktop.org/xorg/lib/libXext/commit/?id=83fdb27df4ddc2fb088ddf2ec65f0db6b7c57287
This patch queries the server for the supported XI extension before
registering the extension with Xlib. The number of events registered depends
on the server version.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Julien Cristau <jcristau@debian.org>
-rw-r--r-- | src/XExtInt.c | 68 | ||||
-rw-r--r-- | src/XGetVers.c | 24 | ||||
-rw-r--r-- | src/XIint.h | 1 |
3 files changed, 82 insertions, 11 deletions
diff --git a/src/XExtInt.c b/src/XExtInt.c index e87ead8..80b3fc7 100644 --- a/src/XExtInt.c +++ b/src/XExtInt.c @@ -173,6 +173,63 @@ static char *XInputErrorList[] = { "BadClass, invalid event class", /* BadClass */ }; +/* Get the version supported by the server to know which number of +* events are support. Otherwise, a wrong number of events may smash +* the Xlib-internal event processing vector. +* +* Since the extension hasn't been initialized yet, we need to +* manually get the opcode, then the version. +*/ +static int +_XiFindEventsSupported(Display *dpy) +{ + XExtCodes codes; + XExtensionVersion *extversion = NULL; + int nevents = 0; + + if (!XQueryExtension(dpy, INAME, &codes.major_opcode, + &codes.first_event, &codes.first_error)) + goto out; + + LockDisplay(dpy); + extversion = _XiGetExtensionVersionRequest(dpy, INAME, codes.major_opcode); + UnlockDisplay(dpy); + SyncHandle(); + + if (!extversion || !extversion->present) + goto out; + + if (extversion->major_version >= 2) + nevents = IEVENTS; /* number is fixed, XI2 adds GenericEvents only */ + else if (extversion->major_version <= 0) + { + printf("XInput_find_display: invalid extension version %d.%d\n", + extversion->major_version, extversion->minor_version); + goto out; + } + else + { + switch(extversion->minor_version) + { + case XI_Add_DeviceProperties_Minor: + nevents = XI_DevicePropertyNotify + 1; + break; + case XI_Add_DevicePresenceNotify_Minor: + nevents = XI_DevicePresenceNotify + 1; + break; + default: + nevents = XI_DeviceButtonstateNotify + 1; + break; + } + } + +out: + if (extversion) + XFree(extversion); + return nevents; +} + + _X_HIDDEN XExtDisplayInfo *XInput_find_display (Display *dpy) { @@ -180,12 +237,17 @@ XExtDisplayInfo *XInput_find_display (Display *dpy) if (!xinput_info) { if (!(xinput_info = XextCreateExtension())) return NULL; } if (!(dpyinfo = XextFindDisplay (xinput_info, dpy))) { + int nevents = _XiFindEventsSupported(dpy); + dpyinfo = XextAddDisplay (xinput_info, dpy, xinput_extension_name, &xinput_extension_hooks, - IEVENTS, NULL); - XESetWireToEventCookie(dpy, dpyinfo->codes->major_opcode, XInputWireToCookie); - XESetCopyEventCookie(dpy, dpyinfo->codes->major_opcode, XInputCopyCookie); + nevents, NULL); + if (dpyinfo->codes) /* NULL if XI doesn't exist on the server */ + { + XESetWireToEventCookie(dpy, dpyinfo->codes->major_opcode, XInputWireToCookie); + XESetCopyEventCookie(dpy, dpyinfo->codes->major_opcode, XInputCopyCookie); + } } return dpyinfo; } diff --git a/src/XGetVers.c b/src/XGetVers.c index 3b500ae..4718617 100644 --- a/src/XGetVers.c +++ b/src/XGetVers.c @@ -72,19 +72,15 @@ XGetExtensionVersion(register Display * dpy, _Xconst char *name) return (ext); } -_X_HIDDEN XExtensionVersion * -_XiGetExtensionVersion(register Display * dpy, _Xconst char *name, - XExtDisplayInfo *info) +_X_HIDDEN XExtensionVersion* +_XiGetExtensionVersionRequest(Display *dpy, _Xconst char *name, int xi_opcode) { xGetExtensionVersionReq *req; xGetExtensionVersionReply rep; XExtensionVersion *ext; - if (_XiCheckExtInit(dpy, Dont_Check, info) == -1) - return ((XExtensionVersion *) NoSuchExtension); - GetReq(GetExtensionVersion, req); - req->reqType = info->codes->major_opcode; + req->reqType = xi_opcode; req->ReqType = X_GetExtensionVersion; req->nbytes = strlen(name); req->length += (unsigned)(req->nbytes + 3) >> 2; @@ -93,6 +89,7 @@ _XiGetExtensionVersion(register Display * dpy, _Xconst char *name, if (!_XReply(dpy, (xReply *) & rep, 0, xTrue)) { return (XExtensionVersion *) NULL; } + ext = (XExtensionVersion *) Xmalloc(sizeof(XExtensionVersion)); if (ext) { ext->present = rep.present; @@ -101,5 +98,16 @@ _XiGetExtensionVersion(register Display * dpy, _Xconst char *name, ext->minor_version = rep.minor_version; } } - return (ext); + + return ext; +} + +_X_HIDDEN XExtensionVersion * +_XiGetExtensionVersion(register Display * dpy, _Xconst char *name, + XExtDisplayInfo *info) +{ + if (_XiCheckExtInit(dpy, Dont_Check, info) == -1) + return ((XExtensionVersion *) NoSuchExtension); + + return _XiGetExtensionVersionRequest(dpy, name, info->codes->major_opcode); } diff --git a/src/XIint.h b/src/XIint.h index 400c920..00e84d3 100644 --- a/src/XIint.h +++ b/src/XIint.h @@ -14,6 +14,7 @@ extern XExtDisplayInfo *XInput_find_display(Display *); extern int _XiCheckExtInit(Display *, int, XExtDisplayInfo *); extern XExtensionVersion *_XiGetExtensionVersion(Display *, _Xconst char *, XExtDisplayInfo *); +extern XExtensionVersion* _XiGetExtensionVersionRequest(Display *dpy, _Xconst char *name, int xi_opcode); extern Status _xiQueryVersion(Display *dpy, int*, int*, XExtDisplayInfo *); extern Status _XiEventToWire( |