]> git.ipfire.org Git - people/stevee/ipfire-3.x.git/blobdiff - xorg-x11-server/patches/xserver-1.8.2-XTEST-PointerKeys-fixes.patch
Move all packages to root.
[people/stevee/ipfire-3.x.git] / xorg-x11-server / patches / xserver-1.8.2-XTEST-PointerKeys-fixes.patch
diff --git a/xorg-x11-server/patches/xserver-1.8.2-XTEST-PointerKeys-fixes.patch b/xorg-x11-server/patches/xserver-1.8.2-XTEST-PointerKeys-fixes.patch
new file mode 100644 (file)
index 0000000..ece8a6c
--- /dev/null
@@ -0,0 +1,909 @@
+From deab888bb3bb2a56963da50ff551bd66fbd858a1 Mon Sep 17 00:00:00 2001
+From: Peter Hutterer <peter.hutterer@who-t.net>
+Date: Tue, 29 Jun 2010 13:49:27 +1000
+Subject: [PATCH 1/5] xkb: Mark switch case fallthrough with comment.
+
+Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
+---
+ xkb/xkbActions.c |    2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c
+index 4c7bce2..6a7f36d 100644
+--- a/xkb/xkbActions.c
++++ b/xkb/xkbActions.c
+@@ -625,6 +625,8 @@ _XkbFilterPointerBtn(      XkbSrvInfoPtr   xkbi,
+                   break;
+               }
+               xkbi->lockedPtrButtons&= ~(1<<button);
++
++              /* fallthrough */
+           case XkbSA_PtrBtn:
+               XkbDDXFakeDeviceButton(xkbi->device, 0, button);
+               break;
+-- 
+1.7.1
+
+From 50b6311dbd2594acc36d6856fdde8623459f1374 Mon Sep 17 00:00:00 2001
+From: Peter Hutterer <peter.hutterer@who-t.net>
+Date: Tue, 29 Jun 2010 12:12:53 +1000
+Subject: [PATCH 2/5] xkb: merge lockedPtrButtons state from all attached SDs.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+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@who-t.net>
+---
+ include/xkbsrv.h |    3 +++
+ xkb/xkbAccessX.c |   18 +++++++++++++++++-
+ xkb/xkbActions.c |    8 ++++++++
+ xkb/xkbUtils.c   |   26 ++++++++++++++++++++++++++
+ 4 files changed, 54 insertions(+), 1 deletions(-)
+
+diff --git a/include/xkbsrv.h b/include/xkbsrv.h
+index c0cd501..f0db0e4 100644
+--- a/include/xkbsrv.h
++++ b/include/xkbsrv.h
+@@ -933,6 +933,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 be1dcee..e3fdc06 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 6a7f36d..ab52b6a 100644
+--- a/xkb/xkbActions.c
++++ b/xkb/xkbActions.c
+@@ -626,6 +626,14 @@ _XkbFilterPointerBtn(     XkbSrvInfoPtr   xkbi,
+               }
+               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:
+               XkbDDXFakeDeviceButton(xkbi->device, 0, button);
+diff --git a/xkb/xkbUtils.c b/xkb/xkbUtils.c
+index b1e0e55..d7d1935 100644
+--- a/xkb/xkbUtils.c
++++ b/xkb/xkbUtils.c
+@@ -2190,3 +2190,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;
++    }
++}
+-- 
+1.7.1
+
+From 4a4224f5d786035af88c251a9ee177217e8f77fd Mon Sep 17 00:00:00 2001
+From: Peter Hutterer <peter.hutterer@who-t.net>
+Date: Wed, 14 Apr 2010 10:54:29 +1000
+Subject: [PATCH 3/5] xkb: rename XkbFakeDeviceButton and XkbFakeDeviceMotion, move into xkbActions.c
+
+The name XkbDDXFakeDeviceButton and XkbDDXFakeDeviceMotion is somewhat
+misleading, there's no DDX involved in the game at all anymore.
+
+This removes XkbFakeDeviceMotion and XkbFakeDeviceButton from the API where
+it arguably shouldn't have been in the first place.
+
+Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
+Reviewed-by: Daniel Stone <daniel@fooishbar.org>
+Reviewed-by: Dan Nicholson <dbn.lists@gmail.com>
+---
+ include/xkbsrv.h |   13 -------
+ xkb/Makefile.am  |    4 +--
+ xkb/ddxDevBtn.c  |   69 --------------------------------------
+ xkb/ddxFakeMtn.c |   64 -----------------------------------
+ xkb/xkbActions.c |   97 ++++++++++++++++++++++++++++++++++++++++++++++-------
+ 5 files changed, 85 insertions(+), 162 deletions(-)
+ delete mode 100644 xkb/ddxDevBtn.c
+ delete mode 100644 xkb/ddxFakeMtn.c
+
+diff --git a/include/xkbsrv.h b/include/xkbsrv.h
+index f0db0e4..d1cbd1a 100644
+--- a/include/xkbsrv.h
++++ b/include/xkbsrv.h
+@@ -768,19 +768,6 @@ extern _X_EXPORT void XkbDDXUpdateDeviceIndicators(
+       CARD32                  /* newState */
+ );
+-extern _X_EXPORT void XkbDDXFakePointerMotion(
+-      DeviceIntPtr    /* dev */,
+-      unsigned int    /* flags */,
+-      int             /* x */,
+-      int             /* y */
+-);
+-
+-extern _X_EXPORT void XkbDDXFakeDeviceButton(
+-      DeviceIntPtr    /* dev */,
+-      Bool            /* press */,
+-      int             /* button */
+-);
+-
+ extern _X_EXPORT int XkbDDXTerminateServer(
+       DeviceIntPtr    /* dev */,
+       KeyCode         /* key */,
+diff --git a/xkb/Makefile.am b/xkb/Makefile.am
+index e54ce59..fb3ccbf 100644
+--- a/xkb/Makefile.am
++++ b/xkb/Makefile.am
+@@ -5,11 +5,9 @@ AM_CFLAGS = $(DIX_CFLAGS)
+ DDX_SRCS = \
+         ddxBeep.c \
+         ddxCtrls.c \
+-        ddxFakeMtn.c \
+         ddxLEDs.c \
+         ddxLoad.c \
+-        ddxList.c \
+-        ddxDevBtn.c
++        ddxList.c
+ DIX_SRCS = \
+         xkb.c \
+diff --git a/xkb/ddxDevBtn.c b/xkb/ddxDevBtn.c
+deleted file mode 100644
+index b8a1255..0000000
+--- a/xkb/ddxDevBtn.c
++++ /dev/null
+@@ -1,69 +0,0 @@
+-/************************************************************
+-Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
+-
+-Permission to use, copy, modify, and distribute this
+-software and its documentation for any purpose and without
+-fee is hereby granted, provided that the above copyright
+-notice appear in all copies and that both that copyright
+-notice and this permission notice appear in supporting
+-documentation, and that the name of Silicon Graphics not be 
+-used in advertising or publicity pertaining to distribution 
+-of the software without specific prior written permission.
+-Silicon Graphics makes no representation about the suitability 
+-of this software for any purpose. It is provided "as is"
+-without any express or implied warranty.
+-
+-SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 
+-SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 
+-AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+-GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
+-DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 
+-DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
+-OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
+-THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-********************************************************/
+-
+-#ifdef HAVE_DIX_CONFIG_H
+-#include <dix-config.h>
+-#endif
+-
+-#include "inputstr.h"
+-#include <xkbsrv.h>
+-#include "mi.h"
+-
+-void
+-XkbDDXFakeDeviceButton(DeviceIntPtr dev,Bool press,int button)
+-{
+-    EventListPtr        events;
+-    int                 nevents, i;
+-    DeviceIntPtr        ptr;
+-
+-    /* If dev is a slave device, and the SD is attached, do nothing. If we'd
+-     * post through the attached master pointer we'd get duplicate events.
+-     *
+-     * if dev is a master keyboard, post through the XTEST device
+-     *
+-     * if dev is a floating slave, post through the device itself.
+-     */
+-
+-    if (IsMaster(dev))
+-        ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER));
+-    else if (!dev->u.master)
+-        ptr = dev;
+-    else
+-        return;
+-
+-    events = InitEventList(GetMaximumEventsNum());
+-    OsBlockSignals();
+-    nevents = GetPointerEvents(events, ptr,
+-                               press ? ButtonPress : ButtonRelease, button,
+-                               0 /* flags */, 0 /* first */,
+-                               0 /* num_val */, NULL);
+-    OsReleaseSignals();
+-
+-    for (i = 0; i < nevents; i++)
+-        mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL);
+-
+-    FreeEventList(events, GetMaximumEventsNum());
+-}
+diff --git a/xkb/ddxFakeMtn.c b/xkb/ddxFakeMtn.c
+deleted file mode 100644
+index b383716..0000000
+--- a/xkb/ddxFakeMtn.c
++++ /dev/null
+@@ -1,64 +0,0 @@
+-/************************************************************
+-Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
+-
+-Permission to use, copy, modify, and distribute this
+-software and its documentation for any purpose and without
+-fee is hereby granted, provided that the above copyright
+-notice appear in all copies and that both that copyright
+-notice and this permission notice appear in supporting
+-documentation, and that the name of Silicon Graphics not be 
+-used in advertising or publicity pertaining to distribution 
+-of the software without specific prior written permission.
+-Silicon Graphics makes no representation about the suitability 
+-of this software for any purpose. It is provided "as is"
+-without any express or implied warranty.
+-
+-SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 
+-SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 
+-AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+-GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
+-DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 
+-DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
+-OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
+-THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-********************************************************/
+-
+-#ifdef HAVE_DIX_CONFIG_H
+-#include <dix-config.h>
+-#endif
+-
+-#include "inputstr.h"
+-#include <xkbsrv.h>
+-#include "mi.h"
+-
+-void
+-XkbDDXFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y)
+-{
+-    EventListPtr        events;
+-    int                 nevents, i;
+-    DeviceIntPtr        ptr;
+-    int                 gpe_flags = 0;
+-
+-    if (!dev->u.master)
+-        ptr = dev;
+-    else
+-        ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER));
+-
+-    if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY)
+-        gpe_flags = POINTER_ABSOLUTE;
+-    else
+-        gpe_flags = POINTER_RELATIVE;
+-
+-    events = InitEventList(GetMaximumEventsNum());
+-    OsBlockSignals();
+-    nevents = GetPointerEvents(events, ptr,
+-                               MotionNotify, 0,
+-                               gpe_flags, 0, 2, (int[]){x, y});
+-    OsReleaseSignals();
+-
+-    for (i = 0; i < nevents; i++)
+-        mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL);
+-
+-    FreeEventList(events, GetMaximumEventsNum());
+-}
+diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c
+index ab52b6a..2817e39 100644
+--- a/xkb/xkbActions.c
++++ b/xkb/xkbActions.c
+@@ -40,11 +40,15 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ #include <xkbsrv.h>
+ #include "xkb.h"
+ #include <ctype.h>
++#include "mi.h"
+ #define EXTENSION_EVENT_BASE 64
+ static int xkbDevicePrivateKeyIndex;
+ DevPrivateKey xkbDevicePrivateKey = &xkbDevicePrivateKeyIndex;
++static void XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button);
++static void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y);
++
+ void
+ xkbUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc,
+                    pointer data)
+@@ -479,7 +483,7 @@ int                dx,dy;
+       dx= xkbi->mouseKeysDX;
+       dy= xkbi->mouseKeysDY;
+     }
+-    XkbDDXFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags,dx,dy);
++    XkbFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags,dx,dy);
+     return xkbi->desc->ctrls->mk_interval;
+ }
+@@ -507,7 +511,7 @@ Bool       accel;
+       accel= ((pAction->ptr.flags&XkbSA_NoAcceleration)==0);
+       x= XkbPtrActionX(&pAction->ptr);
+       y= XkbPtrActionY(&pAction->ptr);
+-      XkbDDXFakePointerMotion(xkbi->device, pAction->ptr.flags,x,y);
++      XkbFakePointerMotion(xkbi->device, pAction->ptr.flags,x,y);
+       AccessXCancelRepeatKey(xkbi,keycode);
+       xkbi->mouseKeysAccel= accel&&
+               (xkbi->desc->ctrls->enabled_ctrls&XkbMouseKeysAccelMask);
+@@ -554,7 +558,7 @@ _XkbFilterPointerBtn(      XkbSrvInfoPtr   xkbi,
+                       ((pAction->btn.flags&XkbSA_LockNoLock)==0)) {
+                   xkbi->lockedPtrButtons|= (1<<button);
+                   AccessXCancelRepeatKey(xkbi,keycode);
+-                  XkbDDXFakeDeviceButton(xkbi->device, 1, button);
++                  XkbFakeDeviceButton(xkbi->device, 1, button);
+                   filter->upAction.type= XkbSA_NoAction;
+               }
+               break;
+@@ -565,12 +569,12 @@ _XkbFilterPointerBtn(    XkbSrvInfoPtr   xkbi,
+                   if (pAction->btn.count>0) {
+                       nClicks= pAction->btn.count;
+                       for (i=0;i<nClicks;i++) {
+-                          XkbDDXFakeDeviceButton(xkbi->device, 1, button);
+-                          XkbDDXFakeDeviceButton(xkbi->device, 0, button);
++                          XkbFakeDeviceButton(xkbi->device, 1, button);
++                          XkbFakeDeviceButton(xkbi->device, 0, button);
+                       }
+                       filter->upAction.type= XkbSA_NoAction;
+                   }
+-                  else XkbDDXFakeDeviceButton(xkbi->device, 1, button);
++                  else XkbFakeDeviceButton(xkbi->device, 1, button);
+               }
+               break;
+           case XkbSA_SetPtrDflt:
+@@ -636,7 +640,7 @@ _XkbFilterPointerBtn(      XkbSrvInfoPtr   xkbi,
+               /* fallthrough */
+           case XkbSA_PtrBtn:
+-              XkbDDXFakeDeviceButton(xkbi->device, 0, button);
++              XkbFakeDeviceButton(xkbi->device, 0, button);
+               break;
+       }
+       filter->active = 0;
+@@ -974,7 +978,7 @@ int                button;
+               if ((pAction->devbtn.flags&XkbSA_LockNoLock)||
+                   BitIsOn(dev->button->down, button))
+                   return 0;
+-              XkbDDXFakeDeviceButton(dev,TRUE,button);
++              XkbFakeDeviceButton(dev,TRUE,button);
+               filter->upAction.type= XkbSA_NoAction;
+               break;
+           case XkbSA_DeviceBtn:
+@@ -982,12 +986,12 @@ int              button;
+                   int nClicks,i;
+                   nClicks= pAction->btn.count;
+                   for (i=0;i<nClicks;i++) {
+-                      XkbDDXFakeDeviceButton(dev,TRUE,button);
+-                      XkbDDXFakeDeviceButton(dev,FALSE,button);
++                      XkbFakeDeviceButton(dev,TRUE,button);
++                      XkbFakeDeviceButton(dev,FALSE,button);
+                   }
+                   filter->upAction.type= XkbSA_NoAction;
+               }
+-              else XkbDDXFakeDeviceButton(dev,TRUE,button);
++              else XkbFakeDeviceButton(dev,TRUE,button);
+               break;
+       }
+     }
+@@ -1006,10 +1010,10 @@ int            button;
+               if ((filter->upAction.devbtn.flags&XkbSA_LockNoUnlock)||
+                   !BitIsOn(dev->button->down, button))
+                   return 0;
+-              XkbDDXFakeDeviceButton(dev,FALSE,button);
++              XkbFakeDeviceButton(dev,FALSE,button);
+               break;
+           case XkbSA_DeviceBtn:
+-              XkbDDXFakeDeviceButton(dev,FALSE,button);
++              XkbFakeDeviceButton(dev,FALSE,button);
+               break;
+       }
+       filter->active = 0;
+@@ -1326,3 +1330,70 @@ xkbStateNotify  sn;
+     return;
+ }
++static void
++XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y)
++{
++    EventListPtr        events;
++    int                 nevents, i;
++    DeviceIntPtr        ptr;
++    int                 gpe_flags = 0;
++
++    if (!dev->u.master)
++        ptr = dev;
++    else
++        ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER));
++
++    if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY)
++        gpe_flags = POINTER_ABSOLUTE;
++    else
++        gpe_flags = POINTER_RELATIVE;
++
++    events = InitEventList(GetMaximumEventsNum());
++    OsBlockSignals();
++    nevents = GetPointerEvents(events, ptr,
++                               MotionNotify, 0,
++                               gpe_flags, 0, 2, (int[]){x, y});
++    OsReleaseSignals();
++
++    for (i = 0; i < nevents; i++)
++        mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL);
++
++    FreeEventList(events, GetMaximumEventsNum());
++}
++
++static void
++XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button)
++{
++    EventListPtr        events;
++    int                 nevents, i;
++    DeviceIntPtr        ptr;
++
++    /* If dev is a slave device, and the SD is attached, do nothing. If we'd
++     * post through the attached master pointer we'd get duplicate events.
++     *
++     * if dev is a master keyboard, post through the XTEST device
++     *
++     * if dev is a floating slave, post through the device itself.
++     */
++
++    if (IsMaster(dev))
++        ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER));
++    else if (!dev->u.master)
++        ptr = dev;
++    else
++        return;
++
++    events = InitEventList(GetMaximumEventsNum());
++    OsBlockSignals();
++    nevents = GetPointerEvents(events, ptr,
++                               press ? ButtonPress : ButtonRelease, button,
++                               0 /* flags */, 0 /* first */,
++                               0 /* num_val */, NULL);
++    OsReleaseSignals();
++
++
++    for (i = 0; i < nevents; i++)
++        mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL);
++
++    FreeEventList(events, GetMaximumEventsNum());
++}
+-- 
+1.7.1
+
+From dcb46252f959893f1934232698e2ae26390a8a5b Mon Sep 17 00:00:00 2001
+From: Peter Hutterer <peter.hutterer@who-t.net>
+Date: Tue, 29 Jun 2010 15:24:51 +1000
+Subject: [PATCH 4/5] xkb: emulate PointerKeys events only on the master device.
+
+This patch replicates the behaviour for button events. Only generate a
+PointerKeys motion event on the master device, not on the slave device.
+Fixes the current issue of PointerKey motion events generating key events as
+well.
+
+Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
+---
+ xkb/xkbActions.c |    9 ++++-----
+ 1 files changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c
+index 2817e39..391c375 100644
+--- a/xkb/xkbActions.c
++++ b/xkb/xkbActions.c
+@@ -496,9 +496,6 @@ _XkbFilterPointerMove(     XkbSrvInfoPtr   xkbi,
+ int   x,y;
+ Bool  accel;
+-    if (xkbi->device == inputInfo.keyboard)
+-        return 0;
+-
+     if (filter->keycode==0) {         /* initial press */
+       filter->keycode = keycode;
+       filter->active = 1;
+@@ -1338,10 +1335,12 @@ XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y)
+     DeviceIntPtr        ptr;
+     int                 gpe_flags = 0;
+-    if (!dev->u.master)
++    if (IsMaster(dev))
++        ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER));
++    else if (!dev->u.master)
+         ptr = dev;
+     else
+-        ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER));
++        return;
+     if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY)
+         gpe_flags = POINTER_ABSOLUTE;
+-- 
+1.7.1
+
+From 40941fb2e9ae763add7b74850e8a0471ac754db6 Mon Sep 17 00:00:00 2001
+From: Peter Hutterer <peter.hutterer@who-t.net>
+Date: Thu, 1 Jul 2010 12:44:57 +1000
+Subject: [PATCH 5/5] xkb: release XTEST pointer buttons on physical releases. (#28808)
+
+If a button release event is posted for the MD pointer, post a release event
+through the matching XTEST device. This way, a client who posts a button
+press through the XTEST extension cannot inadvertedly lock the button.
+
+This behaviour is required for historical reasons, until server 1.7 the core
+pointer would release a button press on physical events, regardless of the
+XTEST state. Clients seem to rely on this behaviour, causing seemingly stuck
+grabs.
+
+The merged behaviour is kept for multiple keyboard PointerKey events, if two
+physical keyboards hold the button down as a result of PointerKey actions,
+the button is not released until the last keyboard releases the button.
+
+X.Org Bug 28808 <http://bugs.freedesktop.org/show_bug.cgi?id=28808>
+
+Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
+---
+ include/xkbsrv.h |    6 ++++++
+ xkb/xkbAccessX.c |   23 ++++++++++-------------
+ xkb/xkbActions.c |    4 ++--
+ 3 files changed, 18 insertions(+), 15 deletions(-)
+
+diff --git a/include/xkbsrv.h b/include/xkbsrv.h
+index d1cbd1a..a96ca56 100644
+--- a/include/xkbsrv.h
++++ b/include/xkbsrv.h
+@@ -923,6 +923,12 @@ extern int XkbGetEffectiveGroup(
+ extern void XkbMergeLockedPtrBtns(
+         DeviceIntPtr            /* master */);
++extern void XkbFakeDeviceButton(
++        DeviceIntPtr            /* dev */,
++        int                     /* press */,
++        int                     /* button */);
++
++
+ #include "xkbfile.h"
+ #include "xkbrules.h"
+diff --git a/xkb/xkbAccessX.c b/xkb/xkbAccessX.c
+index e3fdc06..d3f9652 100644
+--- a/xkb/xkbAccessX.c
++++ b/xkb/xkbAccessX.c
+@@ -710,19 +710,16 @@ DeviceEvent     *event = &ev->device_event;
+       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);
++            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);
++            }
+       }
+       changed |= XkbPointerButtonMask;
+diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c
+index 391c375..5d40199 100644
+--- a/xkb/xkbActions.c
++++ b/xkb/xkbActions.c
+@@ -46,7 +46,7 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ static int xkbDevicePrivateKeyIndex;
+ DevPrivateKey xkbDevicePrivateKey = &xkbDevicePrivateKeyIndex;
+-static void XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button);
++void XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button);
+ static void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y);
+ void
+@@ -1360,7 +1360,7 @@ XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags,int x,int y)
+     FreeEventList(events, GetMaximumEventsNum());
+ }
+-static void
++void
+ XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button)
+ {
+     EventListPtr        events;
+-- 
+1.7.1
+
+From 7273832bcdc6f43e9a5a8fdbb56844466efb710a Mon Sep 17 00:00:00 2001
+From: Peter Hutterer <peter.hutterer@who-t.net>
+Date: Fri, 23 Jul 2010 11:46:30 +1000
+Subject: [PATCH 1/3] xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
+
+commit 14327858391ebe929b806efb53ad79e789361883
+    xkb: release XTEST pointer buttons on physical releases. (#28808)
+revealed a bug with the XTEST/PointerKeys interaction.
+
+Events resulting from PointerKeys are injected into the event processing
+stream, not appended to the event queue. The events generated for the fake
+button press include a DeviceChangedEvent (DCE), a raw button event and the
+button event itself. The DCE causes the master to switch classes to the
+attached XTEST pointer device.
+
+Once the fake button is processed, normal event processing continues with
+events in the EQ. The master still contains the XTEST classes, causing some
+events to be dropped if e.g. the number of valuators of the event in the
+queue exceeds the XTEST device's number of valuators.
+
+Example: the EQ contains the following events, processed one-by-one, left to
+right.
+
+[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
+                  ^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
+
+Thus the event sequence processed looks like this:
+
+[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
+
+The first DCE causes the master to switch to the device. The button up event
+injects a DCE to the XTEST device, causing the following Motion events to be
+processed with the master still being on XTEST classes.
+
+This patch post-fixes the injected event sequence with a DCE to restore the
+classes of the original slave device, resulting in an event sequence like
+this:
+[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
+
+Note that this is a simplified description. The event sequence injected by
+the PointerKeys code is injected for the master device only and the matching
+slave device that caused the injection has already finished processing on
+the slave. Furthermore, the injection happens as part of the the XKB layer,
+before the unwrapping of the processInputProc takes us into the DIX where
+the DCE is actually handled.
+
+Bug reproducible with a device that reports more than 2 valuators. Simply
+cause button releases on the device and wait for a "too many valuators"
+warning message.
+
+Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
+---
+ xkb/xkbActions.c |   26 +++++++++++++++++++-------
+ 1 files changed, 19 insertions(+), 7 deletions(-)
+
+diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c
+index 5d40199..2afd46d 100644
+--- a/xkb/xkbActions.c
++++ b/xkb/xkbActions.c
+@@ -1365,34 +1365,46 @@ XkbFakeDeviceButton(DeviceIntPtr dev,Bool press,int button)
+ {
+     EventListPtr        events;
+     int                 nevents, i;
+-    DeviceIntPtr        ptr;
++    DeviceIntPtr        ptr, mpointer, lastSlave;
+     /* If dev is a slave device, and the SD is attached, do nothing. If we'd
+      * post through the attached master pointer we'd get duplicate events.
+      *
+      * if dev is a master keyboard, post through the XTEST device
+-     *
+      * if dev is a floating slave, post through the device itself.
++     *
++     * The event is injected into the event processing, not the EQ. Thus,
++     * ensure that we restore the master after the event sequence to the
++     * original set of classes. Otherwise, the master remains on the XTEST
++     * classes and drops events that don't fit into the XTEST layout (e.g.
++     * events with more than 2 valuators).
++     * To do so, we remember the lastSlave that posted through the master
++     * and add a DeviceChangedEvent to the end of the list.
+      */
+-    if (IsMaster(dev))
+-        ptr = GetXTestDevice(GetMaster(dev, MASTER_POINTER));
+-    else if (!dev->u.master)
++    if (IsMaster(dev)) {
++        mpointer = GetMaster(dev, MASTER_POINTER);
++        lastSlave = mpointer->u.lastSlave;
++        ptr = GetXTestDevice(mpointer);
++    } else if (!dev->u.master)
+         ptr = dev;
+     else
+         return;
+-    events = InitEventList(GetMaximumEventsNum());
++    events = InitEventList(GetMaximumEventsNum() + 1);
+     OsBlockSignals();
+     nevents = GetPointerEvents(events, ptr,
+                                press ? ButtonPress : ButtonRelease, button,
+                                0 /* flags */, 0 /* first */,
+                                0 /* num_val */, NULL);
++    if (IsMaster(dev) && (lastSlave && lastSlave != ptr))
++        CreateClassesChangedEvent(&events[nevents++], mpointer,
++                                  lastSlave, DEVCHANGE_POINTER_EVENT);
+     OsReleaseSignals();
+     for (i = 0; i < nevents; i++)
+         mieqProcessDeviceEvent(ptr, (InternalEvent*)events[i].event, NULL);
+-    FreeEventList(events, GetMaximumEventsNum());
++    FreeEventList(events, GetMaximumEventsNum() + 1);
+ }
+-- 
+1.7.2
+
+From 817e031a996a5f5aa16fc789d7e570cc589d96cb Mon Sep 17 00:00:00 2001
+From: Peter Hutterer <peter.hutterer@who-t.net>
+Date: Wed, 28 Jul 2010 14:24:59 +1000
+Subject: [PATCH 3/3] Xi: reset the unused classes pointer after copying
+
+After copying the unused_classes into the device, reset the original
+pointer. Otherwise we have two pointers pointing to the same field and both
+get freed on device removal.
+
+Some classes already have this behaviour since 51c8fd69.
+
+Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
+---
+ Xi/exevents.c |    6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/Xi/exevents.c b/Xi/exevents.c
+index 566b0ef..a6160dd 100644
+--- a/Xi/exevents.c
++++ b/Xi/exevents.c
+@@ -227,6 +227,7 @@ DeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to)
+             classes = dixLookupPrivate(&to->devPrivates,
+                                        UnusedClassesPrivateKey);
+             to->intfeed = classes->intfeed;
++            classes->intfeed = NULL;
+         }
+         i = &to->intfeed;
+@@ -263,6 +264,7 @@ DeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to)
+             classes = dixLookupPrivate(&to->devPrivates,
+                                        UnusedClassesPrivateKey);
+             to->stringfeed = classes->stringfeed;
++            classes->stringfeed = NULL;
+         }
+         s = &to->stringfeed;
+@@ -299,6 +301,7 @@ DeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to)
+             classes = dixLookupPrivate(&to->devPrivates,
+                                        UnusedClassesPrivateKey);
+             to->bell = classes->bell;
++            classes->bell = NULL;
+         }
+         b = &to->bell;
+@@ -336,6 +339,7 @@ DeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to)
+             classes = dixLookupPrivate(&to->devPrivates,
+                                        UnusedClassesPrivateKey);
+             to->leds = classes->leds;
++            classes->leds = NULL;
+         }
+         l = &to->leds;
+@@ -387,6 +391,7 @@ DeepCopyKeyboardClasses(DeviceIntPtr from, DeviceIntPtr to)
+             to->kbdfeed = classes->kbdfeed;
+             if (!to->kbdfeed)
+                 InitKeyboardDeviceStruct(to, NULL, NULL, NULL);
++            classes->kbdfeed = NULL;
+         }
+         k = &to->kbdfeed;
+@@ -517,6 +522,7 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
+             classes = dixLookupPrivate(&to->devPrivates,
+                                        UnusedClassesPrivateKey);
+             to->ptrfeed = classes->ptrfeed;
++            classes->ptrfeed = NULL;
+         }
+         p = &to->ptrfeed;
+-- 
+1.7.2
+