[PATCH:libXi] Initialize extension with the right number of events.

Peter Hutterer peter.hutterer at who-t.net
Tue Dec 8 20:06:36 PST 2009


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 at who-t.net>
---

something like that should work.

 src/XExtInt.c  |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/XGetVers.c |   24 ++++++++++++++-------
 src/XIint.h    |    1 +
 3 files changed, 77 insertions(+), 9 deletions(-)

diff --git a/src/XExtInt.c b/src/XExtInt.c
index e87ead8..06d979c 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);
+    if (!extversion || !extversion->present)
+        goto out;
+    UnlockDisplay(dpy);
+    SyncHandle();
+
+    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,10 +237,12 @@ 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);
+                                nevents, NULL);
       XESetWireToEventCookie(dpy, dpyinfo->codes->major_opcode, XInputWireToCookie);
       XESetCopyEventCookie(dpy, dpyinfo->codes->major_opcode, XInputCopyCookie);
     }
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(
-- 
1.6.5.2


More information about the xorg-devel mailing list