xserver: Branch 'master' - 14 commits

Keith Packard keithp at kemper.freedesktop.org
Mon Dec 17 11:47:21 PST 2012


 Xi/exevents.c        |   57 +++++++++++++++++++++---------------
 Xi/xiselectev.c      |   80 +++++++++++++++++++++++++++++++++++----------------
 dix/events.c         |   16 ++++++++++
 dix/inpututils.c     |   30 +++++++++++++------
 dix/touch.c          |    4 +-
 include/inpututils.h |    1 
 test/xi2/xi2.c       |    6 +++
 xfixes/xfixes.c      |    2 -
 xkb/xkbAccessX.c     |   30 ++++++++++---------
 9 files changed, 153 insertions(+), 73 deletions(-)

New commits:
commit 6d508b81857edaed03c7ee06410434ea56d9b701
Merge: d982d87 bb6f351
Author: Keith Packard <keithp at keithp.com>
Date:   Mon Dec 17 11:45:45 2012 -0800

    Merge remote-tracking branch 'whot/for-keith'
    
    I've looked at these patches, but I can't say I've actually
    reviewed them...

commit bb6f3514ca17d993c1af380e8d4480d61e5bbcae
Merge: f961c3a 08da994
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 12 17:25:28 2012 +1000

    Merge branch 'stack-smash-on-touchpoint' into for-keith

commit f961c3a3b9dfbe1201da317c24797ba7f979731e
Merge: 36740d0 39f19b3
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 12 17:25:23 2012 +1000

    Merge branch 'touch-selection-conflict-fixes' into for-keith

commit 39f19b3f3b8c9b714e70e339dfb0083ff629ab2a
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Nov 20 11:48:31 2012 +1000

    Xi: fix touch event selction conflicts (#57301)
    
    There are limits on which client may select for touch events on a given
    window, with restrictions being that no two clients can select on the same
    device, but narrower selections are allowed, i.e. if one client has
    XIAllDevices, a second client may still select for device X.
    
    The current code had a dependency on which client selected first and which
    device, resulting in inconsistencies when selecting for events. Fix that,
    responding with the right errors regardless of who selected what first.
    
    X.Org Bug 57301 <http://bugs.freedesktop.org/show_bug.cgi?id=57301>
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/xiselectev.c b/Xi/xiselectev.c
index ab1b624..45a996e 100644
--- a/Xi/xiselectev.c
+++ b/Xi/xiselectev.c
@@ -37,6 +37,57 @@
 #include "xiselectev.h"
 
 /**
+ * Ruleset:
+ * - if A has XIAllDevices, B may select on device X
+ * - If A has XIAllDevices, B may select on XIAllMasterDevices
+ * - If A has XIAllMasterDevices, B may select on device X
+ * - If A has XIAllMasterDevices, B may select on XIAllDevices
+ * - if A has device X, B may select on XIAllDevices/XIAllMasterDevices
+ */
+static int check_for_touch_selection_conflicts(ClientPtr B, WindowPtr win, int deviceid)
+{
+    OtherInputMasks *inputMasks = wOtherInputMasks(win);
+    InputClients *A = NULL;
+
+    if (inputMasks)
+        A = inputMasks->inputClients;
+    for (; A; A = A->next) {
+        DeviceIntPtr tmp;
+
+        if (CLIENT_ID(A->resource) == B->index)
+            continue;
+
+        if (deviceid == XIAllDevices)
+            tmp = inputInfo.all_devices;
+        else if (deviceid == XIAllMasterDevices)
+            tmp = inputInfo.all_master_devices;
+        else
+            dixLookupDevice(&tmp, deviceid, serverClient, DixReadAccess);
+        if (!tmp)
+            return BadImplementation;       /* this shouldn't happen */
+
+        /* A has XIAllDevices */
+        if (xi2mask_isset_for_device(A->xi2mask, inputInfo.all_devices, XI_TouchBegin)) {
+            if (deviceid == XIAllDevices)
+                return BadAccess;
+        }
+
+        /* A has XIAllMasterDevices */
+        if (xi2mask_isset_for_device(A->xi2mask, inputInfo.all_master_devices, XI_TouchBegin)) {
+            if (deviceid == XIAllMasterDevices)
+                return BadAccess;
+        }
+
+        /* A has this device */
+        if (xi2mask_isset_for_device(A->xi2mask, tmp, XI_TouchBegin))
+            return BadAccess;
+    }
+
+    return Success;
+}
+
+
+/**
  * Check the given mask (in len bytes) for invalid mask bits.
  * Invalid mask bits are any bits above XI2LastEvent.
  *
@@ -169,30 +220,11 @@ ProcXISelectEvents(ClientPtr client)
              * same devices, including master devices.
              * XXX: This breaks if a device goes from floating to attached. */
             if (BitIsOn(bits, XI_TouchBegin)) {
-                OtherInputMasks *inputMasks = wOtherInputMasks(win);
-                InputClients *iclient = NULL;
-
-                if (inputMasks)
-                    iclient = inputMasks->inputClients;
-                for (; iclient; iclient = iclient->next) {
-                    DeviceIntPtr tmp;
-
-                    if (CLIENT_ID(iclient->resource) == client->index)
-                        continue;
-
-                    if (evmask->deviceid == XIAllDevices)
-                        tmp = inputInfo.all_devices;
-                    else if (evmask->deviceid == XIAllMasterDevices)
-                        tmp = inputInfo.all_master_devices;
-                    else
-                        dixLookupDevice(&tmp, evmask->deviceid, serverClient,
-                                        DixReadAccess);
-                    if (!tmp)
-                        return BadImplementation;       /* this shouldn't happen */
-
-                    if (xi2mask_isset(iclient->xi2mask, tmp, XI_TouchBegin))
-                        return BadAccess;
-                }
+                rc = check_for_touch_selection_conflicts(client,
+                                                         win,
+                                                         evmask->deviceid);
+                if (rc != Success)
+                    return rc;
             }
         }
 
