xserver: Branch 'master' - 2 commits

Keith Packard keithp at kemper.freedesktop.org
Wed Jun 30 08:47:10 PDT 2010


 include/dixstruct.h |    1 +
 include/xkbsrv.h    |    3 +++
 os/connection.c     |    9 +++++++++
 xkb/xkbAccessX.c    |   18 +++++++++++++++++-
 xkb/xkbActions.c    |   10 ++++++++++
 xkb/xkbUtils.c      |   26 ++++++++++++++++++++++++++
 6 files changed, 66 insertions(+), 1 deletion(-)

New commits:
commit 6052710670953b43b4fff5d101b727163fcb1187
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Jun 30 08:21:04 2010 -0700

    xkb: merge lockedPtrButtons state from all attached SDs.
    
    Problem:
    lockedPtrButtons keeps the state of the buttons locked by a PointerKeys button
    press. Unconditionally clearing the bits may cause stuck buttons in this
    sequence of events:
    
    1. type Shift + NumLock to enable PointerKeys
    2. type 0/Ins on keypad to emulate Button 1 press
            → button1 press event to client
    3. press and release button 1 on physical mouse
            → button1 release event to client
    
    Button 1 on the MD is now stuck and cannot be released.
    
    Cause:
    XKB PointerKeys button events are posted through the XTEST pointer device.
    Once a press is generated, the XTEST device's button is down. The DIX merges
    the button state of all attached SDs, hence the MD will have a button down
    while the XTEST device has a button down.
    
    PointerKey button events are only generated on the master device to avoid
    duplicate events (see XkbFakeDeviceButton()). If the MD has the
    lockedPtrButtons bit cleared by a release event on a physical device, no
    such event is generated when a keyboard device triggers the PointerKey
    ButtonRelease trigger. Since the event - if generated - is posted through
    the XTEST pointer device, lack of a generated ButtonRelease event on the
    XTEST pointer device means the button is never released, resulting in the
    stuck button observed above.
    
    Solution:
    This patch merges the MD's lockedPtrButtons with the one of all attached
    slave devices on release events. Thus, as long as one attached keyboard has
    a lockedPtrButtons bit set, this bit is kept in the MD. Once a PointerKey
    button is released on all keyboards, the matching release event is emulated
    from the MD through the XTEST pointer device, thus also releasing the button
    in the DIX.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/include/xkbsrv.h b/include/xkbsrv.h
index 5847e63..956b224 100644
--- a/include/xkbsrv.h
+++ b/include/xkbsrv.h
@@ -924,6 +924,9 @@ extern int XkbGetEffectiveGroup(
         XkbStatePtr             /* xkbstate */,
         CARD8                   /* keycode */);
 
+extern void XkbMergeLockedPtrBtns(
+        DeviceIntPtr            /* master */);
+
 #include "xkbfile.h"
 #include "xkbrules.h"
 
diff --git a/xkb/xkbAccessX.c b/xkb/xkbAccessX.c
index b5486b7..451c797 100644
--- a/xkb/xkbAccessX.c
+++ b/xkb/xkbAccessX.c
@@ -707,8 +707,24 @@ DeviceEvent     *event = &ev->device_event;
 	    changed |= XkbPointerButtonMask;
     }
     else if (event->type == ET_ButtonRelease) {
-	if (xkbi)
+	if (xkbi) {
 	    xkbi->lockedPtrButtons&= ~(1 << (event->detail.key & 0x7));
+
+            /* Merge this MD's lockedPtrButtons with the one of all
+             * attached slave devices.
+             * The DIX uses a merged button state for MDs, not
+             * releasing buttons until the last SD has released
+             * thenm. If we unconditionally clear the
+             * lockedPtrButtons bit on the MD, a PointerKeys button
+             * release on the SD keyboard won't generate the required fake button
+             * event on the XTEST pointer, thus never processing the
+             * button event in the DIX and the XTEST pointer's
+             * buttons stay down - result is a stuck button.
+             */
+	    if (IsMaster(dev))
+                XkbMergeLockedPtrBtns(dev);
+	}
+
 	changed |= XkbPointerButtonMask;
     }
 
diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c
index c5030d0..b4b8395 100644
--- a/xkb/xkbActions.c
+++ b/xkb/xkbActions.c
@@ -633,6 +633,16 @@ _XkbFilterPointerBtn(	XkbSrvInfoPtr	xkbi,
 		    break;
 		}
 		xkbi->lockedPtrButtons&= ~(1<<button);
+
+		if (IsMaster(xkbi->device))
+		{
+		    XkbMergeLockedPtrBtns(xkbi->device);
+                    /* One SD still has lock set, don't post event */
+		    if ((xkbi->lockedPtrButtons & (1 << button)) != 0)
+			break;
+		}
+
+		/* fallthrough */
 	    case XkbSA_PtrBtn:
 		XkbFakeDeviceButton(xkbi->device, 0, button);
 		break;
diff --git a/xkb/xkbUtils.c b/xkb/xkbUtils.c
index 3344e50..14dc784 100644
--- a/xkb/xkbUtils.c
+++ b/xkb/xkbUtils.c
@@ -2094,3 +2094,29 @@ XkbGetEffectiveGroup(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 keycode)
 
     return effectiveGroup;
 }
+
+/* Merge the lockedPtrButtons from all attached SDs for the given master
+ * device into the MD's state.
+ */
+void
+XkbMergeLockedPtrBtns(DeviceIntPtr master)
+{
+    DeviceIntPtr d = inputInfo.devices;
+    XkbSrvInfoPtr xkbi = NULL;
+
+    if (!IsMaster(master))
+        return;
+
+    if (!master->key)
+        return;
+
+    xkbi = master->key->xkbInfo;
+    xkbi->lockedPtrButtons = 0;
+
+    for (; d; d = d->next) {
+        if (IsMaster(d) || GetMaster(d, MASTER_KEYBOARD) != master || !d->key)
+            continue;
+
+        xkbi->lockedPtrButtons |= d->key->xkbInfo->lockedPtrButtons;
+    }
+}
commit 28e33ae6f69f716ece5d68e63fc52557236c5f6e
Author: Jesse Barnes <jbarnes at virtuousgeek.org>
Date:   Wed Jun 30 07:59:04 2010 -0700

    OS support: fix writeable client vs IgnoreClient behavior
    
    When ResetCurrentRequest is called, or IgnoreClient is called when a
    client has input pending, IgnoredClientsWithInput will be set.  However,
    a subsequent IgnoreClient request will clear the client fd from that fd
    set, potentially causing the client to hang.
    
    So add an Ignore/Attend count, and only apply the ignore logic on the
    first ignore and the attend logic on the last attend.  This is
    consistent with the comments for these functions; callers must pair
    them.
    
    Fixes https://bugs.freedesktop.org/show_bug.cgi?id=27035.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Daniel Stone <daniel at fooishbar.org>
    Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/include/dixstruct.h b/include/dixstruct.h
index 9610427..efa2577 100644
--- a/include/dixstruct.h
+++ b/include/dixstruct.h
@@ -98,6 +98,7 @@ typedef struct _Client {
     int         clientGone;
     int         noClientException;	/* this client died or needs to be
 					 * killed */
+    int         ignoreCount;		/* count for Attend/IgnoreClient */
     SaveSetElt	*saveSet;
     int         numSaved;
     int         (**requestVector) (
diff --git a/os/connection.c b/os/connection.c
index cd0ca5e..c143fb6 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -1147,6 +1147,10 @@ IgnoreClient (ClientPtr client)
     OsCommPtr oc = (OsCommPtr)client->osPrivate;
     int connection = oc->fd;
 
+    client->ignoreCount++;
+    if (client->ignoreCount > 1)
+	return;
+
     isItTimeToYield = TRUE;
     if (!GrabInProgress || FD_ISSET(connection, &AllClients))
     {
@@ -1181,6 +1185,11 @@ AttendClient (ClientPtr client)
 {
     OsCommPtr oc = (OsCommPtr)client->osPrivate;
     int connection = oc->fd;
+
+    client->ignoreCount--;
+    if (client->ignoreCount)
+	return;
+
     if (!GrabInProgress || GrabInProgress == client->index ||
 	FD_ISSET(connection, &GrabImperviousClients))
     {


More information about the xorg-commit mailing list