xserver: Branch 'mpx' - 54 commits

Peter Hutterer whot at kemper.freedesktop.org
Mon Nov 12 17:41:15 PST 2007


 Xext/geext.h                   |    6 
 Xi/Makefile.am                 |    4 
 Xi/chdevhier.c                 |  241 +++++++++++++++++++
 Xi/chdevhier.h                 |   45 +++
 Xi/exevents.c                  |   51 +++-
 Xi/extinit.c                   |   74 ++++--
 Xi/getpairp.c                  |   15 -
 Xi/listdev.c                   |   50 ++--
 Xi/listdev.h                   |    8 
 Xi/opendev.c                   |    4 
 Xi/setcptr.c                   |   20 -
 dix/devices.c                  |  500 ++++++++++++++++++++++++++++-------------
 dix/events.c                   |  176 ++++++++++----
 dix/getevents.c                |  173 ++++++++++----
 dix/window.c                   |    7 
 hw/xfree86/common/xf86DGA.c    |    4 
 hw/xfree86/common/xf86Xinput.c |   13 -
 hw/xfree86/common/xf86Xinput.h |    1 
 include/input.h                |   14 -
 include/inputstr.h             |   10 
 mi/midispcur.c                 |    2 
 mi/mieq.c                      |   95 +++++++
 mi/mipointer.c                 |   67 ++++-
 mi/misprite.c                  |   48 +++
 xkb/xkbActions.c               |    2 
 xkb/xkbPrKeyEv.c               |    2 
 xkb/xkbUtils.c                 |    5 
 27 files changed, 1269 insertions(+), 368 deletions(-)

New commits:
commit 51239f87ce42ad564ceee1761980391947294511
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Nov 13 11:26:16 2007 +1030

    dix: Send MappingNotify when keyboard maps change.
    
    If a slave device is attached to a master device, then we need to send a
    mapping notify to the client.
    Mapping notify needs to be sent if
     - different slave device but on same master
     - different master
    
    This gives you funny behaviour with the ClientPointer. When a
    MappingNotify is sent to the client, the client usually responds with a
    GetKeyboardMapping. This will retrieve the ClientPointer's keyboard mapping,
    regardless of which keyboard sent the last mapping notify request. So
    depending on the CP setting, your keyboard may change layout in each app...

diff --git a/dix/getevents.c b/dix/getevents.c
index d9adadf..b0211b6 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -867,63 +867,57 @@ GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type,
 
 
 /**
- * Note that pDev was the last device to send a core event.  This function
- * copies the complete keymap from the originating device to the core
- * device, and makes sure the appropriate notifications are generated.
+ * pDev is the slave device that is about to send an event. If it is attached
+ * to a master device, then we need to send a mapping notify to the client.
+ * To do so, we need to remember the last master device that sent a mapping
+ * event.
+ *
+ * Mapping notify needs to be sent in the following cases:
+ *      - different slave device on same master
+ *      - different master
  *
  * Call this just before processInputProc.
+ *
+ * XXX: They way how the code is we also send a map notify if the slave device
+ * stays the same, but the master changes. This isn't really necessary though.
+ *
+ * XXX: this gives you funny behaviour with the ClientPointer. When a
+ * MappingNotify is sent to the client, the client usually responds with a
+ * GetKeyboardMapping. This will retrieve the ClientPointer's keyboard
+ * mapping, regardless of which keyboard sent the last mapping notify request.
+ * So depending on the CP setting, your keyboard may change layout in each
+ * app...
  */
 _X_EXPORT void
 SwitchCoreKeyboard(DeviceIntPtr pDev)
 {
-    KeyClassPtr ckeyc = inputInfo.keyboard->key;
+    static DeviceIntPtr lastMapNotifyDevice = NULL;
+    DeviceIntPtr master;
+    KeyClassPtr ckeyc;
     int i = 0;
+    BOOL sendNotify = FALSE;
 
-    if (inputInfo.keyboard->devPrivates[CoreDevicePrivatesIndex].ptr != pDev) {
-        memcpy(ckeyc->modifierMap, pDev->key->modifierMap, MAP_LENGTH);
-        if (ckeyc->modifierKeyMap)
-            xfree(ckeyc->modifierKeyMap);
-        ckeyc->modifierKeyMap = xalloc(8 * pDev->key->maxKeysPerModifier);
-        memcpy(ckeyc->modifierKeyMap, pDev->key->modifierKeyMap,
-                (8 * pDev->key->maxKeysPerModifier));
-
-        ckeyc->maxKeysPerModifier = pDev->key->maxKeysPerModifier;
-        ckeyc->curKeySyms.minKeyCode = pDev->key->curKeySyms.minKeyCode;
-        ckeyc->curKeySyms.maxKeyCode = pDev->key->curKeySyms.maxKeyCode;
-        SetKeySymsMap(&ckeyc->curKeySyms, &pDev->key->curKeySyms);
-
-        /*
-         * Copy state from the extended keyboard to core.  If you omit this,
-         * holding Ctrl on keyboard one, and pressing Q on keyboard two, will
-         * cause your app to quit.  This feels wrong to me, hence the below
-         * code.
-         *
-         * XXX: If you synthesise core modifier events, the state will get
-         *      clobbered here.  You'll have to work out something sensible
-         *      to fix that.  Good luck.
-         */
-
-#define KEYBOARD_MASK (ShiftMask | LockMask | ControlMask | Mod1Mask | \
-                       Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)
-        ckeyc->state &= ~(KEYBOARD_MASK);
-        ckeyc->state |= (pDev->key->state & KEYBOARD_MASK);
-#undef KEYBOARD_MASK
-        for (i = 0; i < 8; i++)
-            ckeyc->modifierKeyCount[i] = pDev->key->modifierKeyCount[i];
+    if (pDev->isMaster || !pDev->u.master)
+        return;
 
-#ifdef XKB
-        if (!noXkbExtension && pDev->key->xkbInfo && pDev->key->xkbInfo->desc) {
-            if (!XkbCopyKeymap(pDev->key->xkbInfo->desc, ckeyc->xkbInfo->desc,
-                               True))
-                FatalError("Couldn't pivot keymap from device to core!\n");
-        }
-#endif
+    master = pDev->u.master;
+    ckeyc = master->key;
+
+    if (master->devPrivates[CoreDevicePrivatesIndex].ptr != pDev) {
+        master->devPrivates[CoreDevicePrivatesIndex].ptr = pDev;
+        sendNotify = TRUE;
+    }
+
+    if (lastMapNotifyDevice != master)
+        sendNotify = TRUE;
 
+    if (sendNotify)
+    {
         SendMappingNotify(pDev, MappingKeyboard, ckeyc->curKeySyms.minKeyCode,
                           (ckeyc->curKeySyms.maxKeyCode -
                            ckeyc->curKeySyms.minKeyCode),
                           serverClient);
-        inputInfo.keyboard->devPrivates[CoreDevicePrivatesIndex].ptr = pDev;
+        lastMapNotifyDevice = master;
     }
 }
 
diff --git a/mi/mieq.c b/mi/mieq.c
index f0af4b0..11439cf 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -335,8 +335,9 @@ mieqProcessInputEvents(void)
             if ((e->events->event[0].u.u.type == DeviceKeyPress ||
                 e->events->event[0].u.u.type == DeviceKeyRelease ||
                 e->events->event[0].u.u.type == KeyPress ||
-                e->events->event[0].u.u.type == KeyRelease) && 
-                    e->pDev->coreEvents) {
+                e->events->event[0].u.u.type == KeyRelease) &&
+                    !e->pDev->isMaster)
+            {
                 SwitchCoreKeyboard(e->pDev);
             }
 
diff --git a/xkb/xkbUtils.c b/xkb/xkbUtils.c
index e87064a..d49a3c6 100644
--- a/xkb/xkbUtils.c
+++ b/xkb/xkbUtils.c
@@ -935,7 +935,10 @@ XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies)
     xkbMapNotify mn;
     xkbNewKeyboardNotify nkn;
 
-    if (!src || !dst || src == dst)
+    if (src == dst)
+        return TRUE;
+
+    if (!src || !dst)
         return FALSE;
 
     /* client map */
commit 2b1d946392ce28b96941341778b2b526aa0fb126
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Nov 13 09:51:33 2007 +1030

    xkb: disable xkb key repeats (temporarily)
    
    Haven't quite figured out yet how to make these repeats work. Because we share
    the class between devices, the key state is already set when we process the
    master device's event, causing a repeat on each event.