commit a7c97d737ef0d14ec97869082decd049637cfe7a
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Nov 20 11:38:39 2012 +1000

    dix: split xi2_mask_isset into a per-device function
    
    For touch selection conflicts, we need to check not only if the mask is set
    for the device, but if it is set for only that specific device (regardless
    of XIAll*Devices)
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/inpututils.c b/dix/inpututils.c
index eb2222a..9e38e17 100644
--- a/dix/inpututils.c
+++ b/dix/inpututils.c
@@ -1016,6 +1016,21 @@ xi2mask_free(XI2Mask **mask)
 }
 
 /**
+ * Test if the bit for event type is set for this device only.
+ *
+ * @return TRUE if the bit is set, FALSE otherwise
+ */
+Bool
+xi2mask_isset_for_device(XI2Mask *mask, const DeviceIntPtr dev, int event_type)
+{
+    BUG_WARN(dev->id < 0);
+    BUG_WARN(dev->id >= mask->nmasks);
+    BUG_WARN(bits_to_bytes(event_type + 1) > mask->mask_size);
+
+    return BitIsOn(mask->masks[dev->id], event_type);
+}
+
+/**
  * Test if the bit for event type is set for this device, or the
  * XIAllDevices/XIAllMasterDevices (if applicable) is set.
  *
@@ -1026,15 +1041,12 @@ xi2mask_isset(XI2Mask *mask, const DeviceIntPtr dev, int event_type)
 {
     int set = 0;
 
-    BUG_WARN(dev->id < 0);
-    BUG_WARN(dev->id >= mask->nmasks);
-    BUG_WARN(bits_to_bytes(event_type + 1) > mask->mask_size);
-
-    set = ! !BitIsOn(mask->masks[XIAllDevices], event_type);
-    if (!set)
-        set = ! !BitIsOn(mask->masks[dev->id], event_type);
-    if (!set && IsMaster(dev))
-        set = ! !BitIsOn(mask->masks[XIAllMasterDevices], event_type);
+    if (xi2mask_isset_for_device(mask, inputInfo.all_devices, event_type))
+        set = 1;
+    else if (xi2mask_isset_for_device(mask, dev, event_type))
+        set = 1;
+    else if (IsMaster(dev) && xi2mask_isset_for_device(mask, inputInfo.all_master_devices, event_type))
+        set = 1;
 
     return set;
 }
diff --git a/include/inpututils.h b/include/inpututils.h
index cd9a4de..53c96ba 100644
--- a/include/inpututils.h
+++ b/include/inpututils.h
@@ -57,6 +57,7 @@ XI2Mask *xi2mask_new(void);
 XI2Mask *xi2mask_new_with_size(size_t, size_t); /* don't use it */
 void xi2mask_free(XI2Mask **mask);
 Bool xi2mask_isset(XI2Mask *mask, const DeviceIntPtr dev, int event_type);
+Bool xi2mask_isset_for_device(XI2Mask *mask, const DeviceIntPtr dev, int event_type);
 void xi2mask_set(XI2Mask *mask, int deviceid, int event_type);
 void xi2mask_zero(XI2Mask *mask, int deviceid);
 void xi2mask_merge(XI2Mask *dest, const XI2Mask *source);
diff --git a/test/xi2/xi2.c b/test/xi2/xi2.c
index 6ee7052..1cdad1d 100644
--- a/test/xi2/xi2.c
+++ b/test/xi2/xi2.c
@@ -36,8 +36,14 @@ xi2mask_test(void)
     XI2Mask *xi2mask = NULL, *mergemask = NULL;
     unsigned char *mask;
     DeviceIntRec dev;
+    DeviceIntRec all_devices, all_master_devices;
     int i;
 
+    all_devices.id = XIAllDevices;
+    inputInfo.all_devices = &all_devices;
+    all_master_devices.id = XIAllMasterDevices;
+    inputInfo.all_master_devices = &all_master_devices;
+
     /* size >= nmasks * 2 for the test cases below */
     xi2mask = xi2mask_new_with_size(MAXDEVICES + 2, (MAXDEVICES + 2) * 2);
     assert(xi2mask);
commit 08da994a08bb74afae81176c56fb525d0439274b
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Nov 26 12:33:29 2012 +1000

    dix: add FIXME, TouchRemovePointerGrab does nothing
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/touch.c b/dix/touch.c
index f4a93c6..d890b62 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -915,6 +915,8 @@ TouchRemovePointerGrab(DeviceIntPtr dev)
     ti = TouchFindByClientID(dev, ev->touchid);
     if (!ti)
         return;