diff --git a/xkb/xkbPrKeyEv.c b/xkb/xkbPrKeyEv.c
index f007f75..147df3e 100644
--- a/xkb/xkbPrKeyEv.c
+++ b/xkb/xkbPrKeyEv.c
@@ -76,6 +76,7 @@ int             xiEvent;
     if ((behavior.type&XkbKB_Permanent)==0) {
 	switch (behavior.type) {
 	    case XkbKB_Default:
+#if 0
 		if (( xE->u.u.type == KeyPress || 
                             xE->u.u.type == DeviceKeyPress) && 
 		    (keyc->down[key>>3] & (1<<(key&7)))) {
@@ -112,6 +113,7 @@ int             xiEvent;
 		    XkbLastRepeatEvent= NULL;
 		    return;
 		}
+#endif
 		break;
 	    case XkbKB_Lock:
 		if ( xE->u.u.type == KeyRelease || 
commit 70b4087c4dd1904d9d655f4afb9dfcea4f137f7a
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Mon Nov 12 13:10:39 2007 +1030

    dix: don't unconditionally update valuators during key events.
    
    Master may not have valuators, device may not have valuators.

diff --git a/dix/getevents.c b/dix/getevents.c
index e366d22..d9adadf 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -485,8 +485,11 @@ GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type,
     {
         CreateClassesChangedEvent(events, master, pDev);
 
-        pDev->valuator->lastx = master->valuator->lastx;
-        pDev->valuator->lasty = master->valuator->lasty;
+        if (master->valuator && pDev->valuator)
+        {
+            pDev->valuator->lastx = master->valuator->lastx;
+            pDev->valuator->lasty = master->valuator->lasty;
+        }
         master->u.lastSlave = pDev;
         numEvents++;
         events++;
commit 23365d28651f7942fdafb889bcbbd019470a4274
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Mon Nov 12 13:08:38 2007 +1030

    dix: allow grab modifier device to be NULL.
    
    This can happen if we check for a passive core grab and our device is a
    floating slave device. Doesn't really change anything as SDs can't send core
    events but it stops the server from segfaulting.

diff --git a/dix/events.c b/dix/events.c
index c3589f0..daebe35 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -3379,7 +3379,7 @@ CheckPassiveGrabsOnWindow(
     {
 #ifdef XKB
 	DeviceIntPtr	gdev;
-	XkbSrvInfoPtr	xkbi;
+	XkbSrvInfoPtr	xkbi = NULL;
 
 	gdev= grab->modifierDevice;
         if (grab->coreGrab)
@@ -3389,7 +3389,8 @@ CheckPassiveGrabsOnWindow(
             else
                 gdev = device;
         }
-	xkbi= gdev->key->xkbInfo;
+        if (gdev)
+            xkbi= gdev->key->xkbInfo;
 #endif
 	tempGrab.modifierDevice = grab->modifierDevice;
 	if ((device == grab->modifierDevice) &&
@@ -3400,16 +3401,20 @@ CheckPassiveGrabsOnWindow(
 	     ))
 	    tempGrab.modifiersDetail.exact =
 #ifdef XKB
-		(noXkbExtension?gdev->key->prev_state:xkbi->state.grab_mods);
+                (noXkbExtension) ?
+                        ((gdev) ? gdev->key->prev_state : 0) :
+                        ((xkbi) ?  xkbi->state.grab_mods : 0);
 #else
-		grab->modifierDevice->key->prev_state;
+                (gdev) ? gdev->key->prev_state : 0;
 #endif
 	else
 	    tempGrab.modifiersDetail.exact =
 #ifdef XKB
-		(noXkbExtension ? gdev->key->state : xkbi->state.grab_mods);
+                (noXkbExtension) ?
+                        ((gdev) ? gdev->key->state : 0) :
+                        ((xkbi) ? xkbi->state.grab_mods : 0);
 #else
-		grab->modifierDevice->key->state;
+                (gdev) ? gdev->key->state : 0;
 #endif
             /* ignore the device for core events when comparing grabs */
 	if (GrabMatchesSecond(&tempGrab, grab, (xE->u.u.type < LASTEvent)) &&
commit 5a7a65a3c978a65e8ff39d0cc9878527ec42adc9
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Mon Nov 12 12:37:39 2007 +1030

    mi: avoid SIGABRT by setting master_event to NULL.

diff --git a/mi/mieq.c b/mi/mieq.c
index 7ea12fe..f0af4b0 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -363,7 +363,8 @@ mieqProcessInputEvents(void)
             {
                 CopyGetMasterEvent(e->pDev->u.master, event,
                                    &master_event, e->nevents);
-            }
+            } else
+                master_event = NULL;
 
             /* process slave first, then master */
             e->pDev->public.processInputProc(event, e->pDev, e->nevents);
commit a05f43bf3e9629df98e93c366d4327f20ed81e6c
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Mon Nov 12 11:35:18 2007 +1030

    dix: When the last slave is removed, set master to the original classes.
    
    DeviceClassesChangedEvent is sent to the client, where device == new slave.

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 617aef7..3ef3200 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -162,25 +162,10 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
 
         /* event is already correct size, see comment in GetPointerEvents */
         classbuff = (char*)&xE[1];
-        if (master->key) 
-        {
-            /* we don't actually swap here, swapping is done later */
-            CopySwapKeyClass(NullClient, master->key, &classbuff);
-            dcce->num_classes++;
-        }
-        if (master->button) 
-        {
-            CopySwapButtonClass(NullClient, master->button, &classbuff);
-            dcce->num_classes++;
-        }
-        if (master->valuator)
-        {
-            CopySwapValuatorClass(NullClient, master->valuator, &classbuff);
-            dcce->num_classes++;
-        }
-
-        SendEventToAllWindows(master, XI_DeviceClassesChangedMask,
-                              xE, 1);
+        /* we don't actually swap if there's a NullClient, swapping is done
+         * later when event is delivered. */
+        CopySwapClasses(NullClient, master, &dcce->num_classes, &classbuff);
+        SendEventToAllWindows(master, XI_DeviceClassesChangedMask, xE, 1);
         return;
     }
 
diff --git a/Xi/listdev.c b/Xi/listdev.c
index 962998e..1810c9b 100644
--- a/Xi/listdev.c
+++ b/Xi/listdev.c
@@ -142,7 +142,7 @@ CopyDeviceName(char **namebuf, char *name)
  *
  */
 
-void
+static void
 CopySwapButtonClass(ClientPtr client, ButtonClassPtr b, char **buf)
 {
     char n;
@@ -201,7 +201,7 @@ CopySwapDevice(ClientPtr client, DeviceIntPtr d, int num_classes,
  *
  */
 
-void
+static void
 CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf)
 {
     char n;
@@ -231,7 +231,7 @@ CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf)
  *
  */
 
-int
+static int
 CopySwapValuatorClass(ClientPtr client, ValuatorClassPtr v, char **buf)
 {
     int i, j, axes, t_axes;
@@ -286,17 +286,24 @@ ListDeviceInfo(ClientPtr client, DeviceIntPtr d, xDeviceInfoPtr dev,
 {
     CopyDeviceName(namebuf, d->name);
     CopySwapDevice(client, d, 0, devbuf);
-    if (d->key != NULL) {
-	CopySwapKeyClass(client, d->key, classbuf);
-	dev->num_classes++;
+    CopySwapClasses(client, d, &dev->num_classes, classbuf);
+}
+
+void
+CopySwapClasses(ClientPtr client, DeviceIntPtr dev, CARD8 *num_classes,
+                char** classbuf)
+{
+    if (dev->key != NULL) {
+	CopySwapKeyClass(client, dev->key, classbuf);
+	(*num_classes)++;
     }
-    if (d->button != NULL) {
-	CopySwapButtonClass(client, d->button, classbuf);
-	dev->num_classes++;
+    if (dev->button != NULL) {
+	CopySwapButtonClass(client, dev->button, classbuf);
+	(*num_classes)++;
     }
-    if (d->valuator != NULL) {
-	dev->num_classes +=
-	    CopySwapValuatorClass(client, d->valuator, classbuf);
+    if (dev->valuator != NULL) {
+	(*num_classes) +=
+	    CopySwapValuatorClass(client, dev->valuator, classbuf);
     }
 }
 
diff --git a/Xi/listdev.h b/Xi/listdev.h
index afdcd69..22a0d91 100644
--- a/Xi/listdev.h
+++ b/Xi/listdev.h
@@ -44,15 +44,9 @@ void SRepXListInputDevices(ClientPtr /* client */ ,
     );
 
 void
-CopySwapKeyClass(ClientPtr /* client */, 
-                 KeyClassPtr /* k */, 
-                 char** /* buf */);
-void
-CopySwapButtonClass(ClientPtr /* client */, 
-                    ButtonClassPtr /* b */, 
-                    char** /* buf */);
-int
-CopySwapValuatorClass(ClientPtr /* client */, 
-                      ValuatorClassPtr /* v */, 
-                      char** /* buf */);
+CopySwapClasses(ClientPtr /* client */,
+                DeviceIntPtr /* dev */,
+                CARD8* /* num_classes */,
+                char** /* classbuf */);
+
 #endif /* LISTDEV_H */
diff --git a/dix/devices.c b/dix/devices.c
index b423378..2c6d3e1 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -79,6 +79,7 @@ SOFTWARE.
 #include <X11/extensions/XIproto.h>
 #include "exglobals.h"
 #include "exevents.h"
+#include "listdev.h" /* for CopySwapXXXClass */
 
 /** @file
  * This file handles input device-related stuff.
@@ -2314,9 +2315,50 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
      */
     if (!master)
     {
+        DeviceIntPtr it;
                               /* current root window */
         InitializeSprite(dev, dev->spriteInfo->sprite->spriteTrace[0]);
         dev->spriteInfo->spriteOwner = FALSE;
+
+        /* the master may need to restore the original classes, search for a
+         * device that is still paired with our master. */
+        for (it = inputInfo.devices; it; it = it->next)
+            if (!it->isMaster && it->u.master == master)
+                break;
+
+        if (!it)  /* no dev is paired with our master */
+        {
+            ClassesPtr classes;
+            EventList event = { NULL, 0};
+            char* classbuf;
+
+            classes = master->devPrivates[MasterDevClassesPrivIdx].ptr;
+            master->key = classes->key;
+            master->valuator = classes->valuator;
+            master->button = classes->button;
+            master->focus = classes->focus;
+            master->proximity = classes->proximity;
+            master->absolute = classes->absolute;
+            master->kbdfeed = classes->kbdfeed;
+            master->ptrfeed = classes->ptrfeed;
+            master->intfeed = classes->intfeed;
+            master->stringfeed = classes->stringfeed;
+            master->bell = classes->bell;
+            master->leds = classes->leds;
+
+            /* Send event to clients */
+            CreateClassesChangedEvent(&event, master, master);
+            deviceClassesChangedEvent *dcce = 
+                        (deviceClassesChangedEvent*)event.event;
+            dcce->deviceid = master->id;
+            dcce->num_classes = 0;
+            classbuf = (char*)&event.event[1];
+            CopySwapClasses(NullClient, master, &dcce->num_classes, &classbuf);
+            SendEventToAllWindows(master, XI_DeviceClassesChangedMask, 
+                    event.event, 1);
+            xfree(event.event);
+        }
+
     } else
         dev->spriteInfo->sprite = master->spriteInfo->sprite;
 
diff --git a/dix/getevents.c b/dix/getevents.c
index 425b602..e366d22 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -111,7 +111,7 @@ key_autorepeats(DeviceIntPtr pDev, int key_code)
               (1 << (key_code & 7)));
 }
 
-static void
+void
 CreateClassesChangedEvent(EventList* event, 
                           DeviceIntPtr master, 
                           DeviceIntPtr slave)
diff --git a/include/input.h b/include/input.h
index d6a38e6..dbf6aee 100644
--- a/include/input.h
+++ b/include/input.h
@@ -402,6 +402,9 @@ extern int GetMaximumEventsNum(void);
 extern EventListPtr InitEventList(int num_events);
 extern void FreeEventList(EventListPtr list, int num_events);
 
+extern void CreateClassesChangedEvent(EventListPtr event, 
+                                      DeviceIntPtr master,
+                                      DeviceIntPtr slave);
 extern int GetPointerEvents(
     EventListPtr events,
     DeviceIntPtr pDev,
commit 7a81bafc9bc7048560b17483e6addf58469a05d0
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Fri Nov 9 23:10:24 2007 +1030

    Xi, dix: Add ability to change MD classes + send event when doing so.
    
    Each time a different slave device sends through a master, an
    DeviceClassesChangedEvent is enqueued. When this event is processed, all
    classes of the matching master device are changed, and the event is sent to
    the clients.
    
    Next time the master is queried, it thus shows the evclasses of the last slave
    device. The original classes are stored in the devPrivates.
    
    TODO: if all slave devices are removed, the master's original classes need to
    be restored.

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 4c57fd0..617aef7 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -73,6 +73,7 @@ SOFTWARE.
 #include "dixevents.h"	/* DeliverFocusedEvent */
 #include "dixgrabs.h"	/* CreateGrab() */
 #include "scrnintstr.h"
+#include "listdev.h" /* for CopySwapXXXClass */
 
 #ifdef XKB
 #include "xkbsrv.h"
@@ -127,6 +128,62 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
     xEvent core;
     int coretype = 0;
 
+    /* This event is always the first we get, before the actual events with
+     * the data. However, the way how the DDX is set up, "device" will
+     * actually be the slave device that caused the event.
+     */
+    if (GEIsType(xE, IReqCode, XI_DeviceClassesChangedNotify))
+    {
+        deviceClassesChangedEvent* dcce = (deviceClassesChangedEvent*)xE;
+        DeviceIntPtr master = device->u.master;
+        char* classbuff;
+
+        if (device->isMaster)
+            return;
+
+        if (!master) /* if device was set floating between SIGIO and now */
+            return;
+
+        dcce->deviceid     = master->id;
+        dcce->num_classes  = 0;
+
+        master->key        = device->key;
+        master->valuator   = device->valuator;
+        master->button     = device->button;
+        master->focus      = device->focus;
+        master->proximity  = device->proximity;
+        master->absolute   = device->absolute;
+        master->kbdfeed    = device->kbdfeed;
+        master->ptrfeed    = device->ptrfeed;
+        master->intfeed    = device->intfeed;
+        master->stringfeed = device->stringfeed;
+        master->bell       = device->bell;
+        master->leds       = device->leds;
+
+        /* event is already correct size, see comment in GetPointerEvents */
+        classbuff = (char*)&xE[1];
+        if (master->key) 
+        {
+            /* we don't actually swap here, swapping is done later */
+            CopySwapKeyClass(NullClient, master->key, &classbuff);
+            dcce->num_classes++;
+        }
+        if (master->button) 
+        {
+            CopySwapButtonClass(NullClient, master->button, &classbuff);
+            dcce->num_classes++;
+        }
+        if (master->valuator)
+        {
+            CopySwapValuatorClass(NullClient, master->valuator, &classbuff);
+            dcce->num_classes++;
+        }
+
+        SendEventToAllWindows(master, XI_DeviceClassesChangedMask,
+                              xE, 1);
+        return;
+    }
+
     coretype = XItoCoreType(xE->u.u.type);
     if (device->isMaster && device->coreEvents && coretype)
         sendCore = TRUE;
diff --git a/Xi/extinit.c b/Xi/extinit.c
index 0ecb421..017b693 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -703,6 +703,53 @@ SRawDeviceEvent(rawDeviceEvent* from, rawDeviceEvent *to)
         swapl(valptr, n);
 }
 
+static void
+SDeviceClassesChangedEvent(deviceClassesChangedEvent* from, 
+                           deviceClassesChangedEvent* to)
+{
+    char n;
+    int i, j;
+    xAnyClassPtr any;
+
+    *to = *from;
+    memcpy(&to[1], &from[1], from->length * 4);
+
+    swaps(&to->sequenceNumber, n);
+    swapl(&to->length, n);
+    swapl(&to->time, n);
+    
+    /* now swap the actual classes */
+    any = (xAnyClassPtr)&to[1];
+    for (i = 0; i < to->num_classes; i++)
+    {
+        switch(any->class)
+        {
+            case KeyClass:
+                swaps(&((xKeyInfoPtr)any)->num_keys, n);
+                break;
+            case ButtonClass:
+                swaps(&((xButtonInfoPtr)any)->num_buttons, n);
+                break;
+            case ValuatorClass:
+                {
+                    xValuatorInfoPtr v = (xValuatorInfoPtr)any;
+                    xAxisInfoPtr a = (xAxisInfoPtr)&v[1];
+
+                    swapl(&v->motion_buffer_size, n);
+                    for (j = 0; j < v->num_axes; j++)
+                    {
+                        swapl(&a->min_value, n);
+                        swapl(&a->max_value, n);
+                        swapl(&a->resolution, n);
+                        a++;
+                    }
+                }
+                break;
+        }
+        any = (xAnyClassPtr)((char*)any + any->length);
+    }
+}
+
 /**************************************************************************
  *
  * Allow the specified event to have its propagation suppressed.
@@ -1153,6 +1200,10 @@ XIGEEventSwap(xGenericEvent* from, xGenericEvent* to)
         case XI_RawDeviceEvent:
             SRawDeviceEvent((rawDeviceEvent*)from, (rawDeviceEvent*)to);
             break;
+        case XI_DeviceClassesChangedNotify:
+            SDeviceClassesChangedEvent((deviceClassesChangedEvent*)from, 
+                                       (deviceClassesChangedEvent*)to);
+            break;
     }
 }
 
diff --git a/Xi/listdev.c b/Xi/listdev.c
index 8753b29..962998e 100644
--- a/Xi/listdev.c
+++ b/Xi/listdev.c
@@ -68,7 +68,6 @@ SOFTWARE.
 
 #include "listdev.h"
 
-#define VPC	20	/* Max # valuators per chunk */
 
 /***********************************************************************
  *
@@ -143,7 +142,7 @@ CopyDeviceName(char **namebuf, char *name)
  *
  */
 
-static void
+void
 CopySwapButtonClass(ClientPtr client, ButtonClassPtr b, char **buf)
 {
     char n;
@@ -153,7 +152,7 @@ CopySwapButtonClass(ClientPtr client, ButtonClassPtr b, char **buf)
     b2->class = ButtonClass;
     b2->length = sizeof(xButtonInfo);
     b2->num_buttons = b->numButtons;
-    if (client->swapped) {
+    if (client && client->swapped) {
 	swaps(&b2->num_buttons, n);	/* macro - braces are required */
     }
     *buf += sizeof(xButtonInfo);
@@ -202,7 +201,7 @@ CopySwapDevice(ClientPtr client, DeviceIntPtr d, int num_classes,
  *
  */
 
-static void
+void
 CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf)
 {
     char n;
@@ -214,7 +213,7 @@ CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf)
     k2->min_keycode = k->curKeySyms.minKeyCode;
     k2->max_keycode = k->curKeySyms.maxKeyCode;
     k2->num_keys = k2->max_keycode - k2->min_keycode + 1;
-    if (client->swapped) {
+    if (client && client->swapped) {
 	swaps(&k2->num_keys, n);
     }
     *buf += sizeof(xKeyInfo);
@@ -232,7 +231,7 @@ CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf)
  *
  */
 
-static int
+int
 CopySwapValuatorClass(ClientPtr client, ValuatorClassPtr v, char **buf)
 {
     int i, j, axes, t_axes;
@@ -252,7 +251,7 @@ CopySwapValuatorClass(ClientPtr client, ValuatorClassPtr v, char **buf)
 	v2->num_axes = t_axes;
 	v2->mode = v->mode & DeviceMode;
 	v2->motion_buffer_size = v->numMotionEvents;
-	if (client->swapped) {
+	if (client && client->swapped) {
 	    swapl(&v2->motion_buffer_size, n);
 	}
 	*buf += sizeof(xValuatorInfo);
@@ -262,7 +261,7 @@ CopySwapValuatorClass(ClientPtr client, ValuatorClassPtr v, char **buf)
 	    a2->min_value = a->min_value;
 	    a2->max_value = a->max_value;
 	    a2->resolution = a->resolution;
-	    if (client->swapped) {
+	    if (client && client->swapped) {
 		swapl(&a2->min_value, n);
 		swapl(&a2->max_value, n);
 		swapl(&a2->resolution, n);
diff --git a/Xi/listdev.h b/Xi/listdev.h
index db376de..afdcd69 100644
--- a/Xi/listdev.h
+++ b/Xi/listdev.h
@@ -30,6 +30,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #ifndef LISTDEV_H
 #define LISTDEV_H 1
 
+#define VPC	20	/* Max # valuators per chunk */
+
 int SProcXListInputDevices(ClientPtr	/* client */
     );
 
@@ -41,4 +43,16 @@ void SRepXListInputDevices(ClientPtr /* client */ ,
 			   xListInputDevicesReply *	/* rep */
     );
 
+void
+CopySwapKeyClass(ClientPtr /* client */, 
+                 KeyClassPtr /* k */, 
+                 char** /* buf */);
+void
+CopySwapButtonClass(ClientPtr /* client */, 
+                    ButtonClassPtr /* b */, 
+                    char** /* buf */);
+int
+CopySwapValuatorClass(ClientPtr /* client */, 
+                      ValuatorClassPtr /* v */, 
+                      char** /* buf */);
 #endif /* LISTDEV_H */
diff --git a/dix/devices.c b/dix/devices.c
index c9831ea..b423378 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -84,8 +84,25 @@ SOFTWARE.
  * This file handles input device-related stuff.
  */
 
+typedef struct {
+    KeyClassPtr		key;
+    ValuatorClassPtr	valuator;
+    ButtonClassPtr	button;
+    FocusClassPtr	focus;
+    ProximityClassPtr	proximity;
+    AbsoluteClassPtr    absolute;
+    KbdFeedbackPtr	kbdfeed;
+    PtrFeedbackPtr	ptrfeed;
+    IntegerFeedbackPtr	intfeed;
+    StringFeedbackPtr	stringfeed;
+    BellFeedbackPtr	bell;
+    LedFeedbackPtr	leds;
+} ClassesRec, *ClassesPtr;
+
+
 int CoreDevicePrivatesIndex = 0;
 static int CoreDevicePrivatesGeneration = -1;
+int MasterDevClassesPrivIdx = -1;
 
 /* The client that is allowed to change pointer-keyboard pairings. */
 static ClientPtr pairingClient = NULL;
@@ -385,9 +402,16 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what)
 #ifdef XKB
     XkbComponentNamesRec names;
 #endif
+    ClassesPtr classes;
 
     switch (what) {
     case DEVICE_INIT:
+        if (MasterDevClassesPrivIdx == -1)
+            MasterDevClassesPrivIdx = AllocateDevicePrivateIndex();
+
+        if (!AllocateDevicePrivate(pDev, MasterDevClassesPrivIdx) ||
+                !(classes = xcalloc(1, sizeof(ClassesRec))))
+
         keySyms.minKeyCode = 8;
         keySyms.maxKeyCode = 255;
         keySyms.mapWidth = 4;
@@ -425,6 +449,19 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what)
         xfree(keySyms.map);
         xfree(modMap);
 
+        classes->key = pDev->key;
+        classes->valuator = pDev->valuator;
+        classes->button = pDev->button;
+        classes->focus = pDev->focus;
+        classes->proximity = pDev->proximity;
+        classes->absolute = pDev->absolute;
+        classes->kbdfeed = pDev->kbdfeed;
+        classes->ptrfeed = pDev->ptrfeed;
+        classes->intfeed = pDev->intfeed;
+        classes->stringfeed = pDev->stringfeed;
+        classes->bell = pDev->bell;
+        classes->leds = pDev->leds;
+        pDev->devPrivates[MasterDevClassesPrivIdx].ptr = classes;
         break;
 
     case DEVICE_CLOSE:
@@ -439,15 +476,27 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what)
 
 /**
  * Device control function for the Virtual Core Pointer.
+ * 
+ * Aside from initialisation, it backs up the original device classes into the
+ * devicePrivates. This only needs to be done for master devices.
  */
 static int
 CorePointerProc(DeviceIntPtr pDev, int what)
 {
     BYTE map[33];
     int i = 0;
+    ClassesPtr classes;
+
 
     switch (what) {
     case DEVICE_INIT:
+        if (MasterDevClassesPrivIdx == -1)
+            MasterDevClassesPrivIdx = AllocateDevicePrivateIndex();
+
+        if (!AllocateDevicePrivate(pDev, MasterDevClassesPrivIdx) || 
+                !(classes = xcalloc(1, sizeof(ClassesRec))))
+            return BadAlloc;
+
         for (i = 1; i <= 32; i++)
             map[i] = i;
         InitPointerDeviceStruct((DevicePtr)pDev, map, 32,
@@ -457,6 +506,21 @@ CorePointerProc(DeviceIntPtr pDev, int what)
         pDev->valuator->lastx = pDev->valuator->axisVal[0];
         pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
         pDev->valuator->lasty = pDev->valuator->axisVal[1];
+
+        classes->key = pDev->key;
+        classes->valuator = pDev->valuator;
+        classes->button = pDev->button;
+        classes->focus = pDev->focus;
+        classes->proximity = pDev->proximity;
+        classes->absolute = pDev->absolute;
+        classes->kbdfeed = pDev->kbdfeed;
+        classes->ptrfeed = pDev->ptrfeed;
+        classes->intfeed = pDev->intfeed;
+        classes->stringfeed = pDev->stringfeed;
+        classes->bell = pDev->bell;
+        classes->leds = pDev->leds;
+
+        pDev->devPrivates[MasterDevClassesPrivIdx].ptr = classes;
         break;
 
     case DEVICE_CLOSE:
@@ -574,6 +638,7 @@ CloseDevice(DeviceIntPtr dev)
     BellFeedbackPtr b, bnext;
     LedFeedbackPtr l, lnext;
     ScreenPtr screen = screenInfo.screens[0];
+    ClassesPtr classes;
     int j;
 
     if (!dev)
@@ -588,41 +653,46 @@ CloseDevice(DeviceIntPtr dev)
 
     xfree(dev->name);
 
-    if (dev->key) {
+    if (dev->isMaster)
+        classes = (ClassesPtr)dev->devPrivates[MasterDevClassesPrivIdx].ptr;
+    else 
+        classes = (ClassesPtr)&dev->key;
+
+    if (classes->key) {
 #ifdef XKB
-	if (dev->key->xkbInfo)
-	    XkbFreeInfo(dev->key->xkbInfo);
+	if (classes->key->xkbInfo)
+	    XkbFreeInfo(classes->key->xkbInfo);
 #endif
-	xfree(dev->key->curKeySyms.map);
-	xfree(dev->key->modifierKeyMap);
-	xfree(dev->key);
+	xfree(classes->key->curKeySyms.map);
+	xfree(classes->key->modifierKeyMap);
+	xfree(classes->key);
     }
 
-    if (dev->valuator) {
+    if (classes->valuator) {
         /* Counterpart to 'biggest hack ever' in init. */
-        if (dev->valuator->motion &&
-            dev->valuator->GetMotionProc == GetMotionHistory)
-            xfree(dev->valuator->motion);
-        xfree(dev->valuator);
+        if (classes->valuator->motion &&
+            classes->valuator->GetMotionProc == GetMotionHistory)
+            xfree(classes->valuator->motion);
+        xfree(classes->valuator);
     }
 
-    if (dev->button) {
+    if (classes->button) {
 #ifdef XKB
-        if (dev->button->xkb_acts)
-            xfree(dev->button->xkb_acts);
+        if (classes->button->xkb_acts)
+            xfree(classes->button->xkb_acts);
 #endif
-        xfree(dev->button);
+        xfree(classes->button);
     }
 
-    if (dev->focus) {
-	xfree(dev->focus->trace);
-	xfree(dev->focus);
+    if (classes->focus) {
+	xfree(classes->focus->trace);
+	xfree(classes->focus);
     }
 
-    if (dev->proximity)
-        xfree(dev->proximity);
+    if (classes->proximity)
+        xfree(classes->proximity);
 
-    for (k = dev->kbdfeed; k; k = knext) {
+    for (k = classes->kbdfeed; k; k = knext) {
 	knext = k->next;
 #ifdef XKB
 	if (k->xkb_sli)
@@ -631,29 +701,29 @@ CloseDevice(DeviceIntPtr dev)
 	xfree(k);
     }
 
-    for (p = dev->ptrfeed; p; p = pnext) {
+    for (p = classes->ptrfeed; p; p = pnext) {
 	pnext = p->next;
 	xfree(p);
     }
     
-    for (i = dev->intfeed; i; i = inext) {
+    for (i = classes->intfeed; i; i = inext) {
 	inext = i->next;
 	xfree(i);
     }
 
-    for (s = dev->stringfeed; s; s = snext) {
+    for (s = classes->stringfeed; s; s = snext) {
 	snext = s->next;
 	xfree(s->ctrl.symbols_supported);
 	xfree(s->ctrl.symbols_displayed);
 	xfree(s);
     }
 
-    for (b = dev->bell; b; b = bnext) {
+    for (b = classes->bell; b; b = bnext) {
 	bnext = b->next;
 	xfree(b);
     }
 
-    for (l = dev->leds; l; l = lnext) {
+    for (l = classes->leds; l; l = lnext) {
 	lnext = l->next;
 #ifdef XKB
 	if (l->xkb_sli)
diff --git a/dix/getevents.c b/dix/getevents.c
index a23eabe..425b602 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -67,6 +67,7 @@ extern Bool XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies);
 #include "exevents.h"
 #include "exglobals.h"
 #include "extnsionst.h"
+#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
 
 /* Maximum number of valuators, divided by six, rounded up, to get number
  * of events. */
@@ -110,6 +111,52 @@ key_autorepeats(DeviceIntPtr pDev, int key_code)
               (1 << (key_code & 7)));
 }
 
+static void
+CreateClassesChangedEvent(EventList* event, 
+                          DeviceIntPtr master, 
+                          DeviceIntPtr slave)
+{
+    deviceClassesChangedEvent *dcce; 
+    int len = sizeof(xEvent);
+    CARD32 ms = GetTimeInMillis();
+
+    /* XXX: ok, this is a bit weird. We need to alloc enough size for the
+     * event so it can be filled in in POE lateron. Reason being that if
+     * we realloc the event in POE we can get SIGABRT when we try to free
+     * or realloc the original pointer. 
+     * We can only do it here as we don't have the EventList in the event
+     * processing any more.
+     *
+     * Code is basically same as in Xi/listdev.c
+     */
+    if (slave->key)
+        len += sizeof(xKeyInfo);
+    if (slave->button)
+        len += sizeof(xButtonInfo);
+    if (slave->valuator)
+    {
+        int chunks = ((int)slave->valuator->numAxes + 19) / VPC;
+        len += (chunks * sizeof(xValuatorInfo) +
+                slave->valuator->numAxes * sizeof(xAxisInfo));
+    }
+    if (event->evlen < len)
+    {
+        event->event = realloc(event->event, len);
+        if (!event->event)
+            FatalError("[dix] Cannot allocate memory for "
+                    "DeviceClassesChangedEvent.\n");
+        event->evlen = len;
+    }
+
+    dcce = (deviceClassesChangedEvent*)event->event;
+    dcce->type = GenericEvent;
+    dcce->extension = IReqCode;
+    dcce->evtype = XI_DeviceClassesChangedNotify;
+    dcce->time = ms;
+    dcce->new_slave = slave->id;
+    dcce->length = (len - sizeof(xEvent))/4;
+}
+
 /**
  * Allocate the motion history buffer.
  */
@@ -415,6 +462,7 @@ GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type,
     KeySym *map = pDev->key->curKeySyms.map;
     KeySym sym = map[key_code * pDev->key->curKeySyms.mapWidth];
     deviceKeyButtonPointer *kbp = NULL;
+    DeviceIntPtr master;
 
     if (!events)
         return 0;
@@ -432,6 +480,18 @@ GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type,
     if (key_code < 8 || key_code > 255)
         return 0;
 
+    master = pDev->u.master;
+    if (master && master->u.lastSlave != pDev)
+    {
+        CreateClassesChangedEvent(events, master, pDev);
+
+        pDev->valuator->lastx = master->valuator->lastx;
+        pDev->valuator->lasty = master->valuator->lasty;
+        master->u.lastSlave = pDev;
+        numEvents++;
+        events++;
+    }
+
     if (num_valuators) {
         if ((num_valuators / 6) + 1 > MAX_VALUATOR_EVENTS)
             num_valuators = MAX_VALUATOR_EVENTS;
@@ -606,37 +666,14 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
     master = pDev->u.master;
     if (master && master->u.lastSlave != pDev)
     {
-#if 0
-        /* XXX: we should enqueue the state changed event here */
-        devStateEvent *state; 
-        num_events++;
-        state = events->event;
-
-        state->type = GenericEvent;
-        state->extension = IReqCode;
-        state->evtype = XI_DeviceStateChangedNotify;
-        state->deviceid = master->deviceid;
-        state->new_slave = pDev->id;
-        state->time = ms;
-        events++;
-
-#endif
+        CreateClassesChangedEvent(events, master, pDev);
 
-        /* now we need to update our device to the master's device - welcome
-         * to hell. 
-         * We need to match each device's capabilities to the previous
-         * capabilities as used by the master. Valuator[N] of master has to
-         * be written into valuator[N] of pDev. For all relative valuators.
-         * Otherwise we get jumpy valuators.
-         *
-         * However, this if iffy, if pDev->num_valuators !=
-         * master->num_valuators. What do we do with the others? 
-         * 
-         * XXX: just do lastx/y for now.
-         */
         pDev->valuator->lastx = master->valuator->lastx;
         pDev->valuator->lasty = master->valuator->lasty;
         master->u.lastSlave = pDev;
+
+        num_events++;
+        events++;
     }
 
     /* Do we need to send a DeviceValuator event? */
@@ -652,8 +689,6 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
     if (first_valuator < 0 || final_valuator > pDev->valuator->numAxes)
         return 0;
 
-
-
     /* fill up the raw event, after checking that it is large enough to
      * accommodate all valuators. 
      */
diff --git a/mi/mieq.c b/mi/mieq.c
index 26eab6f..7ea12fe 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -243,12 +243,13 @@ ChangeDeviceID(DeviceIntPtr dev, xEvent* event)
     else if (type == GenericEvent)
     {
         /* FIXME: need to put something into XGE to make this saner */
-        xGenericEvent* generic = (xGenericEvent*)event;
-        if (generic->extension == IReqCode
-                && generic->evtype == XI_RawDeviceEvent)
+        if (GEIsType(event, IReqCode, XI_RawDeviceEvent))
         {
             rawDeviceEvent* raw = (rawDeviceEvent*)event;
             raw->deviceid = dev->id;
+        } else if (GEIsType(event, IReqCode, XI_DeviceClassesChangedNotify))
+        {
+            // do nothing or drink a beer. your choice.
         } else
             ErrorF("[mi] Unknown generic event, cannot change id.\n");
     } else
commit c0a05805783ee3d38fbcc0fb45f4aa3c511785f0
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Fri Nov 9 23:07:10 2007 +1030

    Xext: add simple macro to easily check a generic event's type.

diff --git a/Xext/geext.h b/Xext/geext.h
index f3352c2..1ba71e0 100644
--- a/Xext/geext.h
+++ b/Xext/geext.h
@@ -87,6 +87,12 @@ extern GEExtension GEExtensions[MAXEXTENSIONS];
 #define GEEventFill(ev) \
     GEExtensions[GEEXTIDX(xE)].evfill
 
+#define GEIsType(ev, ext, ev_type) \
+        ((ev->u.u.type == GenericEvent) &&  \
+         ((xGenericEvent*)(ev))->extension == ext && \
+         ((xGenericEvent*)(ev))->evtype == ev_type)
+
+
 /* Interface for other extensions */
 void GEWindowSetMask(ClientPtr pClient, WindowPtr pWin, int extension, Mask mask);
 void GERegisterExtension(
commit 5bbc468b702f62d7c91d41aabcc27eeb553f6959
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Fri Nov 9 11:33:27 2007 +1030

    dix: grabbing an attached SD sets it floating for the duration of the grab.

diff --git a/dix/events.c b/dix/events.c
index 8a87618..c3589f0 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -237,6 +237,7 @@ _X_EXPORT CallbackListPtr DeviceEventCallback;
 Mask DontPropagateMasks[DNPMCOUNT];
 static int DontPropagateRefCnts[DNPMCOUNT];
 
+
 /**
  * Main input device struct. 
  *     inputInfo.pointer 
@@ -1540,6 +1541,54 @@ CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode)
     ComputeFreezes();
 }
 
+/* Only ever used if a grab is called on an attached slave device. */
+static int GrabPrivateIndex = -1;
+typedef struct _GrabMemoryRec {
+    DeviceIntPtr oldmaster;
+} GrabMemoryRec, *GrabMemoryPtr;
+
+/**
+ * Save the device's master device in the devPrivates. This needs to be done
+ * if a client directly grabs a slave device that is attached to a master. For
+ * the duration of the grab, the device is detached, ungrabbing re-attaches it
+ * though.
+ */
+static void
+SaveOldMaster(DeviceIntPtr dev)
+{
+    GrabMemoryPtr gm;
+
+    if (GrabPrivateIndex == -1)
+        GrabPrivateIndex = AllocateDevicePrivateIndex();
+
+    if (!AllocateDevicePrivate(dev, GrabPrivateIndex) ||
+            !(gm = xalloc(sizeof(GrabMemoryRec))))
+    {
+        ErrorF("[dix] Cannot allocate grab private. Grab not "
+                "possible on device.\n");
+        return;
+    }
+    gm->oldmaster = dev->u.master;
+    dev->devPrivates[GrabPrivateIndex].ptr = gm;
+}
+
+static void
+RestoreOldMaster(DeviceIntPtr dev)
+{
+    GrabMemoryPtr gm;
+
+    if (dev->isMaster || GrabPrivateIndex == -1)
+        return;
+
+    gm = ((GrabMemoryPtr)dev->devPrivates[GrabPrivateIndex].ptr);
+    if (gm)
+    {
+        dev->u.master = gm->oldmaster;
+        xfree(gm);
+        dev->devPrivates[GrabPrivateIndex].ptr = NULL;
+    }
+}
+
 /**
  * Activate a pointer grab on the given device. A pointer grab will cause all
  * core pointer events of this device to be delivered to the grabbing client only. 
@@ -1563,6 +1612,14 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
     WindowPtr oldWin = (grabinfo->grab) ? 
                         grabinfo->grab->window
                         : mouse->spriteInfo->sprite->win;
+    Bool isPassive = autoGrab & ~ImplicitGrabMask;
+
+    /* slave devices need to float for the duration of the grab. */
+    if (!isPassive && !mouse->isMaster)
+    {
+        SaveOldMaster(mouse);
+        AttachDevice(NULL, mouse, NULL);
+    }
 
     if (grab->confineTo)
     {
@@ -1582,7 +1639,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
 	grab->cursor->refcnt++;
     grabinfo->activeGrab = *grab;
     grabinfo->grab = &grabinfo->activeGrab;
-    grabinfo->fromPassiveGrab = autoGrab & ~ImplicitGrabMask;
+    grabinfo->fromPassiveGrab = isPassive;
     grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
     PostNewCursor(mouse);
     CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode);
@@ -1598,6 +1655,7 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
 {
     GrabPtr grab = mouse->deviceGrab.grab;
     DeviceIntPtr dev;
+    Bool  wasPassive= mouse->deviceGrab.fromPassiveGrab;
 
     mouse->valuator->motionHintWindow = NullWindow;
     mouse->deviceGrab.grab = NullGrab;
@@ -1615,6 +1673,10 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
     PostNewCursor(mouse);
     if (grab->cursor)
 	FreeCursor(grab->cursor, (Cursor)0);
+
+    if (!wasPassive)
+        RestoreOldMaster(mouse);
+
     ComputeFreezes();
 }
 
@@ -1629,6 +1691,13 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool pass
     GrabInfoPtr grabinfo = &keybd->deviceGrab;
     WindowPtr oldWin;
 
+    /* slave devices need to float for the duration of the grab. */
+    if (!passive && !keybd->isMaster)
+    {
+        SaveOldMaster(keybd);
+        AttachDevice(NULL, keybd, NULL);
+    }
+
     if (grabinfo->grab)
 	oldWin = grabinfo->grab->window;
     else if (keybd->focus)
@@ -1660,9 +1729,7 @@ DeactivateKeyboardGrab(DeviceIntPtr keybd)
     DeviceIntPtr dev;
     WindowPtr focusWin = keybd->focus ? keybd->focus->win
                                            : keybd->spriteInfo->sprite->win;
-
-    if (!grab)
-        grab = keybd->deviceGrab.grab;
+    Bool wasPassive = keybd->deviceGrab.fromPassiveGrab;
 
     if (focusWin == FollowKeyboardWin)
 	focusWin = inputInfo.keyboard->focus->win;
@@ -1677,6 +1744,10 @@ DeactivateKeyboardGrab(DeviceIntPtr keybd)
 	    dev->deviceGrab.sync.other = NullGrab;
     }
     DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab);
+
+    if (!wasPassive)
+        RestoreOldMaster(keybd);
+
     ComputeFreezes();
 }
 
@@ -4243,13 +4314,17 @@ EnterLeaveEvent(
 #ifdef XKB
     if (!noXkbExtension) {
         event.u.enterLeave.state = mouse->button->state & 0x1f00;
-        event.u.enterLeave.state |= 
-            XkbGrabStateFromRec(&keybd->key->xkbInfo->state);
+        if (keybd)
+            event.u.enterLeave.state |= 
+                XkbGrabStateFromRec(&keybd->key->xkbInfo->state);
     } else
 #endif
-        event.u.enterLeave.state = keybd->key->state | mouse->button->state;
+    {
+        event.u.enterLeave.state = (keybd) ? keybd->key->state : 0;
+        event.u.enterLeave.state |+ mouse->button->state;
+    }
     event.u.enterLeave.mode = mode;
-    focus = keybd->focus->win;
+    focus = (keybd) ? keybd->focus->win : None;
     if ((focus != NoneWin) &&
             ((pWin == focus) || (focus == PointerRootWin) ||
              IsParent(focus, pWin)))
commit 676b26ca3e9b142cf007af3f439aa1993f2247c4
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Nov 8 17:54:17 2007 +1030

    Xi: notify the clients when the device hierarchy has been changed.

diff --git a/Xi/chdevhier.c b/Xi/chdevhier.c
index c916c0f..338c074 100644
--- a/Xi/chdevhier.c
+++ b/Xi/chdevhier.c
@@ -79,9 +79,11 @@ int
 ProcXChangeDeviceHierarchy(ClientPtr client)
 {
     DeviceIntPtr ptr, keybd;
+    DeviceIntRec dummyDev;
     xAnyHierarchyChangeInfo *any;
     int required_len = sizeof(xChangeDeviceHierarchyReq);
     char n;
+    deviceHierarchyChangedEvent ev;
 
     REQUEST(xChangeDeviceHierarchyReq);
     REQUEST_AT_LEAST_SIZE(xChangeDeviceHierarchyReq);
@@ -226,6 +228,14 @@ ProcXChangeDeviceHierarchy(ClientPtr client)
         any = (xAnyHierarchyChangeInfo*)((char*)any + any->length);
     }
 
+    ev.type = GenericEvent;
+    ev.extension = IReqCode;
+    ev.length = 0;
+    ev.evtype = XI_DeviceHierarchyChangedNotify;
+    ev.time = GetTimeInMillis();
+
+    SendEventToAllWindows(&dummyDev, XI_DeviceHierarchyChangedMask, 
+            (xEvent*)&ev, 1);
     return Success;
 }
 
diff --git a/Xi/extinit.c b/Xi/extinit.c
index de2653f..0ecb421 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -137,9 +137,8 @@ Mask ExtExclusiveMasks[EMASKSIZE];
  * Evtype is index, mask is value at index.
  */
 static Mask xi_filters[3] = {
-    XI_PointerKeyboardPairingChangedMask,
-    XI_RandomStringMask,
-    XI_RawDeviceEventMask,  
+    XI_DeviceHierarchyChangedMask,
+    XI_RawDeviceEventMask,
 };
 
 static struct dev_type
commit cb75f09146a3c17b1a67b636bbf7229c65c83b35
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Fri Nov 9 11:29:18 2007 +1030

    dix: calloc root window's Generic Event mask, stops segfaults.

diff --git a/dix/window.c b/dix/window.c
index 23acbd6..51891a8 100644
--- a/dix/window.c
+++ b/dix/window.c
@@ -455,7 +455,12 @@ CreateRootWindow(ScreenPtr pScreen)
 #ifdef XINPUT
     pWin->optional->inputMasks = NULL;
     pWin->optional->deviceCursors = NULL;
-    pWin->optional->geMasks = NULL;
+    pWin->optional->geMasks = (GenericClientMasksPtr)xcalloc(1, sizeof(GenericClientMasksRec));
+    if (!pWin->optional->geMasks)
+    {
+        xfree(pWin->optional);
+        return FALSE;
+    }
 #endif
 
     pWin->optional->access.perm = NULL;
commit 59b304d8a24fecd094296feb217823f0c73d6f82
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Nov 8 15:44:18 2007 +1030

    dix, mi: stop segfaults when a floating device emits events.
    
    For pointers: don't try to set master->valuator fields if there is no master.
    For keyboards: check if device is valid before trying to access the fields in
    miPointerGetScreen (btw. this disables DGA events for floating keyboards).
    
    Also stop the hideous number of ErrorFs if we request the paired device for a
    floating dev.

diff --git a/dix/devices.c b/dix/devices.c
index 30fc7b3..c9831ea 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2265,11 +2265,8 @@ GetPairedDevice(DeviceIntPtr dev)
         dev = dev->u.master;
 
     if (!dev->spriteInfo->paired)
-    {
-        ErrorF("[dix] No device paired with %d (%s).\n", 
-                dev->id, dev->name);
         return NULL;
-    }
+
     return dev->spriteInfo->paired;
 }
 
diff --git a/dix/getevents.c b/dix/getevents.c
index 3044301..a23eabe 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -736,8 +736,11 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
 
     pDev->valuator->lastx = x;
     pDev->valuator->lasty = y;
-    master->valuator->lastx = x;
-    master->valuator->lasty = y;
+    if (master)
+    {
+        master->valuator->lastx = x;
+        master->valuator->lasty = y;
+    }
 
     if (!coreOnly)
     {
diff --git a/mi/mipointer.c b/mi/mipointer.c
index 7b56579..b2f31c1 100644
--- a/mi/mipointer.c
+++ b/mi/mipointer.c
@@ -529,7 +529,7 @@ miPointerCurrentScreen ()
 _X_EXPORT ScreenPtr
 miPointerGetScreen(DeviceIntPtr pDev)
 {
-    if (!pDev->isMaster && !pDev->u.master)
+    if (!pDev || (!pDev->isMaster && !pDev->u.master))
         return NULL;
 
     return MIPOINTER(pDev)->pScreen;
commit 3063f0c6679bdbea13f360cff8d09a88b9871da9
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Nov 8 11:51:03 2007 +1030

    mi: change the device id to the master devices' when duplicating the event.
    
    Move the event duplication into a CopyGetMasterEvent(), makes the code a bit
    better to read.

diff --git a/mi/mieq.c b/mi/mieq.c
index 20004f3..26eab6f 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -226,6 +226,68 @@ mieqSetHandler(int event, mieqHandler handler)
     miEventQueue.handlers[event] = handler;
 }
 
+/**
+ * Change the device id of the given event to the given device's id.
+ */
+static void
+ChangeDeviceID(DeviceIntPtr dev, xEvent* event)
+{
+    int type = event->u.u.type;
+
+    if (type == DeviceKeyPress || type == DeviceKeyRelease ||
+            type == DeviceButtonPress || type == DeviceButtonRelease ||
+            type == DeviceMotionNotify)
+        ((deviceKeyButtonPointer*)event)->deviceid = dev->id;
+    else if (type == DeviceValuator)
+        ((deviceValuator*)event)->deviceid = dev->id;
+    else if (type == GenericEvent)
+    {
+        /* FIXME: need to put something into XGE to make this saner */
+        xGenericEvent* generic = (xGenericEvent*)event;
+        if (generic->extension == IReqCode
+                && generic->evtype == XI_RawDeviceEvent)
+        {
+            rawDeviceEvent* raw = (rawDeviceEvent*)event;
+            raw->deviceid = dev->id;
+        } else
+            ErrorF("[mi] Unknown generic event, cannot change id.\n");
+    } else
+        ErrorF("[mi] Unknown event type, cannot change id.\n");
+}
+
+/**
+ * Copy the given event into master.
+ * @param mdev The master device
+ * @param original The event as it came from the EQ
+ * @param master The event after being copied
+ * @param count Number of events in original.
+ */
+static void
+CopyGetMasterEvent(DeviceIntPtr mdev, xEvent* original,
+                   xEvent** master, int count)
+{
+    if (count > 1) {
+        *master = xcalloc(count, sizeof(xEvent));
+        if (!*master)
+            FatalError("[mi] No memory left for master event.\n");
+        while(count--)
+        {
+            memcpy(&(*master)[count], &original[count], sizeof(xEvent));
+            ChangeDeviceID(mdev, &(*master)[count]);
+        }
+    } else
+    {
+        int len = sizeof(xEvent);
+        if (original->u.u.type == GenericEvent)
+            len += GEV(original)->length * 4;
+        *master = xalloc(len);
+        if (!*master)
+            FatalError("[mi] No memory left for master event.\n");
+        memcpy(*master, original, len);
+        ChangeDeviceID(mdev, *master);
+    }
+}
+
 /* Call this from ProcessInputEvents(). */
 void
 mieqProcessInputEvents(void)
@@ -233,7 +295,7 @@ mieqProcessInputEvents(void)
     EventRec *e = NULL;
     int x = 0, y = 0;
     xEvent* event,
-            *master_event;
+            *master_event = NULL;
 
     while (miEventQueue.head != miEventQueue.tail) {
         if (screenIsSaved == SCREEN_SAVER_ON)
@@ -284,39 +346,32 @@ mieqProcessInputEvents(void)
              * copy. Eventually the interface for the processInputProc needs
              * to be changed. (whot)
              */ 
-
-            /* The event is changed during event processing, so we need to
-             * memcpy the event we have and pass the copy through for master
-             */
             if (e->nevents > 1)
             {
                 int i;
                 event = xcalloc(e->nevents, sizeof(xEvent));
-                master_event = xcalloc(e->nevents, sizeof(xEvent));
-                if (!event || !master_event)
+                if (!event)
                     FatalError("[mi] No memory left for event processing.\n");
                 for (i = 0; i < e->nevents; i++)
                 {
                     memcpy(&event[i], e->events[i].event, sizeof(xEvent));
-                    memcpy(&master_event[i], e->events[i].event, sizeof(xEvent));
                 }
-            }
-            else 
-            {
-                int len = sizeof(xEvent); 
+            } else
                 event = e->events->event;
-                if (event->u.u.type == GenericEvent) 
-                        len += GEV(event)->length * 4;
-                master_event = xalloc(len);
-                if (!master_event)
-                    FatalError("[mi] No memory left for master event.\n");
-                memcpy(master_event, event, len);
+            if (!e->pDev->isMaster && e->pDev->u.master)
+            {
+                CopyGetMasterEvent(e->pDev->u.master, event,
+                                   &master_event, e->nevents);
             }
 
+            /* process slave first, then master */
             e->pDev->public.processInputProc(event, e->pDev, e->nevents);
+
             if (!e->pDev->isMaster && e->pDev->u.master)
+            {
                 e->pDev->u.master->public.processInputProc(master_event, 
                         e->pDev->u.master, e->nevents);
+            }
 
             if (e->nevents > 1)
                 xfree(event);
@@ -331,3 +386,4 @@ mieqProcessInputEvents(void)
         }
     }
 }
+
commit 180220f284823c486e7001ef00f1279dc548c9c7
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Nov 8 10:00:35 2007 +1030

    Xi: return BadDevice for slave devices on ProcXSetClientPointer
    
    Also clean up to return error codes instead of sending the error manually.

diff --git a/Xi/setcptr.c b/Xi/setcptr.c
index 66c8981..ad8f571 100644
--- a/Xi/setcptr.c
+++ b/Xi/setcptr.c
@@ -78,11 +78,10 @@ ProcXSetClientPointer(ClientPtr client)
 
 
     pDev = LookupDeviceIntRec(stuff->deviceid);
-    if (pDev == NULL || !IsPointerDevice(pDev))
+    if (pDev == NULL || !IsPointerDevice(pDev) || !pDev->isMaster)
     {
-        SendErrorToClient(client, IReqCode, X_SetClientPointer, 0,
-                BadDevice); 
-        return Success;
+        client->errorValue = stuff->deviceid;
+        return BadDevice;
     }
 
     if (stuff->win != None)
@@ -90,19 +89,18 @@ ProcXSetClientPointer(ClientPtr client)
         err = dixLookupWindow(&pWin, stuff->win, client, DixReadWriteAccess);
         if (err != Success)
         {
-            SendErrorToClient(client, IReqCode, X_SetClientPointer, 
-                    stuff->win, err);
-            return Success;
+            client->errorValue = stuff->win;
+            return err;
         }
         targetClient= wClient(pWin);
     } else
         targetClient = client;
-    
+
     if (!SetClientPointer(targetClient, client, pDev))
     {
-        SendErrorToClient(client, IReqCode, X_SetClientPointer, 
-                stuff->win, BadAccess);
-        return Success;
+        client->errorValue = stuff->win;
+        return BadAccess;
     }
+
     return Success;
 }
commit 184a7b8917a15bb2c719153b9b016c03aab42101
Merge: a8808ac... 0b72905...
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Nov 8 09:34:35 2007 +1030

    Merge branch 'mpx' into mdsd
    
    Conflicts:
    
    	Xi/opendev.c

diff --cc xkb/xkbActions.c
index 32b9e0d,ea7913a..ebc5bfd
--- a/xkb/xkbActions.c
+++ b/xkb/xkbActions.c
@@@ -1273,9 -1272,8 +1272,8 @@@ xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICE
  	    keyc->modifierMap[key] = 0;
              tmpdev = dev;
          } else
 -            tmpdev = GetPairedPointer(dev);
 +            tmpdev = GetPairedDevice(dev);
  
- 
          UNWRAP_PROCESS_INPUT_PROC(tmpdev,xkbPrivPtr, backupproc);
          dev->public.processInputProc(xE,tmpdev,count);
          COND_WRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr,
commit a8808ac3d093f33b39de109107d396fe0a02c4fc
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Wed Nov 7 11:42:58 2007 +1030

    Xi: don't call CheckMotion for slave devices.
    
    This essentially disables enter/leave for slave devices, but re-enables them
    for master devices. Which is a good thing after all.

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 3f096a6..cf73bfd 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -127,7 +127,8 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
     if (device->isMaster && device->coreEvents && coretype)
         sendCore = TRUE;
 
-    CheckMotion(xE, device);
+    if (device->isMaster)
+        CheckMotion(xE, device);
 
     if (xE->u.u.type != DeviceValuator && xE->u.u.type != GenericEvent) {
         DeviceIntPtr mouse = NULL, kbd = NULL;
commit 15944b8f02752eedd61be34a6a29dd6b82a0ac97
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Wed Nov 7 11:33:24 2007 +1030

    mi: duplicate event before processing it, so master has original values
    
    Event values may get changed in the event processing stage, so we need to
    duplicate it to pump different events through for slave and master device.

diff --git a/mi/mieq.c b/mi/mieq.c
index 7d6d110..20004f3 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -232,7 +232,8 @@ mieqProcessInputEvents(void)
 {
     EventRec *e = NULL;
     int x = 0, y = 0;
-    xEvent* event;
+    xEvent* event,
+            *master_event;
 
     while (miEventQueue.head != miEventQueue.tail) {
         if (screenIsSaved == SCREEN_SAVER_ON)
@@ -283,25 +284,43 @@ mieqProcessInputEvents(void)
              * copy. Eventually the interface for the processInputProc needs
              * to be changed. (whot)
              */ 
+
+            /* The event is changed during event processing, so we need to
+             * memcpy the event we have and pass the copy through for master
+             */
             if (e->nevents > 1)
             {
                 int i;
                 event = xcalloc(e->nevents, sizeof(xEvent));
+                master_event = xcalloc(e->nevents, sizeof(xEvent));
+                if (!event || !master_event)
+                    FatalError("[mi] No memory left for event processing.\n");
                 for (i = 0; i < e->nevents; i++)
+                {
                     memcpy(&event[i], e->events[i].event, sizeof(xEvent));
+                    memcpy(&master_event[i], e->events[i].event, sizeof(xEvent));
+                }
             }
             else 
             {
+                int len = sizeof(xEvent); 
                 event = e->events->event;
+                if (event->u.u.type == GenericEvent) 
+                        len += GEV(event)->length * 4;
+                master_event = xalloc(len);
+                if (!master_event)
+                    FatalError("[mi] No memory left for master event.\n");
+                memcpy(master_event, event, len);
             }
 
             e->pDev->public.processInputProc(event, e->pDev, e->nevents);
             if (!e->pDev->isMaster && e->pDev->u.master)
-                e->pDev->u.master->public.processInputProc(event, 
+                e->pDev->u.master->public.processInputProc(master_event, 
                         e->pDev->u.master, e->nevents);
 
             if (e->nevents > 1)
                 xfree(event);
+            xfree(master_event);
         }
 
         /* Update the sprite now. Next event may be from different device. */
commit 7ef863720dc79107fc2cd17ce684366c87e001a4
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 23 17:28:03 2007 +0930

    dix: Create new sprite for floating devices.
    
    Floating devices get sprites, but still aren't spriteOwners. This prevents
    them from getting rendered, and also stops segfaulting.
    (not really solving the problems with keyboards though)

diff --git a/dix/devices.c b/dix/devices.c
index d971339..7e7e646 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2205,16 +2205,18 @@ PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd)
  * Client is set to the client that issued the request, or NULL if it comes
  * from some internal automatic pairing.
  *
+ * Master may be NULL to set the device floating. 
+ *
  * We don't allow multi-layer hierarchies right now. You can't attach a slave
  * to another slave. 
  */
 int
 AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
 {
-    if (!dev || !master)
+    if (!dev || dev->isMaster) 
         return BadDevice;
 
-    if (!master->isMaster) /* can't attach to slave device */
+    if (master && !master->isMaster) /* can't attach to slaves */
         return BadDevice;
 
     if (!pairingClient)
@@ -2222,8 +2224,27 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
     else if (client && pairingClient != client)
         return BadAccess;
 
+    /* set from floating to floating? */
+    if (!dev->u.master && !master)
+        return Success;
+
+    /* free the existing sprite. */
+    if (!dev->u.master && dev->spriteInfo->sprite)
+        xfree(dev->spriteInfo->sprite);
+
     dev->u.master = master;
-    dev->spriteInfo->sprite = master->spriteInfo->sprite;
+
+    /* If device is set to floating, we need to create a sprite for it,
+     * otherwise things go bad. However, we don't want to render the cursor,
+     * so we reset spriteOwner.
+     */
+    if (!master)
+    {
+                              /* current root window */
+        InitializeSprite(dev, dev->spriteInfo->sprite->spriteTrace[0]);
+        dev->spriteInfo->spriteOwner = FALSE;
+    } else
+        dev->spriteInfo->sprite = master->spriteInfo->sprite;
 
     return Success;
 }
commit d9caa469b9bb4eb6125b890820853062fc2c4441
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Fri Oct 19 15:26:09 2007 +0930

    Xi: allow VCP/VCK to be OpenDevice'd as well.
    
    All devices deserve to be equal. Except master devices, they are a bit more
    equal than the others.

diff --git a/Xi/opendev.c b/Xi/opendev.c
index 0b0671d..192cddc 100644
--- a/Xi/opendev.c
+++ b/Xi/opendev.c
@@ -106,12 +106,6 @@ ProcXOpenDevice(ClientPtr client)
     REQUEST(xOpenDeviceReq);
     REQUEST_SIZE_MATCH(xOpenDeviceReq);
 
-    if (stuff->deviceid == inputInfo.pointer->id ||
-	stuff->deviceid == inputInfo.keyboard->id) {
-	SendErrorToClient(client, IReqCode, X_OpenDevice, 0, BadDevice);
-	return Success;
-    }
-
     if ((dev = LookupDeviceIntRec(stuff->deviceid)) == NULL) {	/* not open */
 	for (dev = inputInfo.off_devices; dev; dev = dev->next)
 	    if (dev->id == stuff->deviceid)
commit 155e2c559ed0dbf31b6d39d48648a3ee22b37635
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Fri Oct 19 14:37:07 2007 +0930

    Xi: advertise as XInput v2 capable

diff --git a/Xi/extinit.c b/Xi/extinit.c
index c933e55..d02053c 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -236,8 +236,8 @@ Mask PropagateMask[MAX_DEVICES];
  */
 
 static XExtensionVersion thisversion = { XI_Present,
-    XI_Add_DevicePresenceNotify_Major,
-    XI_Add_DevicePresenceNotify_Minor
+    XI_2_Major,
+    XI_2_Minor
 };
 
 
commit 5ba738935f0d786e4670adf3b05ad42fc5e710fd
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Fri Oct 19 14:36:37 2007 +0930

    Xi: remove ChangePointerKeyboardPairing in favour of ChangeDeviceHierarchy.

diff --git a/Xi/Makefile.am b/Xi/Makefile.am
index 2cf11a0..407928d 100644
--- a/Xi/Makefile.am
+++ b/Xi/Makefile.am
@@ -9,6 +9,8 @@ libXi_la_SOURCES =	\
         chdevcur.h \
 	chgdctl.c \
 	chgdctl.h \
+        chdevhier.c \
+        chdevhier.h \
 	chgfctl.c \
 	chgfctl.h \
 	chgkbd.c \
@@ -19,8 +21,6 @@ libXi_la_SOURCES =	\
 	chgprop.h \
 	chgptr.c \
 	chgptr.h \
-	chpkpair.c \
-	chpkpair.h \
 	chaccess.c \
 	chaccess.h \
 	closedev.c \
diff --git a/Xi/chdevhier.c b/Xi/chdevhier.c
new file mode 100644
index 0000000..c916c0f
--- /dev/null
+++ b/Xi/chdevhier.c
@@ -0,0 +1,231 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+/***********************************************************************
+ *
+ * Request change in the device hierarchy.
+ *
+ */
+
+
+#define	 NEED_EVENTS
+#define	 NEED_REPLIES
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>	/* for inputstr.h    */
+#include <X11/Xproto.h>	/* Request macro     */
+#include "inputstr.h"	/* DeviceIntPtr      */
+#include "windowstr.h"	/* window structure  */
+#include "scrnintstr.h"	/* screen structure  */
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XInput.h>
+#include <X11/extensions/XIproto.h>
+#include <X11/extensions/geproto.h>
+#include "extnsionst.h"
+#include "extinit.h"	/* LookupDeviceIntRec */
+#include "exevents.h"
+#include "exglobals.h"
+#include "geext.h"
+
+#include "chdevhier.h"
+
+
+/***********************************************************************
+ *
+ * This procedure allows a client to change the device hierarchy through
+ * adding new master devices, removing them, etc.
+ *
+ */
+
+int SProcXChangeDeviceHierarchy(ClientPtr client)
+{
+    char n;
+
+    REQUEST(xChangeDeviceHierarchyReq);
+    swaps(&stuff->length, n);
+    return (ProcXChangeDeviceHierarchy(client));
+}
+
+#define SWAPIF(cmd) if (client->swapped) { cmd; }
+
+int
+ProcXChangeDeviceHierarchy(ClientPtr client)
+{
+    DeviceIntPtr ptr, keybd;
+    xAnyHierarchyChangeInfo *any;
+    int required_len = sizeof(xChangeDeviceHierarchyReq);
+    char n;
+
+    REQUEST(xChangeDeviceHierarchyReq);
+    REQUEST_AT_LEAST_SIZE(xChangeDeviceHierarchyReq);
+
+    /* XXX: check if client is allowed to change hierarch */
+
+    
+    any = (xAnyHierarchyChangeInfo*)&stuff[1];
+    while(stuff->num_changes--)
+    {
+        SWAPIF(swapl(&any->type, n));
+        SWAPIF(swaps(&any->length, n));
+
+        required_len += any->length;
+        if ((stuff->length * 4) < required_len)
+            return BadLength;
+
+        switch(any->type)
+        {
+            case CH_CreateMasterDevice:
+                {
+                    xCreateMasterInfo* c = (xCreateMasterInfo*)any;
+                    char* name;
+                    int ret;
+                    
+                    SWAPIF(swaps(&c->namelen, n));
+                    name = xcalloc(c->namelen + 1, sizeof(char));
+                    strncpy(name, (char*)&c[1], c->namelen);
+
+                    ret = AllocMasterDevice(name, &ptr, &keybd);
+                    if (ret != Success)
+                    {
+                        xfree(name);
+                        return ret;
+                    }
+
+                    if (!c->sendCore)
+                        ptr->coreEvents = keybd->coreEvents =  FALSE;
+
+                    ActivateDevice(ptr);
+                    ActivateDevice(keybd);
+
+                    if (c->enable)
+                    {
+                        EnableDevice(ptr);
+                        EnableDevice(keybd);
+                    }
+                    xfree(name);
+                }
+                break;
+            case CH_RemoveMasterDevice:
+                {
+                    xRemoveMasterInfo* r = (xRemoveMasterInfo*)any;
+
+                    if (r->returnMode != AttachToMaster && 
+                            r->returnMode != Floating)
+                        return BadValue;
+
+                    ptr = LookupDeviceIntRec(r->deviceid);
+                    if (!ptr || !ptr->isMaster)
+                        return BadDevice;
+
+                    /* XXX: For now, don't allow removal of VCP, VCK */
+                    if (ptr == inputInfo.pointer ||
+                            ptr == inputInfo.keyboard)
+                        return BadDevice;
+
+                    /* disable keyboards first */
+                    if (IsPointerDevice(ptr))
+                        keybd = ptr->spriteInfo->paired;
+                    else
+                    {
+                        keybd = ptr;
+                        ptr = keybd->spriteInfo->paired;
+                    }
+
+                    /* Disabling sends the devices floating, reattach them if
+                     * desired. */
+                    if (r->returnMode == AttachToMaster)
+                    {
+                        DeviceIntPtr attached, 
+                                     newptr, 
+                                     newkeybd;
+
+                        newptr = LookupDeviceIntRec(r->returnPointer);
+                        newkeybd = LookupDeviceIntRec(r->returnKeyboard);
+                        if (!newptr || !newptr->isMaster ||
+                                !newkeybd || !newkeybd->isMaster)
+                            return BadDevice;
+
+                        for (attached = inputInfo.devices; 
+                                attached; 
+                                attached = attached->next)
+                        {
+                            if (!attached->isMaster) {
+                                if (attached->u.master == ptr)
+                                    AttachDevice(client, attached, newptr);
+                                if (attached->u.master == keybd)
+                                    AttachDevice(client, attached, newkeybd);
+                            }
+                        }
+                    }
+
+                    /* can't disable until we removed pairing */
+                    keybd->spriteInfo->paired = NULL;
+                    ptr->spriteInfo->paired = NULL;
+                    DisableDevice(keybd);
+                    DisableDevice(ptr);
+
+                    RemoveDevice(keybd);
+                    RemoveDevice(ptr);
+                }
+                break;
+            case CH_ChangeAttachment:
+                {
+                    xChangeAttachmentInfo* c = (xChangeAttachmentInfo*)any;
+
+                    ptr = LookupDeviceIntRec(c->deviceid);
+                    if (!ptr || ptr->isMaster)
+                        return BadDevice;
+
+                    if (c->changeMode == Floating)
+                        AttachDevice(client, ptr, NULL);
+                    else
+                    {
+                        DeviceIntPtr newmaster = LookupDeviceIntRec(c->newMaster);
+                        if (!newmaster || !newmaster->isMaster)
+                            return BadDevice;
+
+                        if ((IsPointerDevice(newmaster) &&
+                                    !IsPointerDevice(ptr)) ||
+                                (IsKeyboardDevice(newmaster) &&
+                                 !IsKeyboardDevice(ptr))) 
+                                return BadDevice;
+                        AttachDevice(client, ptr, newmaster);
+                    }
+
+                }
+                break;
+        }
+
+        any = (xAnyHierarchyChangeInfo*)((char*)any + any->length);
+    }
+
+    return Success;
+}
+
diff --git a/Xi/chdevhier.h b/Xi/chdevhier.h
new file mode 100644
index 0000000..1853fa7
--- /dev/null
+++ b/Xi/chdevhier.h
@@ -0,0 +1,45 @@
+/*
+
+Copyright 2007 Peter Hutterer <peter at cs.unisa.edu.au>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the author shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the author.
+
+*/
+
+/***********************************************************************
+ *
+ * Request change in the device hierarchy.
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef CHDEVHIER_H
+#define CHDEVHIER_H 1
+
+int SProcXChangeDeviceHierarchy(ClientPtr /* client */);
+int ProcXChangeDeviceHierarchy(ClientPtr /* client */);
+
+#endif
diff --git a/Xi/extinit.c b/Xi/extinit.c
index c1b6eed..c933e55 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -79,11 +79,11 @@ SOFTWARE.
 #include "chaccess.h"
 #include "chdevcur.h"
 #include "chgdctl.h"
+#include "chdevhier.h"
 #include "chgfctl.h"
 #include "chgkbd.h"
 #include "chgprop.h"
 #include "chgptr.h"
-#include "chpkpair.h"
 #include "closedev.h"
 #include "extgrbdev.h"
 #include "devbell.h"
@@ -328,8 +328,8 @@ ProcIDispatch(ClientPtr client)
         return (ProcXWarpDevicePointer(client));
     else if (stuff->data == X_ChangeDeviceCursor)
         return (ProcXChangeDeviceCursor(client));
-    else if (stuff->data == X_ChangePointerKeyboardPairing)
-        return (ProcXChangePointerKeyboardPairing(client));
+    else if (stuff->data == X_ChangeDeviceHierarchy)
+        return (ProcXChangeDeviceHierarchy(client));
     else if (stuff->data == X_XiSelectEvent)
         return (ProcXiSelectEvent(client));
     else if (stuff->data == X_RegisterPairingClient)
@@ -445,8 +445,8 @@ SProcIDispatch(ClientPtr client)
 	return (SProcXWarpDevicePointer(client));
     else if (stuff->data == X_ChangeDeviceCursor)
         return (SProcXChangeDeviceCursor(client));
-    else if (stuff->data == X_ChangePointerKeyboardPairing)
-        return (SProcXChangePointerKeyboardPairing(client));
+    else if (stuff->data == X_ChangeDeviceHierarchy)
+        return (SProcXChangeDeviceHierarchy(client));
     else if (stuff->data == X_XiSelectEvent)
         return (SProcXiSelectEvent(client));
     else if (stuff->data == X_RegisterPairingClient)
@@ -1153,10 +1153,6 @@ XIGEEventSwap(xGenericEvent* from, xGenericEvent* to)
     swaps(&from->sequenceNumber, n);
     switch(from->evtype)
     {
-        case XI_PointerKeyboardPairingChangedNotify:
-            SPointerKeyboardPairingChangedNotifyEvent
-                ((pairingChangedNotify*)from, (pairingChangedNotify*)to);
-            break;
         case XI_RawDeviceEvent:
             SRawDeviceEvent((rawDeviceEvent*)from, (rawDeviceEvent*)to);
             break;
diff --git a/dix/devices.c b/dix/devices.c
index af086a4..d971339 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2343,6 +2343,7 @@ AllocMasterDevice(char* name, DeviceIntPtr* ptr, DeviceIntPtr* keybd)
 {
     DeviceIntPtr pointer;
     DeviceIntPtr keyboard;
+    *ptr = *keybd = NULL;
 
     pointer = AddInputDevice(CorePointerProc, TRUE);
     if (!pointer)
commit 6dcde0e9c1d068d9fc4a772d29d1d4c6cc57aeb9
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Oct 18 12:21:07 2007 +0930

    Xi: set master device's id in ListDevices Reply.

diff --git a/Xi/listdev.c b/Xi/listdev.c
index 5b5d26e..8753b29 100644
--- a/Xi/listdev.c
+++ b/Xi/listdev.c
@@ -187,6 +187,9 @@ CopySwapDevice(ClientPtr client, DeviceIntPtr d, int num_classes,
         dev->use = IsXExtensionPointer;
     else
 	dev->use = IsXExtensionDevice;
+    if (!d->isMaster) 
+        dev->attached = (d->u.master) ? d->u.master->id : IsFloating;
+
     if (client->swapped) {
 	swapl(&dev->type, n);	/* macro - braces are required */
     }
commit cfcc6e14b9a15f7979ba0df9c105cf563bef98fa
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Fri Oct 19 11:28:44 2007 +0930

    Xi: return all master devices as type IsXPointer/Keyboard when listing devs.
    
    Slave devices are reported as IsXExtensionPointer/Keyboard.

diff --git a/Xi/listdev.c b/Xi/listdev.c
index a9fd401..5b5d26e 100644
--- a/Xi/listdev.c
+++ b/Xi/listdev.c
@@ -177,9 +177,9 @@ CopySwapDevice(ClientPtr client, DeviceIntPtr d, int num_classes,
     dev->id = d->id;
     dev->type = d->type;
     dev->num_classes = num_classes;
-    if (d == inputInfo.keyboard)
+    if (d->isMaster && IsKeyboardDevice(d))
 	dev->use = IsXKeyboard;
-    else if (d == inputInfo.pointer)
+    else if (d->isMaster && IsPointerDevice(d))
 	dev->use = IsXPointer;
     else if (d->key && d->kbdfeed)
         dev->use = IsXExtensionKeyboard;
@@ -328,10 +328,6 @@ ProcXListInputDevices(ClientPtr client)
 
     AddOtherInputDevices();
 
-    SizeDeviceInfo(inputInfo.keyboard, &namesize, &size);
-    SizeDeviceInfo(inputInfo.pointer, &namesize, &size);
-    numdevs = 2;
-
     for (d = inputInfo.devices; d; d = d->next) {
 	SizeDeviceInfo(d, &namesize, &size);
         numdevs++;
@@ -348,11 +344,6 @@ ProcXListInputDevices(ClientPtr client)
     savbuf = devbuf;
 
     dev = (xDeviceInfoPtr) devbuf;
-    ListDeviceInfo(client, inputInfo.keyboard, dev++, 
-                   &devbuf, &classbuf, &namebuf);
-    ListDeviceInfo(client, inputInfo.pointer, dev++,
-                   &devbuf, &classbuf, &namebuf);
-
     for (d = inputInfo.devices; d; d = d->next, dev++)
 	ListDeviceInfo(client, d, dev, &devbuf, &classbuf, &namebuf);
     for (d = inputInfo.off_devices; d; d = d->next, dev++)
commit 9aadde377991bfbd88524d02106bec3dedd6e7c9
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Wed Oct 17 12:05:50 2007 +0930

    mi: don't call UndisplayCursor for non-sprite-owners.
    
    Segfaults are bad.

diff --git a/mi/mipointer.c b/mi/mipointer.c
index 0db4d2c..7a32578 100644
--- a/mi/mipointer.c
+++ b/mi/mipointer.c
@@ -229,7 +229,8 @@ miPointerUndisplayCursor(pDev, pScreen)
     ScreenPtr 	 pScreen;
 {
     SetupScreen(pScreen);
-    (*pScreenPriv->spriteFuncs->UndisplayCursor)(pDev, pScreen);
+    if (pDev->isMaster && pDev->spriteInfo->spriteOwner)
+        (*pScreenPriv->spriteFuncs->UndisplayCursor)(pDev, pScreen);
 }
 
 static void
commit 8b7c4249d82d07e852d8d8c15c7ab9977dd1f31c
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Wed Oct 17 10:41:58 2007 +0930

    mi: call processInputProc for master devices after slave event processing.
    
    More work is needed to sort out grabs though.

diff --git a/mi/mieq.c b/mi/mieq.c
index f5e119e..7d6d110 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -296,6 +296,9 @@ mieqProcessInputEvents(void)
             }
 
             e->pDev->public.processInputProc(event, e->pDev, e->nevents);
+            if (!e->pDev->isMaster && e->pDev->u.master)
+                e->pDev->u.master->public.processInputProc(event, 
+                        e->pDev->u.master, e->nevents);
 
             if (e->nevents > 1)
                 xfree(event);
commit ae9fc10adec8f9bf0492d14d435f8f11e0163b27
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Wed Oct 17 10:41:04 2007 +0930

    Xi: don't send core events for slave devices.

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 49400e8..3f096a6 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -124,7 +124,7 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
     int coretype = 0;
 
     coretype = XItoCoreType(xE->u.u.type);
-    if (device->coreEvents && coretype)
+    if (device->isMaster && device->coreEvents && coretype)
         sendCore = TRUE;
 
     CheckMotion(xE, device);
commit de70cfdbe60eb6e7bf3e74dfd1ac34de554deff1
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Wed Oct 17 09:52:30 2007 +0930

    mi: fix some macros to allow multiple cursors for master devices.
    
    Macros defaulted to inputInfo.pointe rfor devices that weren't spriteOwners.
    Changed to take the device's master device now.
    
    This includes sticking in a number of checks and warnings that cursor
    rendering won't be called for floating devices.

diff --git a/mi/midispcur.c b/mi/midispcur.c
index d7a8964..16ece10 100644
--- a/mi/midispcur.c
+++ b/mi/midispcur.c
@@ -85,7 +85,7 @@ typedef struct {
 #define MIDCBUFFER(dev) \
  ((DevHasCursor(dev)) ? \
   (miDCBufferPtr)dev->devPrivates[miDCSpriteIndex].ptr :\
-  (miDCBufferPtr)inputInfo.pointer->devPrivates[miDCSpriteIndex].ptr)
+  (miDCBufferPtr)dev->u.master->devPrivates[miDCSpriteIndex].ptr)
 
 /* 
  * The core pointer buffer will point to the index of the virtual core pointer
diff --git a/mi/mipointer.c b/mi/mipointer.c
index eabc435..0db4d2c 100644
--- a/mi/mipointer.c
+++ b/mi/mipointer.c
@@ -59,7 +59,7 @@ static int miPointerPrivatesIndex = 0;
 #define MIPOINTER(dev) \
     ((DevHasCursor((dev))) ? \
         (miPointerPtr) dev->devPrivates[miPointerPrivatesIndex].ptr : \
-        (miPointerPtr) inputInfo.pointer->devPrivates[miPointerPrivatesIndex].ptr)
+        (miPointerPtr) dev->u.master->devPrivates[miPointerPrivatesIndex].ptr)
 
 static Bool miPointerRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 
                                    CursorPtr pCursor);
@@ -210,7 +210,12 @@ miPointerDisplayCursor (pDev, pScreen, pCursor)
     ScreenPtr 	 pScreen;
     CursorPtr	 pCursor;
 {
-    miPointerPtr pPointer = MIPOINTER(pDev);
+    miPointerPtr pPointer;
+    
+    if (!pDev->isMaster && !pDev->u.master)
+        return FALSE;
+
+    pPointer = MIPOINTER(pDev);
 
     pPointer->pCursor = pCursor;
     pPointer->pScreen = pScreen;
@@ -233,7 +238,12 @@ miPointerConstrainCursor (pDev, pScreen, pBox)
     ScreenPtr	pScreen;
     BoxPtr	pBox;
 {
-    miPointerPtr pPointer = MIPOINTER(pDev);
+    miPointerPtr pPointer;
+
+    if (!pDev->isMaster && !pDev->u.master)
+        return;
+    
+    pPointer = MIPOINTER(pDev);
 
     pPointer->limits = *pBox;
     pPointer->confined = PointerConfinedToScreen(pDev);
@@ -347,7 +357,11 @@ miPointerWarpCursor (pDev, pScreen, x, y)
     ScreenPtr	 pScreen;
     int	   	 x, y;
 {
-    miPointerPtr pPointer = MIPOINTER(pDev);
+    miPointerPtr pPointer;
+    
+    if (!pDev->isMaster && !pDev->u.master)
+        return;
+    pPointer = MIPOINTER(pDev);
     SetupScreen (pScreen);
 
     if (pPointer->pScreen != pScreen)
@@ -399,7 +413,7 @@ miPointerUpdateSprite (DeviceIntPtr pDev)
     int			x, y, devx, devy;
     miPointerPtr        pPointer;
 
-    if (!pDev || !pDev->coreEvents)
+    if (!pDev || !pDev->coreEvents || (!pDev->isMaster && !pDev->u.master))
         return;
 
     pPointer = MIPOINTER(pDev);
@@ -488,7 +502,12 @@ miPointerSetScreen(DeviceIntPtr pDev, int screen_no, int x, int y)
 {
 	miPointerScreenPtr pScreenPriv;
 	ScreenPtr pScreen;
-        miPointerPtr pPointer = MIPOINTER(pDev);
+        miPointerPtr pPointer; 
+        
+        if (!pDev->isMaster && !pDev->u.master)
+            return;
+
+        pPointer = MIPOINTER(pDev);
 
 	pScreen = screenInfo.screens[screen_no];
 	pScreenPriv = GetScreenPrivate (pScreen);
@@ -508,8 +527,10 @@ miPointerCurrentScreen ()
 _X_EXPORT ScreenPtr
 miPointerGetScreen(DeviceIntPtr pDev)
 {
-    miPointerPtr pPointer = MIPOINTER(pDev);
-    return pPointer->pScreen;
+    if (!pDev->isMaster && !pDev->u.master)
+        return NULL;
+
+    return MIPOINTER(pDev)->pScreen;
 }
 
 /* Move the pointer to x, y on the current screen, update the sprite, and
@@ -526,9 +547,13 @@ static void
 miPointerMoved (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y,
                      unsigned long time)
 {
-    miPointerPtr pPointer = MIPOINTER(pDev);
+    miPointerPtr pPointer;
     SetupScreen(pScreen);
 
+    if (!pDev->isMaster && !pDev->u.master) 
+        return;
+
+    pPointer = MIPOINTER(pDev);
 
     if (pDev && pDev->coreEvents 
         && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen)
@@ -551,8 +576,12 @@ miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y, unsigned long time)
     ScreenPtr		pScreen;
     ScreenPtr		newScreen;
 
-    miPointerPtr        pPointer = MIPOINTER(pDev);
+    miPointerPtr        pPointer; 
+    
+    if (!pDev->isMaster && !pDev->u.master)
+        return;
 
+    pPointer = MIPOINTER(pDev);
     pScreen = pPointer->pScreen;
     if (!pScreen)
 	return;	    /* called before ready */
@@ -605,9 +634,14 @@ miPointerPosition (int *x, int *y)
 _X_EXPORT void
 miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y)
 {
-    miPointerPtr pPointer = MIPOINTER(pDev);
-    *x = pPointer->x;
-    *y = pPointer->y;
+    if (!pDev->isMaster && !pDev->u.master)
+    {
+        ErrorF("[mi] miPointerGetPosition called for floating device.\n");
+        return;
+    }
+
+    *x = MIPOINTER(pDev)->x;
+    *y = MIPOINTER(pDev)->y;
 }
 
 void
diff --git a/mi/misprite.c b/mi/misprite.c
index 6e42152..6aad36c 100644
--- a/mi/misprite.c
+++ b/mi/misprite.c
@@ -77,7 +77,7 @@ static int miSpriteDevPrivatesIndex;
 #define MISPRITE(dev) \
     ((DevHasCursor(dev)) ? \
        (miCursorInfoPtr) dev->devPrivates[miSpriteDevPrivatesIndex].ptr : \
-       (miCursorInfoPtr) inputInfo.pointer->devPrivates[miSpriteDevPrivatesIndex].ptr)
+       (miCursorInfoPtr) dev->u.master->devPrivates[miSpriteDevPrivatesIndex].ptr)
 
 
 /*
@@ -759,6 +759,12 @@ miSpriteRealizeCursor (pDev, pScreen, pCursor)
     miCursorInfoPtr pCursorInfo;
 
     pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+
+    if (!pDev->isMaster && !pDev->u.master)
+    {
+        ErrorF("[mi] miSpriteRealizeCursor called for floating device.\n");
+        return FALSE;
+    }
     pCursorInfo = MISPRITE(pDev);
 
     if (pCursor == pCursorInfo->pCursor)
@@ -790,7 +796,14 @@ miSpriteSetCursor (pDev, pScreen, pCursor, x, y)
     miSpriteScreenPtr	pScreenPriv;
 
     pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
-    miCursorInfoPtr pPointer = MISPRITE(pDev);
+    miCursorInfoPtr pPointer;
+    
+    if (!pDev->isMaster && !pDev->u.master)
+    {
+        ErrorF("[mi] miSpriteSetCursor called for floating device.\n");
+        return;
+    }
+    pPointer = MISPRITE(pDev);
 
     if (!pCursor)
     {
@@ -905,6 +918,11 @@ miSpriteMoveCursor (pDev, pScreen, x, y)
     CursorPtr pCursor;
 
     pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
+    if (!pDev->isMaster && !pDev->u.master)
+    {
+        ErrorF("[mi] miSpriteMoveCursor called for floating device.\n");
+        return;
+    }
     pCursor = MISPRITE(pDev)->pCursor;
 
     miSpriteSetCursor (pDev, pScreen, pCursor, x, y);
@@ -972,6 +990,11 @@ miSpriteUndisplayCursor(pDev, pScreen)
     DeviceIntPtr pDev;
     ScreenPtr    pScreen;
 {
+    if (!pDev->isMaster && !pDev->u.master)
+    {
+        ErrorF("[mi] miSpriteUndisplayCursor called for floating device.\n");
+        return;
+    }
     if (MISPRITE(pDev)->isUp)
         miSpriteRemoveCursor(pDev, pScreen);
 }
@@ -989,6 +1012,11 @@ miSpriteRemoveCursor (pDev, pScreen)
     miCursorInfoPtr     pCursorInfo;
 
 
+    if (!pDev->isMaster && !pDev->u.master)
+    {
+        ErrorF("[mi] miSpriteRemoveCursor called for floating device.\n");
+        return;
+    }
     DamageDrawInternal (pScreen, TRUE);
     pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
     pCursorInfo = MISPRITE(pDev);
@@ -1026,6 +1054,11 @@ miSpriteSaveUnderCursor(pDev, pScreen)
     CursorPtr		pCursor;
     miCursorInfoPtr     pCursorInfo;
 
+    if (!pDev->isMaster && !pDev->u.master)
+    {
+        ErrorF("[mi] miSpriteSaveUnderCursor called for floating device.\n");
+        return;
+    }
     DamageDrawInternal (pScreen, TRUE);
     pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
     pCursorInfo = MISPRITE(pDev);
@@ -1065,6 +1098,12 @@ miSpriteRestoreCursor (pDev, pScreen)
     int			x, y;
     CursorPtr		pCursor;
     miCursorInfoPtr     pCursorInfo;
+    
+    if (!pDev->isMaster && !pDev->u.master)
+    {
+        ErrorF("[mi] miSpriteRestoreCursor called for floating device.\n");
+        return;
+    }
 
     DamageDrawInternal (pScreen, TRUE);
     pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
@@ -1106,6 +1145,11 @@ miSpriteComputeSaved (pDev, pScreen)
     CursorPtr	    pCursor;
     miCursorInfoPtr pCursorInfo;
 
+    if (!pDev->isMaster && !pDev->u.master)
+    {
+        ErrorF("[mi] miSpriteComputeSaved called for floating device.\n");
+        return;
+    }
     pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
     pCursorInfo = MISPRITE(pDev);
 
commit 1d9ebbac8c589cae7e4952083692b6d148def9bc
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 18:46:12 2007 +0930

    dix: Make InitCoreDevices use AllocMasterDevice.
    
    Also change naming a bit, append "pointer" and "keyboard" to master devices
    instead of -ptr and -keybd.

diff --git a/dix/devices.c b/dix/devices.c
index ef5ebf9..af086a4 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -485,68 +485,27 @@ CorePointerProc(DeviceIntPtr pDev, int what)
 void
 InitCoreDevices(void)
 {
-    DeviceIntPtr dev;
-
     if (CoreDevicePrivatesGeneration != serverGeneration) {
         CoreDevicePrivatesIndex = AllocateDevicePrivateIndex();
         CoreDevicePrivatesGeneration = serverGeneration;
     }
 
-    if (!inputInfo.keyboard) {
-        dev = AddInputDevice(CoreKeyboardProc, TRUE);
-        if (!dev)
-            FatalError("Failed to allocate core keyboard");
-        dev->name = strdup("Virtual core keyboard");
-#ifdef XKB
-        dev->public.processInputProc = ProcessOtherEvent;
-        dev->public.realInputProc = ProcessOtherEvent;
-        if (!noXkbExtension)
-            XkbSetExtension(dev, ProcessKeyboardEvent);
-#else
-        dev->public.processInputProc = ProcessKeyboardEvent;
-        dev->public.realInputProc = ProcessKeyboardEvent;
-#endif
-        dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
-        dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
-        dev->coreEvents = TRUE;
-        dev->spriteInfo->spriteOwner = FALSE;
-        if (!AllocateDevicePrivate(dev, CoreDevicePrivatesIndex))
-            FatalError("Couldn't allocate keyboard devPrivates\n");
-        dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
-        dev->u.lastSlave = NULL;
-        dev->isMaster = TRUE;
-        (void)ActivateDevice(dev);
-
-        inputInfo.keyboard = dev;
-    }
-
-    if (!inputInfo.pointer) {
-        dev = AddInputDevice(CorePointerProc, TRUE);
-        if (!dev)
-            FatalError("Failed to allocate core pointer");
-        dev->name = strdup("Virtual core pointer");
-#ifdef XKB
-        dev->public.processInputProc = ProcessOtherEvent;
-        dev->public.realInputProc = ProcessOtherEvent;
-        if (!noXkbExtension)
-           XkbSetExtension(dev, ProcessPointerEvent);
-#else
-        dev->public.processInputProc = ProcessPointerEvent;
-        dev->public.realInputProc = ProcessPointerEvent;
-#endif
-        dev->deviceGrab.ActivateGrab = ActivatePointerGrab;
-        dev->deviceGrab.DeactivateGrab = DeactivatePointerGrab;
-        dev->coreEvents = TRUE;
-        dev->spriteInfo->spriteOwner = TRUE;
-        if (!AllocateDevicePrivate(dev, CoreDevicePrivatesIndex))
-            FatalError("Couldn't allocate pointer devPrivates\n");
-        dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
-        dev->u.lastSlave = NULL;
-        dev->isMaster = TRUE;
-        (void)ActivateDevice(dev);
-
-        inputInfo.pointer = dev;
-    }
+    if (AllocMasterDevice("Virtual core", 
+                          &inputInfo.pointer, 
+                          &inputInfo.keyboard) == BadAlloc)
+        FatalError("Failed to allocate core devices");
+
+    if (!AllocateDevicePrivate(inputInfo.keyboard, CoreDevicePrivatesIndex))
+        FatalError("Couldn't allocate keyboard devPrivates\n");
+    inputInfo.keyboard->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
+
+    if (!AllocateDevicePrivate(inputInfo.pointer, CoreDevicePrivatesIndex))
+        FatalError("Couldn't allocate pointer devPrivates\n");
+    inputInfo.pointer->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
+
+    ActivateDevice(inputInfo.keyboard);
+    ActivateDevice(inputInfo.pointer);
+
 }
 
 /**
@@ -2389,9 +2348,9 @@ AllocMasterDevice(char* name, DeviceIntPtr* ptr, DeviceIntPtr* keybd)
     if (!pointer)
         return BadAlloc;
 
-    pointer->name = xcalloc(strlen(name) + strlen("-ptr") + 1, sizeof(char));
+    pointer->name = xcalloc(strlen(name) + strlen(" pointer") + 1, sizeof(char));
     strcpy(pointer->name, name);
-    strcat(pointer->name, "-ptr");
+    strcat(pointer->name, " pointer");
 
 #ifdef XKB
     pointer->public.processInputProc = ProcessOtherEvent;
@@ -2414,9 +2373,9 @@ AllocMasterDevice(char* name, DeviceIntPtr* ptr, DeviceIntPtr* keybd)
     if (!keyboard)
         return BadAlloc;
 
-    keyboard->name = xcalloc(strlen(name) + strlen("-keybd") + 1, sizeof(char));
+    keyboard->name = xcalloc(strlen(name) + strlen(" keyboard") + 1, sizeof(char));
     strcpy(keyboard->name, name);
-    strcat(keyboard->name, "-keybd");
+    strcat(keyboard->name, " keyboard");
 
 #ifdef XKB
     keyboard->public.processInputProc = ProcessOtherEvent;
commit 299573f4617c3b5599bb65069e96d050277b9471
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 18:40:15 2007 +0930

    dix: add AllocMasterDevice for creation of new master devices.
    
    Devices are initiated pretty much the same as the core devices.

diff --git a/dix/devices.c b/dix/devices.c
index 3e5405b..ef5ebf9 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2374,3 +2374,69 @@ NextFreePointerDevice()
             return dev;
     return NULL;
 }
+/**
+ * Create a new master device (== one pointer, one keyboard device).
+ * Only allocates the devices, you will need to call ActivateDevice() and
+ * EnableDevice() manually.
+ */
+int
+AllocMasterDevice(char* name, DeviceIntPtr* ptr, DeviceIntPtr* keybd)
+{
+    DeviceIntPtr pointer;
+    DeviceIntPtr keyboard;
+
+    pointer = AddInputDevice(CorePointerProc, TRUE);
+    if (!pointer)
+        return BadAlloc;
+
+    pointer->name = xcalloc(strlen(name) + strlen("-ptr") + 1, sizeof(char));
+    strcpy(pointer->name, name);
+    strcat(pointer->name, "-ptr");
+
+#ifdef XKB
+    pointer->public.processInputProc = ProcessOtherEvent;
+    pointer->public.realInputProc = ProcessOtherEvent;
+    if (!noXkbExtension)
+        XkbSetExtension(pointer, ProcessPointerEvent);
+#else
+    pointer->public.processInputProc = ProcessPointerEvent;
+    pointer->public.realInputProc = ProcessPointerEvent;
+#endif
+    pointer->deviceGrab.ActivateGrab = ActivatePointerGrab;
+    pointer->deviceGrab.DeactivateGrab = DeactivatePointerGrab;
+    pointer->coreEvents = TRUE;
+    pointer->spriteInfo->spriteOwner = TRUE;
+
+    pointer->u.lastSlave = NULL;
+    pointer->isMaster = TRUE;
+
+    keyboard = AddInputDevice(CoreKeyboardProc, TRUE);
+    if (!keyboard)
+        return BadAlloc;
+
+    keyboard->name = xcalloc(strlen(name) + strlen("-keybd") + 1, sizeof(char));
+    strcpy(keyboard->name, name);
+    strcat(keyboard->name, "-keybd");
+
+#ifdef XKB
+    keyboard->public.processInputProc = ProcessOtherEvent;
+    keyboard->public.realInputProc = ProcessOtherEvent;
+    if (!noXkbExtension)
+        XkbSetExtension(keyboard, ProcessKeyboardEvent);
+#else
+    keyboard->public.processInputProc = ProcessKeyboardEvent;
+    keyboard->public.realInputProc = ProcessKeyboardEvent;
+#endif
+    keyboard->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
+    keyboard->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
+    keyboard->coreEvents = TRUE;
+    keyboard->spriteInfo->spriteOwner = FALSE;
+
+    keyboard->u.lastSlave = NULL;
+    keyboard->isMaster = TRUE;
+
+    *ptr = pointer;
+    *keybd = keyboard;
+
+    return Success;
+}
diff --git a/include/input.h b/include/input.h
index a176bba..d6a38e6 100644
--- a/include/input.h
+++ b/include/input.h
@@ -477,6 +477,10 @@ extern Bool UnregisterPairingClient(ClientPtr client);
 extern DeviceIntPtr GuessFreePointerDevice(void);
 extern DeviceIntPtr NextFreePointerDevice(void);
 
+extern int AllocMasterDevice(char* name,
+                             DeviceIntPtr* ptr,
+                             DeviceIntPtr* keybd);
+
 /* Window/device based access control */
 extern Bool ACRegisterClient(ClientPtr client);
 extern Bool ACUnregisterClient(ClientPtr client);
commit 5fe9bfd23f17b84c3afaa82f75a7c517c9f8e0d3
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 18:23:48 2007 +0930

    xfree86: NIDR: don't call PairDevices explicitly.
             set isMaster to FALSE explicitly.
    
    Pairing isn't necessary, attachment should be done in EnableDevices.

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 711bf94..fc846ba 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -172,6 +172,7 @@ xf86ActivateDevice(LocalDevicePtr local)
         local->dev = dev;      
         
         dev->coreEvents = local->flags & XI86_ALWAYS_CORE; 
+        dev->isMaster = FALSE;
         dev->spriteInfo->spriteOwner = FALSE;
 
         if (DeviceIsPointerType(dev))
@@ -447,9 +448,6 @@ NewInputDeviceRequest (InputOption *options, DeviceIntPtr *pdev)
         (!is_auto || xf86Info.autoEnableDevices))
         EnableDevice(dev);
 
-    if (!IsPointerDevice(dev))
-        PairDevices(NULL, GuessFreePointerDevice(), dev);
-
     /* send enter/leave event, update sprite window */
     CheckMotion(NULL, dev);
 
commit 5eb033835e92ea951cc385fd709af9656b3772d8
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 18:03:52 2007 +0930

    mi: don't exclude inputInfo.pointer from rendering.

diff --git a/mi/mipointer.c b/mi/mipointer.c
index 8dc7c7f..eabc435 100644
--- a/mi/mipointer.c
+++ b/mi/mipointer.c
@@ -399,7 +399,7 @@ miPointerUpdateSprite (DeviceIntPtr pDev)
     int			x, y, devx, devy;
     miPointerPtr        pPointer;
 
-    if (!pDev || pDev == inputInfo.pointer || !pDev->coreEvents)
+    if (!pDev || !pDev->coreEvents)
         return;
 
     pPointer = MIPOINTER(pDev);
@@ -530,7 +530,7 @@ miPointerMoved (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y,
     SetupScreen(pScreen);
 
 
-    if (pDev && (pDev->coreEvents || pDev == inputInfo.pointer)
+    if (pDev && pDev->coreEvents 
         && !pScreenPriv->waitForUpdate && pScreen == pPointer->pSpriteScreen)
     {
 	pPointer->devx = x;
@@ -557,7 +557,7 @@ miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y, unsigned long time)
     if (!pScreen)
 	return;	    /* called before ready */
 
-    if (!pDev || !(pDev->coreEvents || pDev == inputInfo.pointer))
+    if (!pDev || !pDev->coreEvents)
         return;
 
     if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height)
commit b697c4ed145968d3c3281bb85e628f1b068b09fc
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 17:47:06 2007 +0930

    dix: CheckPassiveGrabOnWindow: only get paired device for non-keyboards.

diff --git a/dix/events.c b/dix/events.c
index 50d06c4..d342d36 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -3243,7 +3243,12 @@ CheckPassiveGrabsOnWindow(
 
 	gdev= grab->modifierDevice;
         if (grab->coreGrab)
-            gdev = GetPairedDevice(device);
+        {
+            if (IsPointerDevice(device))
+                gdev = GetPairedDevice(device);
+            else
+                gdev = device;
+        }
 	xkbi= gdev->key->xkbInfo;
 #endif
 	tempGrab.modifierDevice = grab->modifierDevice;
commit caa69d8f7b92b80669df02e1001409d7c653e7e4
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 17:38:13 2007 +0930

    dix: fix detritus from adding lastSlave field.

diff --git a/dix/devices.c b/dix/devices.c
index 75dfa69..3e5405b 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -302,7 +302,7 @@ DisableDevice(DeviceIntPtr dev)
     {
         for (other = inputInfo.devices; other; other = other->next) 
         {
-            if (other->master == dev)
+            if (other->u.master == dev)
                 AttachDevice(NULL, dev, NULL);
         }
     }
@@ -513,7 +513,7 @@ InitCoreDevices(void)
         if (!AllocateDevicePrivate(dev, CoreDevicePrivatesIndex))
             FatalError("Couldn't allocate keyboard devPrivates\n");
         dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
-        dev->master = NULL;
+        dev->u.lastSlave = NULL;
         dev->isMaster = TRUE;
         (void)ActivateDevice(dev);
 
@@ -541,7 +541,7 @@ InitCoreDevices(void)
         if (!AllocateDevicePrivate(dev, CoreDevicePrivatesIndex))
             FatalError("Couldn't allocate pointer devPrivates\n");
         dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
-        dev->master = NULL;
+        dev->u.lastSlave = NULL;
         dev->isMaster = TRUE;
         (void)ActivateDevice(dev);
 
@@ -2255,7 +2255,7 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
     if (!dev || !master)
         return BadDevice;
 
-    if (master->master) /* can't attach to slave device */
+    if (!master->isMaster) /* can't attach to slave device */
         return BadDevice;
 
     if (!pairingClient)
@@ -2263,7 +2263,7 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
     else if (client && pairingClient != client)
         return BadAccess;
 
-    dev->master = master;
+    dev->u.master = master;
     dev->spriteInfo->sprite = master->spriteInfo->sprite;
 
     return Success;
@@ -2277,8 +2277,8 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
 _X_EXPORT DeviceIntPtr
 GetPairedDevice(DeviceIntPtr dev)
 {
-    if (!dev->isMaster && dev->master)
-        dev = dev->master;
+    if (!dev->isMaster && dev->u.master)
+        dev = dev->u.master;
 
     if (!dev->spriteInfo->paired)
     {
commit 90d077e537ac4cb7d79d67afcf3984a3e8d65fe8
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 17:37:33 2007 +0930

    dix: GetPointerEvents: get state from master device before applying valuators.
    
    We need to get lastx/y from the master device before we start applying
    acceleration etc. Otherwise we get jumping cursors, which is reasonably bad.

diff --git a/dix/getevents.c b/dix/getevents.c
index 7457078..694d404 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -544,6 +544,7 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
     CARD32* valptr;
     deviceKeyButtonPointer *kbp = NULL;
     rawDeviceEvent* ev;
+    DeviceIntPtr master;
 
     /* Thanks to a broken lib, we _always_ have to chase DeviceMotionNotifies
      * with DeviceValuators. */
@@ -558,17 +559,55 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
 
     if ((type == ButtonPress || type == ButtonRelease) && !pDev->button)
         return 0;
-
+    
     /* FIXME: I guess it should, in theory, be possible to post button events
      *        from devices without valuators. */
     if (!pDev->valuator)
         return 0;
 
-    num_events = 2;
-
     if (type == MotionNotify && num_valuators <= 0)
         return 0;
 
+    ms = GetTimeInMillis();
+
+    num_events = 2;
+
+    master = pDev->u.master;
+    if (master && master->u.lastSlave != pDev)
+    {
+#if 0
+        /* XXX: we should enqueue the state changed event here */
+        devStateEvent *state; 
+        num_events++;
+        state = events->event;
+
+        state->type = GenericEvent;
+        state->extension = IReqCode;
+        state->evtype = XI_DeviceStateChangedNotify;
+        state->deviceid = master->deviceid;
+        state->new_slave = pDev->id;
+        state->time = ms;
+        events++;
+
+#endif
+
+        /* now we need to update our device to the master's device - welcome
+         * to hell. 
+         * We need to match each device's capabilities to the previous
+         * capabilities as used by the master. Valuator[N] of master has to
+         * be written into valuator[N] of pDev. For all relative valuators.
+         * Otherwise we get jumpy valuators.
+         *
+         * However, this if iffy, if pDev->num_valuators !=
+         * master->num_valuators. What do we do with the others? 
+         * 
+         * XXX: just do lastx/y for now.
+         */
+        pDev->valuator->lastx = master->valuator->lastx;
+        pDev->valuator->lasty = master->valuator->lasty;
+        master->u.lastSlave = pDev;
+    }
+
     /* Do we need to send a DeviceValuator event? */
     if (!coreOnly && sendValuators) {
         if ((((num_valuators - 1) / 6) + 1) > MAX_VALUATOR_EVENTS)
@@ -582,7 +621,6 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
     if (first_valuator < 0 || final_valuator > pDev->valuator->numAxes)
         return 0;
 
-    ms = GetTimeInMillis();
 
 
     /* fill up the raw event, after checking that it is large enough to
@@ -667,6 +705,8 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
 
     pDev->valuator->lastx = x;
     pDev->valuator->lasty = y;
+    master->valuator->lastx = x;
+    master->valuator->lasty = y;
 
     if (!coreOnly)
     {
commit b6ccf721b0a582150858d68f91967fb4e319c340
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 17:35:06 2007 +0930

    include: add "lastSlave" field to DeviceIntRec.
    
    Set to the last slave device that routed events through the master.

diff --git a/include/inputstr.h b/include/inputstr.h
index d96e24a..b2304dd 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -400,7 +400,10 @@ typedef struct _DeviceIntRec {
     int			nPrivates;
     DeviceUnwrapProc    unwrapProc;
     SpriteInfoPtr       spriteInfo;
+    union {
     DeviceIntPtr        master;       /* master device */
+    DeviceIntPtr        lastSlave;    /* last slave device used */
+    } u;
 } DeviceIntRec;
 
 typedef struct {
commit e6bd8ae0608bd8379c5ac962f69cd0bcc54f9734
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 15:59:30 2007 +0930

    dix: set the device's sprite when using AttachDevice
    
    Sprite is set to the master device's sprite.

diff --git a/dix/devices.c b/dix/devices.c
index 0f43d12..75dfa69 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2264,6 +2264,7 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
         return BadAccess;
 
     dev->master = master;
+    dev->spriteInfo->sprite = master->spriteInfo->sprite;
 
     return Success;
 }
commit 271d4c3d6255318aabb9ad1ea444f534ed456f0b
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 15:50:07 2007 +0930

    xfree86: remove XI86_SHARED_POINTER flag.
    
    Not needed anymore. By default, all devices are slaves of first master device.

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index acc3ae6..711bf94 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -135,11 +135,6 @@ xf86ProcessCommonOptions(LocalDevicePtr local,
         xf86Msg(X_CONFIG, "%s: always reports core events\n", local->name);
     }
 
-    if (xf86SetBoolOption(list, "SharedPointer", 0)) {
-        local->flags |= XI86_SHARED_POINTER;
-        xf86Msg(X_CONFIG, "%s: is shared device\n", local->name);
-    } 
-
     if (xf86SetBoolOption(list, "SendDragEvents", 1)) {
         local->flags |= XI86_SEND_DRAG_EVENTS;
     } else {
@@ -177,7 +172,7 @@ xf86ActivateDevice(LocalDevicePtr local)
         local->dev = dev;      
         
         dev->coreEvents = local->flags & XI86_ALWAYS_CORE; 
-        dev->spriteInfo->spriteOwner = !(local->flags & XI86_SHARED_POINTER);
+        dev->spriteInfo->spriteOwner = FALSE;
 
         if (DeviceIsPointerType(dev))
         {
diff --git a/hw/xfree86/common/xf86Xinput.h b/hw/xfree86/common/xf86Xinput.h
index 7fddfb1..d88bbbe 100644
--- a/hw/xfree86/common/xf86Xinput.h
+++ b/hw/xfree86/common/xf86Xinput.h
@@ -81,7 +81,6 @@
 #define XI86_CORE_KEYBOARD	0x20 /* device is the core keyboard */
 #define XI86_POINTER_CAPABLE	0x40 /* capable of being a core pointer */
 #define XI86_KEYBOARD_CAPABLE	0x80 /* capable of being a core keyboard */
-#define XI86_SHARED_POINTER     0x100 /* device shares core cursor */
 
 #define XI_PRIVATE(dev) \
 	(((LocalDevicePtr)((dev)->public.devicePrivate))->private)
commit c7b878b90406781c97db751a9b454e2b6baee0e1
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 15:07:31 2007 +0930

    dix: don't treat VCK/VCP separately in DevHasCursor, IsPointer/KeyboardDevice.

diff --git a/dix/events.c b/dix/events.c
index 5bdf145..50d06c4 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -322,7 +322,7 @@ XItoCoreType(int xitype)
 _X_EXPORT Bool
 DevHasCursor(DeviceIntPtr pDev) 
 {
-    return (pDev != inputInfo.pointer && pDev->spriteInfo->spriteOwner);
+    return pDev->spriteInfo->spriteOwner;
 }
 
 /*
@@ -332,7 +332,7 @@ DevHasCursor(DeviceIntPtr pDev)
 _X_EXPORT Bool
 IsPointerDevice(DeviceIntPtr dev)
 {
-    return ((dev->valuator && dev->button) || dev == inputInfo.pointer);
+    return (dev->valuator && dev->button);
 }
 
 /*
@@ -342,7 +342,7 @@ IsPointerDevice(DeviceIntPtr dev)
 _X_EXPORT Bool
 IsKeyboardDevice(DeviceIntPtr dev)
 {
-    return ((dev->key && dev->kbdfeed) || dev == inputInfo.keyboard);
+    return (dev->key && dev->kbdfeed);
 }
 
 #ifdef XEVIE
commit e9f149fb56747f7eaa0f714dce97b067b007c47e
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 14:24:20 2007 +0930

    Fix up detritus from removing GetPairedPointer/Keyboard.

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 1bcc101..49400e8 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -144,12 +144,12 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
          */
         if (IsPointerDevice(device))
         {
-            kbd = GetPairedKeyboard(device);
+            kbd = GetPairedDevice(device);
             mouse = device;
         }
         else
         {
-            mouse = GetPairedPointer(device);
+            mouse = GetPairedDevice(device);
             kbd = device;
         }
         xE->u.keyButtonPointer.state = (kbd) ? (kbd->key->state) : 0;
diff --git a/Xi/getpairp.c b/Xi/getpairp.c
index 4f1ff03..1833a00 100644
--- a/Xi/getpairp.c
+++ b/Xi/getpairp.c
@@ -73,27 +73,20 @@ ProcXGetPairedPointer(ClientPtr client)
     REQUEST_SIZE_MATCH(xGetPairedPointerReq);
 
     kbd = LookupDeviceIntRec(stuff->deviceid);
-    if (!kbd || !kbd->key) {
+    if (!kbd || !kbd->key || !kbd->isMaster) {
         SendErrorToClient(client, IReqCode, X_GetPairedPointer,
                 stuff->deviceid, BadDevice);
         return Success;
     }
 
-    ptr = GetPairedPointer(kbd);
+    ptr = GetPairedDevice(kbd);
 
     rep.repType = X_Reply;
     rep.RepType = X_GetPairedPointer;
     rep.length = 0;
     rep.sequenceNumber = client->sequence;
-    if (ptr == inputInfo.pointer)
-    {
-        rep.paired = FALSE;
-        rep.deviceid = 0;
-    } else 
-    {
-        rep.paired = TRUE;
-        rep.deviceid = ptr->id;
-    }
+    rep.paired = TRUE;
+    rep.deviceid = ptr->id;
     WriteReplyToClient(client, sizeof(xGetPairedPointerReply), &rep);
     return Success;
 }
diff --git a/dix/events.c b/dix/events.c
index 58188c8..5bdf145 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -3243,7 +3243,7 @@ CheckPassiveGrabsOnWindow(
 
 	gdev= grab->modifierDevice;
         if (grab->coreGrab)
-            gdev = GetPairedKeyboard(device);
+            gdev = GetPairedDevice(device);
 	xkbi= gdev->key->xkbInfo;
 #endif
 	tempGrab.modifierDevice = grab->modifierDevice;
@@ -3294,7 +3294,7 @@ CheckPassiveGrabsOnWindow(
             if (xE->u.u.type < LASTEvent)
             {
                 grab->device = device; 
-                grab->modifierDevice = GetPairedKeyboard(device);
+                grab->modifierDevice = GetPairedDevice(device);
             }
 
             /* In some cases a passive core grab may exist, but the client
@@ -3453,9 +3453,7 @@ DeliverFocusedEvent(DeviceIntPtr keybd, xEvent *xE, WindowPtr window, int count)
 	if (DeliverDeviceEvents(window, xE, NullGrab, focus, keybd, count))
 	    return;
     }
-    pointer = GetPairedPointer(keybd);
-    if (!pointer)
-        pointer = inputInfo.pointer;
+    pointer = GetPairedDevice(keybd);
     /* just deliver it to the focus window */
     FixUpEventFromWindow(pointer, xE, focus, None, FALSE);
     if (xE->u.u.type & EXTENSION_EVENT_BASE)
@@ -3684,7 +3682,7 @@ drawable.id:0;
 #endif
     /* ProcessOtherEvent already updated the keyboard's state, so we need to
      * access prev_state here! */
-    XE_KBPTR.state = (keyc->prev_state | GetPairedPointer(keybd)->button->state);
+    XE_KBPTR.state = (keyc->prev_state | GetPairedDevice(keybd)->button->state);
     XE_KBPTR.rootX = keybd->spriteInfo->sprite->hot.x;
     XE_KBPTR.rootY = keybd->spriteInfo->sprite->hot.y;
     key = xE->u.u.detail;
@@ -3796,7 +3794,7 @@ ProcessPointerEvent (xEvent *xE, DeviceIntPtr mouse, int count)
     SpritePtr           pSprite = mouse->spriteInfo->sprite;
 
 #ifdef XKB
-    XkbSrvInfoPtr xkbi= GetPairedKeyboard(mouse)->key->xkbInfo;
+    XkbSrvInfoPtr xkbi= GetPairedDevice(mouse)->key->xkbInfo;
 #endif
 #ifdef XEVIE
     if(xevieFlag && clients[xevieClientIndex] && !xeviegrabState &&
@@ -4141,7 +4139,7 @@ EnterLeaveEvent(
     int                 mskidx;
     OtherInputMasks     *inputMasks;
 
-    keybd = GetPairedKeyboard(mouse);
+    keybd = GetPairedDevice(mouse);
 
     if ((pWin == mouse->valuator->motionHintWindow) &&
 	(detail != NotifyInferior))
@@ -4682,7 +4680,7 @@ SetInputFocus(
     if (IsKeyboardDevice(dev))
         keybd = dev;
     else
-        keybd = GetPairedKeyboard(dev);
+        keybd = GetPairedDevice(dev);
 
     if ((focusID == None) || (focusID == PointerRoot))
 	focusWin = (WindowPtr)(long)focusID;
@@ -5697,7 +5695,7 @@ ProcGrabButton(ClientPtr client)
     }
 
     pointer = PickPointer(client);
-    modifierDevice = GetPairedKeyboard(pointer);
+    modifierDevice = GetPairedDevice(pointer);
 
     grab = CreateGrab(client->index, pointer, pWin, 
         (Mask)stuff->eventMask, (Bool)stuff->ownerEvents,
diff --git a/hw/xfree86/common/xf86DGA.c b/hw/xfree86/common/xf86DGA.c
index 553679d..74788be 100644
--- a/hw/xfree86/common/xf86DGA.c
+++ b/hw/xfree86/common/xf86DGA.c
@@ -1038,7 +1038,7 @@ DGAProcessKeyboardEvent (ScreenPtr pScreen, dgaEvent *de, DeviceIntPtr keybd)
     xEvent	    core;
     KeyClassPtr	    keyc = keybd->key;
     DGAScreenPtr    pScreenPriv = DGA_GET_SCREEN_PRIV(pScreen);
-    DeviceIntPtr    pointer = GetPairedPointer(keybd);
+    DeviceIntPtr    pointer = GetPairedDevice(keybd);
     
     coreEquiv = de->u.u.type - *XDGAEventBase;
 
@@ -1145,7 +1145,7 @@ DGAProcessPointerEvent (ScreenPtr pScreen, dgaEvent *de, DeviceIntPtr mouse)
      * Fill in remaining event state
      */
     de->u.event.screen = pScreen->myNum;
-    de->u.event.state = butc->state | GetPairedKeyboard(mouse)->key->state;
+    de->u.event.state = butc->state | GetPairedDevice(mouse)->key->state;
     /*
      * Keep the core state in sync by duplicating what
      * CoreProcessPointerEvent does
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index c6df92c..acc3ae6 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -723,7 +723,7 @@ xf86PostKeyboardEvent(DeviceIntPtr      device,
     int index;
 
 #if XFreeXDGA
-    DeviceIntPtr pointer = GetPairedPointer(device);
+    DeviceIntPtr pointer = GetPairedDevice(device);
 
     if (miPointerGetScreen(pointer)) {
         index = miPointerGetScreen(pointer)->myNum;
diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c
index dd4d7c1..32b9e0d 100644
--- a/xkb/xkbActions.c
+++ b/xkb/xkbActions.c
@@ -1273,7 +1273,7 @@ xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev);
 	    keyc->modifierMap[key] = 0;
             tmpdev = dev;
         } else
-            tmpdev = GetPairedPointer(dev);
+            tmpdev = GetPairedDevice(dev);
 
 
         UNWRAP_PROCESS_INPUT_PROC(tmpdev,xkbPrivPtr, backupproc);
commit 840bde3d32f3627dfc3d7d8b6564a61a8014933b
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 13:09:35 2007 +0930

    dix: GetPairedDevice: return dev paired with master for slave devices.

diff --git a/dix/devices.c b/dix/devices.c
index a4360e5..0f43d12 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2268,11 +2268,17 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
     return Success;
 }
 
-/* Return the device paired with the given device or NULL.
+/**
+ * Return the device paired with the given device or NULL.
+ * Returns the device paired with the parent master if the given device is a
+ * slave device.
  */
 _X_EXPORT DeviceIntPtr
 GetPairedDevice(DeviceIntPtr dev)
 {
+    if (!dev->isMaster && dev->master)
+        dev = dev->master;
+
     if (!dev->spriteInfo->paired)
     {
         ErrorF("[dix] No device paired with %d (%s).\n", 
commit 6c259a08d917f94fd7381453b625b07826d3ef9c
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 13:09:19 2007 +0930

    include: remove unused GetPairedPointer/Keyboard declarations.

diff --git a/include/input.h b/include/input.h
index f41514a..a176bba 100644
--- a/include/input.h
+++ b/include/input.h
@@ -469,8 +469,7 @@ extern int AttachDevice(ClientPtr client,
                         DeviceIntPtr slave,
                         DeviceIntPtr master);
 
-extern DeviceIntPtr GetPairedPointer(DeviceIntPtr kbd);
-extern DeviceIntPtr GetPairedKeyboard(DeviceIntPtr ptr);
+extern DeviceIntPtr GetPairedDevice(DeviceIntPtr kbd);
 
 extern Bool RegisterPairingClient(ClientPtr client);
 extern Bool UnregisterPairingClient(ClientPtr client);
commit 9ecbbf198f4cec398897736e173e7e8c56bf6f94
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Sun Oct 14 08:00:06 2007 +0930

    dix: adjust PickPointer and PickKeyboard to get the first master device.
    
    Simplifies it a lot, since we always have at least one master device
    available at all times, so less mucking around.

diff --git a/dix/events.c b/dix/events.c
index b84d18d..58188c8 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -6117,34 +6117,22 @@ SetClientPointer(ClientPtr client, ClientPtr setter, DeviceIntPtr device)
     return TRUE;
 }
 
-/* PickPointer will pick an appropriate pointer for the given client.
- *
- * If a client pointer is set, it will pick the client pointer, otherwise the
- * first available pointer in the list. If no physical device is attached, it
- * will pick the core pointer, but will not store it on the client.
- */
+/* PickPointer will pick an appropriate pointer for the given client.  */
 _X_EXPORT DeviceIntPtr
 PickPointer(ClientPtr client)
 {
     if (!client->clientPtr)
     {
-        /* look if there is a real device attached */
         DeviceIntPtr it = inputInfo.devices;
         while (it)
         {
-            if (it != inputInfo.pointer && it->spriteInfo->spriteOwner)
+            if (it->isMaster && it->spriteInfo->spriteOwner)
             {
                 client->clientPtr = it;
                 break;
             }
             it = it->next;
         }
-
-        if (!it)
-        {
-            ErrorF("[dix] Picking VCP\n");
-            return inputInfo.pointer;
-        }
     }
     return client->clientPtr;
 }
@@ -6159,18 +6147,15 @@ _X_EXPORT DeviceIntPtr
 PickKeyboard(ClientPtr client)
 {
     DeviceIntPtr ptr = PickPointer(client);
-    DeviceIntPtr kbd = inputInfo.devices;
+    DeviceIntPtr kbd = ptr->spriteInfo->paired;
 
-    while(kbd)
+    if (!kbd)
     {
-        if (ptr != kbd && 
-            IsKeyboardDevice(kbd) && 
-            ptr->spriteInfo->sprite == kbd->spriteInfo->sprite)
-            return kbd;
-        kbd = kbd->next;
+        ErrorF("[dix] ClientPointer not paired with a keyboard. This " 
+                "is a bug.\n");
     }
 
-    return (kbd) ? kbd : inputInfo.keyboard;
+    return kbd;
 }
 
 /* A client that has one or more core grabs does not get core events from
commit 0c5f65ecd3ad11fbdb1cab3cb1d0eb4f33bb4e35
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Sun Oct 14 07:57:24 2007 +0930

    dix: don't allow slave devices as ClientPointer

diff --git a/dix/events.c b/dix/events.c
index 8141a40..b84d18d 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -6103,6 +6103,16 @@ WriteEventsToClient(ClientPtr pClient, int count, xEvent *events)
 _X_EXPORT Bool
 SetClientPointer(ClientPtr client, ClientPtr setter, DeviceIntPtr device)
 {
+    if (!device->isMaster)
+    {
+        ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n");
+        return FALSE;
+    } else if (!device->spriteInfo->spriteOwner)
+    {
+        ErrorF("[dix] Device %d does not have a sprite. " 
+                "Cannot be ClientPointer\n", device->id);
+        return FALSE;
+    }
     client->clientPtr = device;
     return TRUE;
 }
commit 9ccc9ab6f29f68298b68cdb5c9b4bd57a095f05a
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Sun Oct 14 07:53:00 2007 +0930

    dix: don't call CloseDevice on VCP/VCK separately.

diff --git a/dix/devices.c b/dix/devices.c
index b47ae59..a4360e5 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -751,9 +751,6 @@ CloseDownDevices(void)
 	CloseDevice(dev);
     }
 
-    CloseDevice(inputInfo.keyboard);
-    CloseDevice(inputInfo.pointer);
-
     inputInfo.devices = NULL;
     inputInfo.off_devices = NULL;
     inputInfo.keyboard = NULL;
commit e4fd981b48723b77a6c1a528638a771b9cc35472
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Sun Oct 14 07:52:11 2007 +0930

    dix: check for isMaster before calling DeviceCursorCleanup.

diff --git a/dix/devices.c b/dix/devices.c
index 7a9932a..b47ae59 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -624,7 +624,7 @@ CloseDevice(DeviceIntPtr dev)
 	(void)(*dev->deviceProc)(dev, DEVICE_CLOSE);
 
     /* free sprite memory */
-    if (IsPointerDevice(dev))
+    if (dev->isMaster && dev->spriteInfo->sprite)
         screen->DeviceCursorCleanup(dev, screen);
 
     xfree(dev->name);
commit 7503d1340726e0a529f04304d177ed2ceb8fbc91
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Sun Oct 14 07:50:13 2007 +0930

    dix: don't check VCK and VCP separately when looking for device ids.
    
    Both are part of the device list again, so we cover them there.

diff --git a/dix/devices.c b/dix/devices.c
index b4d04b4..7a9932a 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -107,10 +107,6 @@ AddInputDevice(DeviceProc deviceProc, Bool autoStart)
 
     /* Find next available id */
     memset(devind, 0, sizeof(char)*MAX_DEVICES);
-    if (inputInfo.keyboard)
-        devind[inputInfo.keyboard->id]++;
-    if (inputInfo.pointer)
-        devind[inputInfo.pointer->id]++;
     for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next)
 	devind[devtmp->id]++;
     for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next)
commit 032e906711202d376af95b37bb0cdf14a3648256
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 11:57:42 2007 +0930

    dix: Remove GetPairedPointer, GetPairedKeyboard in favour of GetPairedDevice.

diff --git a/dix/devices.c b/dix/devices.c
index f886120..b4d04b4 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2274,46 +2274,19 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
 
     return Success;
 }
-/* Return the pointer that is paired with the given keyboard. If no pointer is
- * paired, return the virtual core pointer 
- */ 
-DeviceIntPtr
-GetPairedPointer(DeviceIntPtr kbd)
-{
-    DeviceIntPtr ptr = inputInfo.devices;
-    while(ptr)
-    {
-        if (ptr->spriteInfo->sprite == kbd->spriteInfo->sprite && 
-                ptr->spriteInfo->spriteOwner)
-        {
-            return ptr;
-        }
-        ptr = ptr->next;
-    }
 
-    return inputInfo.pointer;
-}
-
-/* Find the keyboard device that is paired with the given pointer. If none is
- * found, return the VCK.
+/* Return the device paired with the given device or NULL.
  */
 _X_EXPORT DeviceIntPtr
-GetPairedKeyboard(DeviceIntPtr ptr)
+GetPairedDevice(DeviceIntPtr dev)
 {
-    DeviceIntPtr dev = inputInfo.devices;
-
-    if (IsKeyboardDevice(ptr))
-        return ptr;
-
-    while(dev)
+    if (!dev->spriteInfo->paired)
     {
-        if (ptr != dev && 
-            IsKeyboardDevice(dev) &&
-            ptr->spriteInfo->sprite == dev->spriteInfo->sprite)
-            return dev;
-        dev = dev->next;
+        ErrorF("[dix] No device paired with %d (%s).\n", 
+                dev->id, dev->name);
+        return NULL;
     }
-    return (dev) ? dev : inputInfo.keyboard;
+    return dev->spriteInfo->paired;
 }
 
 /*
commit 3e07e73fefc100e491d1e465cb162373d1d82425
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 11:34:29 2007 +0930

    dix: remove pairing/attachment from InitAndStartDevices.
    
    If we enabled in the correct order, this has all been done already.

diff --git a/dix/devices.c b/dix/devices.c
index 7be0d69..f886120 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -215,7 +215,10 @@ EnableDevice(DeviceIntPtr dev)
         {
             /* Sprites appear on first root window, so we can hardcode it */
             if (dev->spriteInfo->spriteOwner)
+            {
                 InitializeSprite(dev, WindowTable[0]);
+                ((FocusSemaphoresPtr)(WindowTable[0])->devPrivates[FocusPrivatesIndex].ptr)->enterleave++;
+            }
             else if ((other = NextFreePointerDevice()) == NULL)
             {
                 ErrorF("[dix] cannot find pointer to pair with. "
@@ -596,23 +599,6 @@ InitAndStartDevices(WindowPtr root)
 	    (void)EnableDevice(dev);
     }
 
-    /* All of the devices are started up now. Pair VCK with VCP, then
-     * attach each device to the initial master.
-     */ 
-    PairDevices(NULL, inputInfo.pointer, inputInfo.keyboard);
-
-    for (dev = inputInfo.devices; dev; dev = dev->next)
-    {
-        if (!DevHasCursor(dev))
-            AttachDevice(NULL, dev, inputInfo.keyboard);
-        else
-        {
-            AttachDevice(NULL, dev, inputInfo.pointer);
-            /* enter/leave counter on root window */
-            ((FocusSemaphoresPtr)root->devPrivates[FocusPrivatesIndex].ptr)->enterleave++;
-        }
-    }
-
     return Success;
 }
 
commit 38baac71bdbb8c7e882e3e39133615cfed894a6b
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Sun Oct 14 04:21:42 2007 +0930

    dix: Set bidirectional pairing, don't allow pairing with already paired devs.

diff --git a/dix/devices.c b/dix/devices.c
index 2dd3f9e..7be0d69 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2238,7 +2238,10 @@ PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd)
         return BadDevice;
 
     /* Don't allow pairing for slave devices */
-    if (ptr->master || kbd->master)
+    if (!ptr->isMaster || !kbd->isMaster)
+        return BadDevice;
+
+    if (ptr->spriteInfo->paired)
         return BadDevice;
 
     if (!pairingClient)
@@ -2255,6 +2258,7 @@ PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd)
 
     kbd->spriteInfo->sprite = ptr->spriteInfo->sprite;
     kbd->spriteInfo->paired = ptr;
+    ptr->spriteInfo->paired = kbd;
     return Success;
 }
 
commit 70efd3d06a15093661933bda4ec21e306dece4a4
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 11:30:32 2007 +0930

    dix: fix up Activate/Enable/Disable device.
    
    Set isMaster for VCP/VCK.
    Init sprites for master pointer devices.
    Pair master kbds with master pointers (1:1 pairing!).
    Attach other devices to VCP/VCK.

diff --git a/dix/devices.c b/dix/devices.c
index c41fa0c..2dd3f9e 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -189,8 +189,9 @@ AddInputDevice(DeviceProc deviceProc, Bool autoStart)
  * list. Initialize the DIX sprite or pair the device. All clients are
  * notified about the device being enabled.
  *
- * A device will send events once enabled.
- *
+ * A master pointer device needs to be enabled before a master keyboard
+ * device.
+ * 
  * @param The device to be enabled.
  * @return TRUE on success or FALSE otherwise.
  */
@@ -200,6 +201,7 @@ EnableDevice(DeviceIntPtr dev)
     DeviceIntPtr *prev;
     int ret;
     DeviceIntRec dummyDev;
+    DeviceIntPtr other;
     devicePresenceNotify ev;
 
     for (prev = &inputInfo.off_devices;
@@ -207,15 +209,26 @@ EnableDevice(DeviceIntPtr dev)
 	 prev = &(*prev)->next)
 	;
 
-    /* Sprites pop up on the first root window, so we can supply it directly
-     * here. 
-     */
     if (!dev->spriteInfo->sprite)
     {
-        if (IsPointerDevice(dev) && dev->spriteInfo->spriteOwner)
-            InitializeSprite(dev, WindowTable[0]);
-        else
-            PairDevices(NULL, inputInfo.pointer, dev);
+        if (dev->isMaster)
+        {
+            /* Sprites appear on first root window, so we can hardcode it */
+            if (dev->spriteInfo->spriteOwner)
+                InitializeSprite(dev, WindowTable[0]);
+            else if ((other = NextFreePointerDevice()) == NULL)
+            {
+                ErrorF("[dix] cannot find pointer to pair with. "
+                       "This is a bug.\n");
+                return FALSE;
+            } else
+                PairDevices(NULL, other, dev);
+        } else
+        {
+            other = (IsPointerDevice(dev)) ? inputInfo.pointer :
+                inputInfo.keyboard;
+            AttachDevice(NULL, dev, other);
+        }
     }
 
     if ((*prev != dev) || !dev->inited ||
@@ -247,12 +260,15 @@ EnableDevice(DeviceIntPtr dev)
  * list. A device will not send events while disabled. All clients are
  * notified about the device being disabled.
  *
+ * Master keyboard devices have to be disabled before master pointer devices
+ * otherwise things turn bad.
+ *
  * @return TRUE on success or FALSE otherwise.
  */
 Bool
 DisableDevice(DeviceIntPtr dev)
 {
-    DeviceIntPtr *prev, paired;
+    DeviceIntPtr *prev, other;
     DeviceIntRec dummyDev;
     devicePresenceNotify ev;
 
@@ -262,20 +278,34 @@ DisableDevice(DeviceIntPtr dev)
 	;
     if (*prev != dev)
 	return FALSE;
+
+    if (dev->isMaster && dev->spriteInfo->sprite)
+    {
+        for (other = inputInfo.devices; other; other = other->next)
+        {
+            if (other->spriteInfo->paired == dev)
+            {
+                ErrorF("[dix] cannot disable device, still paired. " 
+                        "This is a bug. \n");
+                return FALSE;
+            }
+        }
+    }
+
     (void)(*dev->deviceProc)(dev, DEVICE_OFF);
     dev->enabled = FALSE;
     *prev = dev->next;
     dev->next = inputInfo.off_devices;
     inputInfo.off_devices = dev;
 
-    /* Some other device may have been paired with this device. 
-       Re-pair with VCP. We don't repair with a real device, as this
-       may cause somebody suddenly typing where they shouldn't. 
-     */
-    for (paired = inputInfo.devices; paired; paired = paired->next)
+    /* float attached devices */
+    if (dev->isMaster)
     {
-        if (paired->spriteInfo->paired == dev)
-            PairDevices(NULL, inputInfo.pointer, paired);
+        for (other = inputInfo.devices; other; other = other->next) 
+        {
+            if (other->master == dev)
+                AttachDevice(NULL, dev, NULL);
+        }
     }
 
     ev.type = DevicePresenceNotify;
@@ -313,7 +343,7 @@ ActivateDevice(DeviceIntPtr dev)
     dev->inited = (ret == Success);
 
     /* Initialize memory for sprites. */
-    if (IsPointerDevice(dev))
+    if (dev->isMaster && dev->spriteInfo->spriteOwner)
         pScreen->DeviceCursorInitialize(dev, pScreen);
     
     ev.type = DevicePresenceNotify;
@@ -485,6 +515,7 @@ InitCoreDevices(void)
             FatalError("Couldn't allocate keyboard devPrivates\n");
         dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
         dev->master = NULL;
+        dev->isMaster = TRUE;
         (void)ActivateDevice(dev);
 
         inputInfo.keyboard = dev;
@@ -512,6 +543,7 @@ InitCoreDevices(void)
             FatalError("Couldn't allocate pointer devPrivates\n");
         dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
         dev->master = NULL;
+        dev->isMaster = TRUE;
         (void)ActivateDevice(dev);
 
         inputInfo.pointer = dev;
@@ -550,10 +582,10 @@ InitAndStartDevices(WindowPtr root)
     }
 
     /* Now enable all devices */
-    if (inputInfo.keyboard->inited && inputInfo.keyboard->startup)
-        EnableDevice(inputInfo.keyboard);
     if (inputInfo.pointer->inited && inputInfo.pointer->startup)
         EnableDevice(inputInfo.pointer);
+    if (inputInfo.keyboard->inited && inputInfo.keyboard->startup)
+        EnableDevice(inputInfo.keyboard);
 
     /* enable real devices */
     for (dev = inputInfo.off_devices; dev; dev = next)
@@ -2367,3 +2399,15 @@ GuessFreePointerDevice()
 
     return (lastRealPtr) ? lastRealPtr : inputInfo.pointer;
 }
+
+DeviceIntPtr
+NextFreePointerDevice()
+{
+    DeviceIntPtr dev;
+    for (dev = inputInfo.devices; dev; dev = dev->next)
+        if (dev->isMaster && 
+                dev->spriteInfo->spriteOwner && 
+                !dev->spriteInfo->paired)
+            return dev;
+    return NULL;
+}
diff --git a/include/input.h b/include/input.h
index 1ef36b8..f41514a 100644
--- a/include/input.h
+++ b/include/input.h
@@ -476,6 +476,7 @@ extern Bool RegisterPairingClient(ClientPtr client);
 extern Bool UnregisterPairingClient(ClientPtr client);
 
 extern DeviceIntPtr GuessFreePointerDevice(void);
+extern DeviceIntPtr NextFreePointerDevice(void);
 
 /* Window/device based access control */
 extern Bool ACRegisterClient(ClientPtr client);
commit 204f2dc89ef662b57400b128c30c15e8cf32f323
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Sun Oct 14 04:13:06 2007 +0930

    include: add "isMaster" field to DeviceIntRec.
    
    Set to TRUE for master devices.
    
    Also fixing up comment for paired field in spriteInfo, will be set
    bidirectional from now on.

diff --git a/include/inputstr.h b/include/inputstr.h
index 146fbc8..d96e24a 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -357,8 +357,9 @@ typedef struct _SpriteInfoRec {
      * sprite, let sprite point to a paired spriteOwner's sprite. */
     SpritePtr           sprite;      /* sprite information */
     Bool                spriteOwner; /* True if device owns the sprite */
-    DeviceIntPtr        paired;      /* the real owner of the sprite or
-                                        NULL if spriteOwner is TRUE*/
+    DeviceIntPtr        paired;      /* The paired device. Keyboard if
+                                        spriteOwner is TRUE, otherwise the
+                                        pointer that owns the sprite. */ 
 } SpriteInfoRec, *SpriteInfoPtr;
 
 typedef struct _DeviceIntRec {
@@ -373,6 +374,7 @@ typedef struct _DeviceIntRec {
     Bool        enabled;                /* TRUE if ON returns Success */
     Bool        coreEvents;             /* TRUE if device also sends core */
     GrabInfoRec deviceGrab;             /* grab on the device */
+    Bool        isMaster;               /* TRUE if device is master */
     Atom		type;
     char		*name;
     CARD8		id;
commit bd7d5255ce4865b684f7d8bcf80ba9872a1af22d
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Tue Oct 16 11:18:31 2007 +0930

    dix: add AttachDevice, needed to attach a slave device to a master device.
    
    For now, we don't allow attaching slaves to other slaves, and we don't allow
    pairing slaves with other slaves.
    Pairing is for master keyboard->master pointer only.
    Attaching is for slave device->master device only.

diff --git a/dix/devices.c b/dix/devices.c
index 9e9fca3..c41fa0c 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -540,11 +540,11 @@ InitAndStartDevices(WindowPtr root)
 	ActivateDevice(dev);
     }
 
-    if (!inputInfo.keyboard) {
+    if (!inputInfo.keyboard) { /* In theory, this cannot happen */
 	ErrorF("[dix] No core keyboard\n");
 	return BadImplementation;
     }
-    if (!inputInfo.pointer) {
+    if (!inputInfo.pointer) { /* In theory, this cannot happen */
 	ErrorF("[dix] No core pointer\n");
 	return BadImplementation;
     }
@@ -555,10 +555,6 @@ InitAndStartDevices(WindowPtr root)
     if (inputInfo.pointer->inited && inputInfo.pointer->startup)
         EnableDevice(inputInfo.pointer);
 
-    /* Remove VCP and VCK from device list */
-    inputInfo.devices = NULL;
-    inputInfo.keyboard->next = inputInfo.pointer->next = NULL;
-
     /* enable real devices */
     for (dev = inputInfo.off_devices; dev; dev = next)
     {
@@ -569,17 +565,20 @@ InitAndStartDevices(WindowPtr root)
     }
 
     /* All of the devices are started up now. Pair VCK with VCP, then
-     * pair each real keyboard with a real pointer. 
+     * attach each device to the initial master.
      */ 
     PairDevices(NULL, inputInfo.pointer, inputInfo.keyboard);
 
     for (dev = inputInfo.devices; dev; dev = dev->next)
     {
         if (!DevHasCursor(dev))
-            PairDevices(NULL, GuessFreePointerDevice(), dev);
+            AttachDevice(NULL, dev, inputInfo.keyboard);
         else
+        {
+            AttachDevice(NULL, dev, inputInfo.pointer);
             /* enter/leave counter on root window */
             ((FocusSemaphoresPtr)root->devPrivates[FocusPrivatesIndex].ptr)->enterleave++;
+        }
     }
 
     return Success;
@@ -2195,7 +2194,7 @@ ProcQueryKeymap(ClientPtr client)
 }
 
 /* Pair the keyboard to the pointer device. Keyboard events will follow the
- * pointer sprite. 
+ * pointer sprite. Only applicable for master devices. 
  * If the client is set, the request to pair comes from some client. In this
  * case, we need to check for access. If the client is NULL, it's from an
  * internal automatic pairing, we must always permit this.
@@ -2206,6 +2205,10 @@ PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd)
     if (!ptr)
         return BadDevice;
 
+    /* Don't allow pairing for slave devices */
+    if (ptr->master || kbd->master)
+        return BadDevice;
+
     if (!pairingClient)
         RegisterPairingClient(client);
     else if (client && pairingClient != client)
@@ -2223,6 +2226,32 @@ PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd)
     return Success;
 }
 
+/**
+ * Attach device 'dev' to device 'master'.
+ * Client is set to the client that issued the request, or NULL if it comes
+ * from some internal automatic pairing.
+ *
+ * We don't allow multi-layer hierarchies right now. You can't attach a slave
+ * to another slave. 
+ */
+int
+AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
+{
+    if (!dev || !master)
+        return BadDevice;
+
+    if (master->master) /* can't attach to slave device */
+        return BadDevice;
+
+    if (!pairingClient)
+        RegisterPairingClient(client);
+    else if (client && pairingClient != client)
+        return BadAccess;
+
+    dev->master = master;
+
+    return Success;
+}
 /* Return the pointer that is paired with the given keyboard. If no pointer is
  * paired, return the virtual core pointer 
  */ 
diff --git a/include/input.h b/include/input.h
index d86a969..1ef36b8 100644
--- a/include/input.h
+++ b/include/input.h
@@ -465,6 +465,9 @@ extern DeviceIntPtr LookupDeviceIntRec(
 extern int PairDevices(ClientPtr client, 
                        DeviceIntPtr pointer, 
                        DeviceIntPtr keyboard);
+extern int AttachDevice(ClientPtr client,
+                        DeviceIntPtr slave,
+                        DeviceIntPtr master);
 
 extern DeviceIntPtr GetPairedPointer(DeviceIntPtr kbd);
 extern DeviceIntPtr GetPairedKeyboard(DeviceIntPtr ptr);
commit be1565f6b8fb09eba9941d6f7c485bf5fb25fe7a
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Sun Oct 14 01:53:54 2007 +0930

    dix: Set core devices to ProcessOtherEvents, set sendCore and XKB.
    
    Even the virtual core devices should send through ProcessOtherEvents.

diff --git a/dix/devices.c b/dix/devices.c
index 37a98a0..9e9fca3 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -469,21 +469,22 @@ InitCoreDevices(void)
             FatalError("Failed to allocate core keyboard");
         dev->name = strdup("Virtual core keyboard");
 #ifdef XKB
-        dev->public.processInputProc = CoreProcessKeyboardEvent;
-        dev->public.realInputProc = CoreProcessKeyboardEvent;
-        /*if (!noXkbExtension)*/
-        /*XkbSetExtension(dev, ProcessKeyboardEvent);*/
+        dev->public.processInputProc = ProcessOtherEvent;
+        dev->public.realInputProc = ProcessOtherEvent;
+        if (!noXkbExtension)
+            XkbSetExtension(dev, ProcessKeyboardEvent);
 #else
         dev->public.processInputProc = ProcessKeyboardEvent;
         dev->public.realInputProc = ProcessKeyboardEvent;
 #endif
         dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
         dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
-        dev->coreEvents = FALSE;
+        dev->coreEvents = TRUE;
         dev->spriteInfo->spriteOwner = FALSE;
         if (!AllocateDevicePrivate(dev, CoreDevicePrivatesIndex))
             FatalError("Couldn't allocate keyboard devPrivates\n");
         dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
+        dev->master = NULL;
         (void)ActivateDevice(dev);
 
         inputInfo.keyboard = dev;
@@ -495,8 +496,8 @@ InitCoreDevices(void)
             FatalError("Failed to allocate core pointer");
         dev->name = strdup("Virtual core pointer");
 #ifdef XKB
-        dev->public.processInputProc = CoreProcessPointerEvent;
-        dev->public.realInputProc = CoreProcessPointerEvent;
+        dev->public.processInputProc = ProcessOtherEvent;
+        dev->public.realInputProc = ProcessOtherEvent;
         if (!noXkbExtension)
            XkbSetExtension(dev, ProcessPointerEvent);
 #else
@@ -505,11 +506,12 @@ InitCoreDevices(void)
 #endif
         dev->deviceGrab.ActivateGrab = ActivatePointerGrab;
         dev->deviceGrab.DeactivateGrab = DeactivatePointerGrab;
-        dev->coreEvents = FALSE;
+        dev->coreEvents = TRUE;
         dev->spriteInfo->spriteOwner = TRUE;
         if (!AllocateDevicePrivate(dev, CoreDevicePrivatesIndex))
             FatalError("Couldn't allocate pointer devPrivates\n");
         dev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
+        dev->master = NULL;
         (void)ActivateDevice(dev);
 
         inputInfo.pointer = dev;
commit ce9bf9a19185a36ac2f7ae75acd320ab8d03d247
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Sun Oct 14 01:50:40 2007 +0930

    include: add "master" field to DeviceIntRec.
    
    "master" points to the device this device is attached to. Event sent by the
    device will also be routed through the master.
    master and spriteOwner are mutually exclusive.

diff --git a/include/inputstr.h b/include/inputstr.h
index cbbc4e2..146fbc8 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -398,6 +398,7 @@ typedef struct _DeviceIntRec {
     int			nPrivates;
     DeviceUnwrapProc    unwrapProc;
     SpriteInfoPtr       spriteInfo;
+    DeviceIntPtr        master;       /* master device */
 } DeviceIntRec;
 
 typedef struct {


More information about the xorg-commit mailing list