+
+    /* FIXME: missing a bit of code here... */
 }
 
 /* As touch grabs don't turn into active grabs with their own resources, we
commit 00def5144557cfe8bf535f926212a8e084dc7cf6
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Nov 26 14:55:13 2012 +1000

    Xi: if a TouchEnd appears on a actively grabbing client, always accept
    
    Once the TouchEnd appears on the device, the touch is done. If the client
    still has a pointer grab, accept it to avoid clients with TouchOwnership
    selections to wait indefinitely for the actual touch event.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index ae126df..4c1aeb4 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1566,32 +1566,41 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
     else
         ti = TouchFindByClientID(dev, touchid);
 
-    /* Under the following circumstances we create a new touch record for an
-     * existing touch:
-     *
-     * - The touch may be pointer emulated
-     * - An explicit grab is active on the device
-     * - The grab is a pointer grab
-     *
-     * This allows for an explicit grab to receive pointer events for an already
-     * active touch.
-     */
-    if (!ti && type != ET_TouchBegin && emulate_pointer &&
-        dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab &&
+    /* Active pointer grab */
+    if (emulate_pointer && dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab &&
         (dev->deviceGrab.grab->grabtype == CORE ||
          dev->deviceGrab.grab->grabtype == XI ||
-         !xi2mask_isset(dev->deviceGrab.grab->xi2mask, dev, XI_TouchBegin))) {
-        ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
-                             emulate_pointer);
-        if (!ti) {
-            DebugF("[Xi] %s: Failed to create new dix record for explicitly "
-                   "grabbed touchpoint %d\n",
-                   dev->name, touchid);
-            return;
-        }
+         !xi2mask_isset(dev->deviceGrab.grab->xi2mask, dev, XI_TouchBegin)))
+    {
+        /* Active pointer grab on touch point and we get a TouchEnd - claim this
+         * touchpoint accepted, otherwise clients waiting for ownership will
+         * wait on this touchpoint until this client ungrabs, or the cows come
+         * home, whichever is earlier */
+        if (ti && type == ET_TouchEnd)
+            TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
+        else if (!ti && type != ET_TouchBegin) {
+            /* Under the following circumstances we create a new touch record for an
+             * existing touch:
+             *
+             * - The touch may be pointer emulated
+             * - An explicit grab is active on the device
+             * - The grab is a pointer grab
+             *
+             * This allows for an explicit grab to receive pointer events for an already
+             * active touch.
+             */
+            ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
+                                 emulate_pointer);
+            if (!ti) {
+                DebugF("[Xi] %s: Failed to create new dix record for explicitly "
+                       "grabbed touchpoint %d\n",
+                       dev->name, touchid);
+                return;
+            }
 
-        TouchBuildSprite(dev, ti, ev);
-        TouchSetupListeners(dev, ti, ev);
+            TouchBuildSprite(dev, ti, ev);
+            TouchSetupListeners(dev, ti, ev);
+        }
     }
 
     if (!ti) {
commit ece8157a59751b3ed492fb2e1eb8d5f20221e195
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Nov 26 15:14:19 2012 +1000

    dix: when deactivating pointer-only grabs, don't emulate TouchEnd events
    
    A client with a pointer grab on a touch device must reject the touch when
    detactivating the grab while the touch is active. However, such a rejecting
    must not trigger a ButtonRelease event to be emulated and sent to the
    client.
    Set the grabbing listener's state to HAS_END, so we simply skip delivery to
    that client.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/events.c b/dix/events.c
index 03ed106..31f8d87 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1513,8 +1513,15 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
      * all the touches' listener lists. */
     for (i = 0; !wasPassive && mouse->touch && i < mouse->touch->num_touches; i++) {
         TouchPointInfoPtr ti = mouse->touch->touches + i;
-        if (ti->active && TouchResourceIsOwner(ti, grab_resource))
+        if (ti->active && TouchResourceIsOwner(ti, grab_resource)) {
+            /* Rejecting will generate a TouchEnd, but we must not
+               emulate a ButtonRelease here. So pretend the listener
+               already has the end event */
+            if (grab->grabtype == CORE || grab->grabtype == XI ||
+                    !xi2mask_isset(dev->deviceGrab.grab->xi2mask, dev, XI_TouchBegin))
+                ti->listeners[0].state = LISTENER_HAS_END;
             TouchListenerAcceptReject(mouse, ti, 0, XIRejectTouch);
+        }
     }
 
     TouchRemovePointerGrab(mouse);
commit bc1f90a615018c05994fae3e678dd2341256cd82
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Nov 26 12:23:54 2012 +1000

    dix: only reject active grabs on ungrab and do it before actually ungrabbing
    
    An active grab ungrabbing is the same as rejecting the grab, since the
    client is no longer interested in those events. So reject any touch grab,
    but do so before actually deactivating since we're interested in the
    TouchEnd for the current grabbing client.
    
    A passive grab otoh is _not_ like rejecting a grab, since it deactivates
    automatically when the touch ends.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/events.c b/dix/events.c
index 3282ef8..03ed106 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1503,11 +1503,20 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
 {
     GrabPtr grab = mouse->deviceGrab.grab;
     DeviceIntPtr dev;
+    Bool wasPassive = mouse->deviceGrab.fromPassiveGrab;
     Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
                         mouse->deviceGrab.implicitGrab);
     XID grab_resource = grab->resource;
     int i;
 
+    /* If an explicit grab was deactivated, we must remove it from the head of
+     * all the touches' listener lists. */
+    for (i = 0; !wasPassive && mouse->touch && i < mouse->touch->num_touches; i++) {
+        TouchPointInfoPtr ti = mouse->touch->touches + i;
+        if (ti->active && TouchResourceIsOwner(ti, grab_resource))
+            TouchListenerAcceptReject(mouse, ti, 0, XIRejectTouch);
+    }
+
     TouchRemovePointerGrab(mouse);
 
     mouse->valuator->motionHintWindow = NullWindow;
commit 146f48c2934fc85ec095496da5c8f0102bc7f5b5
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Nov 22 13:49:34 2012 +1000

    dix: don't call ProcessInputEvents() when accepting/rejecting touches
    
    TouchListenerAcceptReject may be called during normal event processing, but
    ProcessInputEvents is not reentrant and calling it here smashes the event
    queue.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/touch.c b/dix/touch.c
index 29ba171..f4a93c6 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -987,8 +987,6 @@ TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti, int listener,
     for (i = 0; i < nev; i++)
         mieqProcessDeviceEvent(dev, events + i, NULL);
 
-    ProcessInputEvents();
-
     FreeEventList(events, GetMaximumEventsNum());
 
     return nev ? Success : BadMatch;
commit ead21f9426122536adfb4787ac181008ae83cd4b
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Nov 19 16:16:10 2012 +1000

    Xi: fix typo "mechansims" → "mechanisms"
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 2caf98c..ae126df 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1409,7 +1409,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
     ptrev->device_event.corestate = event_get_corestate(dev, kbd);
 
     if (grab) {
-        /* this side-steps the usual activation mechansims, but... */
+        /* this side-steps the usual activation mechanisms, but... */
         if (ev->any.type == ET_TouchBegin && !dev->deviceGrab.grab)
             ActivatePassiveGrab(dev, grab, ptrev, ev);  /* also delivers the event */
         else {
commit 36740d02b9ca117f1404e077367fbbbe271a17d6
Author: Daniel Martin <consume.noise at gmail.com>
Date:   Fri Dec 7 19:38:55 2012 +0100

    xfixes: Fix minor number in QueryVersion
    
    Due to a typo the major version number was passed as minor version to
    version_compare().
    
    Regression-from: ffd4874798ba54f86acac75779a15b4babeaa5f3
    
    Signed-off-by: Daniel Martin <consume.noise at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/xfixes/xfixes.c b/xfixes/xfixes.c
index 52c57df..48af9ea 100644
--- a/xfixes/xfixes.c
+++ b/xfixes/xfixes.c
@@ -74,7 +74,7 @@ ProcXFixesQueryVersion(ClientPtr client)
 
     if (version_compare(stuff->majorVersion, stuff->minorVersion,
                         SERVER_XFIXES_MAJOR_VERSION,
-                        SERVER_XFIXES_MAJOR_VERSION) < 0) {
+                        SERVER_XFIXES_MINOR_VERSION) < 0) {
         rep.majorVersion = stuff->majorVersion;
         rep.minorVersion = stuff->minorVersion;
     }
commit 5daa442fe15d9a87112a2def673c99a5f2506dcf
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Dec 4 15:28:14 2012 +1000

    xkb: only post a XTest release if the XTest device has the button down
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/xkb/xkbAccessX.c b/xkb/xkbAccessX.c
index 9631502..13051e0 100644
--- a/xkb/xkbAccessX.c
+++ b/xkb/xkbAccessX.c
@@ -732,8 +732,13 @@ ProcessPointerEvent(InternalEvent *ev, DeviceIntPtr mouse)
             if (rc != Success)
                 ErrorF("[xkb] bad sourceid '%d' on button release event.\n",
                         event->sourceid);
-            else if (!IsXTestDevice(source, GetMaster(dev, MASTER_POINTER)))
-                XkbFakeDeviceButton(dev, FALSE, event->detail.key);
+            else if (!IsXTestDevice(source, GetMaster(dev, MASTER_POINTER))) {
+                DeviceIntPtr xtest_device;
+
+                xtest_device = GetXTestDevice(GetMaster(dev, MASTER_POINTER));
+                if (button_is_down(xtest_device, ev->device_event.detail.button, BUTTON_PROCESSED))
+                    XkbFakeDeviceButton(dev, FALSE, event->detail.key);
+            }
         }
 
         if (xkbi)
commit c4fee9d2ecd6fdd4c05b04c9f02b23f10f2938b8
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Dec 4 15:03:37 2012 +1000

    xkb: always post XTest button up when the physical button released (#28808)
    
    Regression introduced by commit 2decff6393a44b56d80d53570718f95354fde454
      xkb: ProcesssPointerEvent must work on the VCP if it gets the VCP
    
    XTest buttons must be released when a physical button is released. This was
    fixed in 14327858391ebe929b806efb53ad79e789361883, but
    2decff6393a44b56d80d53570718f95354fde454 changed a condition that this code
    didn't get triggered anymore.
    
    "dev" for pointer events is now always the VCP which doesn't have a xkbi
    struct. So move this condition out and always trigger the XTest released for
    button events.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Tested-by: Frank Roscher <Frank-Roscher at gmx.net>

diff --git a/xkb/xkbAccessX.c b/xkb/xkbAccessX.c
index 21df85d..9631502 100644
--- a/xkb/xkbAccessX.c
+++ b/xkb/xkbAccessX.c
@@ -723,23 +723,22 @@ ProcessPointerEvent(InternalEvent *ev, DeviceIntPtr mouse)
         changed |= XkbPointerButtonMask;
     }
     else if (event->type == ET_ButtonRelease) {
-        if (xkbi) {
-            xkbi->lockedPtrButtons &= ~(1 << (event->detail.key & 0x7));
-
-            if (IsMaster(dev)) {
-                DeviceIntPtr source;
-                int rc;
-
-                rc = dixLookupDevice(&source, event->sourceid, serverClient,
-                                     DixWriteAccess);
-                if (rc != Success)
-                    ErrorF("[xkb] bad sourceid '%d' on button release event.\n",
-                           event->sourceid);
-                else if (!IsXTestDevice(source, GetMaster(dev, MASTER_POINTER)))
-                    XkbFakeDeviceButton(dev, FALSE, event->detail.key);
-            }
+        if (IsMaster(dev)) {
+            DeviceIntPtr source;
+            int rc;
+
+            rc = dixLookupDevice(&source, event->sourceid, serverClient,
+                    DixWriteAccess);
+            if (rc != Success)
+                ErrorF("[xkb] bad sourceid '%d' on button release event.\n",
+                        event->sourceid);
+            else if (!IsXTestDevice(source, GetMaster(dev, MASTER_POINTER)))
+                XkbFakeDeviceButton(dev, FALSE, event->detail.key);
         }
 
+        if (xkbi)
+            xkbi->lockedPtrButtons &= ~(1 << (event->detail.key & 0x7));
+
         changed |= XkbPointerButtonMask;
     }
 


More information about the xorg-commit mailing list