xserver: Branch 'mpx' - 11 commits

Peter Hutterer whot at kemper.freedesktop.org
Thu Apr 10 16:56:12 PDT 2008


 Xi/chdevhier.c                 |    6 -
 Xi/exevents.c                  |   56 ++++++++++++++-
 dix/devices.c                  |  121 +++------------------------------
 dix/events.c                   |  146 ++++++++++++++++++++++++-----------------
 dix/window.c                   |    2 
 hw/xfree86/common/xf86Xinput.c |    5 +
 include/dix.h                  |    1 
 include/input.h                |   35 +++++++++
 include/windowstr.h            |   12 ++-
 9 files changed, 204 insertions(+), 180 deletions(-)

New commits:
commit 90f491cf8eb869f27c4278b26c1bb84432b12d63
Merge: cbe01b3... b4380d8...
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Fri Apr 11 08:29:52 2008 +0930

    Merge whot at wombat:~/potoroo/xserver into mpx

commit b4380d8030927c940ddaea83c4cf24e0b9eb7b96
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 19:25:43 2008 +0930

    dix: don't free MDs classes on init.
    
    The device classes aren't deleted anymore on a class change, so there's no
    need to store the MD's original classes. We should however restore the MD to
    sane defaults when disconnecting the last device, consider this as TODO item.

diff --git a/dix/devices.c b/dix/devices.c
index 2d7885e..a78a125 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -88,8 +88,6 @@ SOFTWARE.
 
 /* The client that is allowed to change pointer-keyboard pairings. */
 static ClientPtr pairingClient = NULL;
-
-DevPrivateKey MasterDevClassesPrivateKey = &MasterDevClassesPrivateKey;
 DevPrivateKey CoreDevicePrivateKey = &CoreDevicePrivateKey;
 
 /**
@@ -409,7 +407,6 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what)
     XkbComponentNamesRec names;
 #endif
     ClassesPtr classes;
-    DeviceIntRec dummy;
 
     switch (what) {
     case DEVICE_INIT:
@@ -419,8 +416,6 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what)
             return BadAlloc;
         }
 
-        dixSetPrivate(&pDev->devPrivates, MasterDevClassesPrivateKey, NULL);
-
         keySyms.minKeyCode = 8;
         keySyms.maxKeyCode = 255;
         keySyms.mapWidth = 4;
@@ -459,53 +454,9 @@ 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;
-
-        /* Each time we switch classes we free the MD's classes and copy the
-         * SD's classes into the MD. We mustn't lose the first set of classes
-         * though as we need it to restore them when the last SD disconnects.
-         *
-         * So we create a fake device, seem to copy from the fake to the real
-         * one, thus ending up with a copy of the original ones in our MD.
-         *
-         * If we don't do that, we're in SIGABRT territory (double-frees, etc)
-         */
-        memcpy(&dummy, pDev, sizeof(DeviceIntRec));
-        /* Need to set them to NULL. Otherwise, Xkb does some weird stuff and
-         * the dev->key->xkbInfo->kbdProc starts calling itself. This can
-         * probably be fixed in a better way, but I don't know how. (whot) */
-        pDev->key        = NULL;
-        pDev->valuator   = NULL;
-        pDev->button     = NULL;
-        pDev->focus      = NULL;
-        pDev->proximity  = NULL;
-        pDev->absolute   = NULL;
-        pDev->kbdfeed    = NULL;
-        pDev->ptrfeed    = NULL;
-        pDev->intfeed    = NULL;
-        pDev->stringfeed = NULL;
-        pDev->bell       = NULL;
-        pDev->leds       = NULL;
-        DeepCopyDeviceClasses(&dummy, pDev);
-
-        dixSetPrivate(&pDev->devPrivates, MasterDevClassesPrivateKey,
-                      classes);
         break;
 
     case DEVICE_CLOSE:
-	dixSetPrivate(&pDev->devPrivates, CoreDevicePrivateKey, NULL);
         break;
 
     default:
@@ -526,16 +477,12 @@ CorePointerProc(DeviceIntPtr pDev, int what)
     BYTE map[33];
     int i = 0;
     ClassesPtr classes;
-    DeviceIntRec dummy;
-
 
     switch (what) {
     case DEVICE_INIT:
         if (!(classes = xcalloc(1, sizeof(ClassesRec))))
             return BadAlloc;
 
-        dixSetPrivate(&pDev->devPrivates, MasterDevClassesPrivateKey, NULL);
-
         for (i = 1; i <= 32; i++)
             map[i] = i;
         InitPointerDeviceStruct((DevicePtr)pDev, map, 32,
@@ -545,43 +492,9 @@ CorePointerProc(DeviceIntPtr pDev, int what)
         pDev->lastx = pDev->valuator->axisVal[0];
         pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
         pDev->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;
-
-        /* See comment in CoreKeyboardProc. */
-        memcpy(&dummy, pDev, sizeof(DeviceIntRec));
-        /* Need to set them to NULL for the VCK (see CoreKeyboardProc). Not
-         * sure if also necessary for the VCP, but it doesn't seem to hurt */
-        pDev->key        = NULL;
-        pDev->valuator   = NULL;
-        pDev->button     = NULL;
-        pDev->focus      = NULL;
-        pDev->proximity  = NULL;
-        pDev->absolute   = NULL;
-        pDev->kbdfeed    = NULL;
-        pDev->ptrfeed    = NULL;
-        pDev->intfeed    = NULL;
-        pDev->stringfeed = NULL;
-        pDev->bell       = NULL;
-        pDev->leds       = NULL;
-        DeepCopyDeviceClasses(&dummy, pDev);
-
-        dixSetPrivate(&pDev->devPrivates, MasterDevClassesPrivateKey, classes);
         break;
 
     case DEVICE_CLOSE:
-	dixSetPrivate(&pDev->devPrivates, CoreDevicePrivateKey, NULL);
         break;
 
     default:
@@ -857,13 +770,6 @@ CloseDevice(DeviceIntPtr dev)
 
     xfree(dev->name);
 
-    if (dev->isMaster)
-    {
-        classes = (ClassesPtr)dixLookupPrivate(&dev->devPrivates,
-                MasterDevClassesPrivateKey);
-        FreeAllDeviceClasses(classes);
-    }
-
     classes = (ClassesPtr)&dev->key;
     FreeAllDeviceClasses(classes);
 
@@ -2543,16 +2449,9 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
 
         if (!it)  /* no dev is paired with old master */
         {
-            ClassesPtr classes;
+            /* XXX: reset to defaults */
             EventList event = { NULL, 0};
             char* classbuf;
-            DeviceIntRec dummy;
-
-            FreeAllDeviceClasses((ClassesPtr)&oldmaster->key);
-            classes = (ClassesPtr)dixLookupPrivate(&oldmaster->devPrivates,
-                                        MasterDevClassesPrivateKey);
-            memcpy(&dummy.key, classes, sizeof(ClassesRec));
-            DeepCopyDeviceClasses(&dummy, oldmaster);
 
             /* Send event to clients */
             CreateClassesChangedEvent(&event, oldmaster, oldmaster);
commit 04dff74ffdf727015e3721aae4ea13acc498cd1c
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 19:22:59 2008 +0930

    dix: Rework Enter/Leave semaphore system.
    
    Instead of a simple counter, use bits to keep track of which device is where
    etc. When device enters a window (or sets focus), the bit matching the device
    is set, when it leaves again, it is unset. If there are 0 bits set, then
    Leave/Enter/Focus events may be sent to the client.
    
    Same theory as before, but this should get around the insanity with
    Grab/Ungrab special cases. Those cases are basically untested though.

diff --git a/dix/devices.c b/dix/devices.c
index df194de..2d7885e 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -224,8 +224,7 @@ EnableDevice(DeviceIntPtr dev)
             if (dev->spriteInfo->spriteOwner)
             {
                 InitializeSprite(dev, WindowTable[0]);
-                ((FocusSemaphoresPtr)dixLookupPrivate(&(WindowTable[0])->devPrivates,
-                    FocusPrivatesKey))->enterleave++;
+                ENTER_LEAVE_SEMAPHORE_SET(WindowTable[0], dev);
             }
             else if ((other = NextFreePointerDevice()) == NULL)
             {
diff --git a/dix/events.c b/dix/events.c
index 1445914..1b62db0 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -4393,7 +4393,7 @@ EnterLeaveEvent(
     GrabPtr	        grab = mouse->deviceGrab.grab;
     GrabPtr	        devgrab = mouse->deviceGrab.grab;
     Mask		mask;
-    int*                inWindow; /* no of sprites inside pWin */
+    int                 inWindow; /* zero if no sprites are in window */
     Bool                sendevent = FALSE;
 
     deviceEnterNotify   *devEnterLeave;
@@ -4446,7 +4446,6 @@ EnterLeaveEvent(
              IsParent(focus, pWin)))
         event.u.enterLeave.flags |= ELFlagFocus;
 
-    inWindow = &((FocusSemaphoresPtr)dixLookupPrivate(&pWin->devPrivates, FocusPrivatesKey))->enterleave;
 
     /*
      * Sending multiple core enter/leave events to the same window confuse the
@@ -4472,16 +4471,15 @@ EnterLeaveEvent(
      * NotifyNonlinearVirtual to C and nothing to B.
      */
 
-    if (event.u.u.detail != NotifyVirtual &&
-            event.u.u.detail != NotifyNonlinearVirtual)
-    {
-        if (((*inWindow) == (LeaveNotify - type)))
-            sendevent = TRUE;
-    } else
-    {
-        if (!(*inWindow))
-            sendevent = TRUE;
-    }
+    /* Clear bit for device, but don't worry about SDs. */
+    if (mouse->isMaster && type == LeaveNotify &&
+            (mode != NotifyVirtual && mode != NotifyNonlinearVirtual))
+        ENTER_LEAVE_SEMAPHORE_UNSET(pWin, mouse);
+
+    inWindow = EnterLeaveSemaphoresIsset(pWin);
+
+    if (!inWindow)
+        sendevent = TRUE;
 
     if ((mask & filters[mouse->id][type]) && sendevent)
     {
@@ -4493,6 +4491,10 @@ EnterLeaveEvent(
                                   filters[mouse->id][type], NullGrab, 0);
     }
 
+    if (mouse->isMaster && type == EnterNotify &&
+            (mode != NotifyVirtual && mode != NotifyNonlinearVirtual))
+        ENTER_LEAVE_SEMAPHORE_SET(pWin, mouse);
+
     /* we don't have enough bytes, so we squash flags and mode into
        one byte, and use the last byte for the deviceid. */
     devEnterLeave = (deviceEnterNotify*)&event;
@@ -4582,25 +4584,6 @@ LeaveNotifies(DeviceIntPtr pDev,
     }
 }
 
-/* welcome to insanity */
-#define FOCUS_SEMAPHORE_MODIFY(win, field, mode, val) \
-{ \
-    FocusSemaphoresPtr sem;\
-    sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey); \
-    if (mode != NotifyGrab && mode != NotifyUngrab) { \
-        sem->field += val; \
-    } else if (mode == NotifyUngrab) { \
-        if (sem->field == 0 && val > 0) \
-            sem->field += val; \
-        else if (sem->field == 1 && val < 0) \
-            sem->field += val; \
-    } \
-}
-#define ENTER_LEAVE_SEMAPHORE_UP(win, mode)  \
-        FOCUS_SEMAPHORE_MODIFY(win, enterleave, mode, 1);
-
-#define ENTER_LEAVE_SEMAPHORE_DOWN(win, mode) \
-        FOCUS_SEMAPHORE_MODIFY(win, enterleave, mode,  -1);
 
 
 /**
@@ -4620,33 +4603,27 @@ DoEnterLeaveEvents(DeviceIntPtr pDev,
 	return;
     if (IsParent(fromWin, toWin))
     {
-        ENTER_LEAVE_SEMAPHORE_DOWN(fromWin, mode);
         EnterLeaveEvent(pDev, LeaveNotify, mode, NotifyInferior, fromWin,
                         None);
         EnterNotifies(pDev, fromWin, toWin, mode,
                       NotifyVirtual);
-        ENTER_LEAVE_SEMAPHORE_UP(toWin, mode);
         EnterLeaveEvent(pDev, EnterNotify, mode, NotifyAncestor, toWin, None);
     }
     else if (IsParent(toWin, fromWin))
     {
-        ENTER_LEAVE_SEMAPHORE_DOWN(fromWin, mode);
 	EnterLeaveEvent(pDev, LeaveNotify, mode, NotifyAncestor, fromWin,
                         None);
 	LeaveNotifies(pDev, fromWin, toWin, mode, NotifyVirtual);
-        ENTER_LEAVE_SEMAPHORE_UP(toWin, mode);
 	EnterLeaveEvent(pDev, EnterNotify, mode, NotifyInferior, toWin, None);
     }
     else
     { /* neither fromWin nor toWin is descendent of the other */
 	WindowPtr common = CommonAncestor(toWin, fromWin);
 	/* common == NullWindow ==> different screens */
-        ENTER_LEAVE_SEMAPHORE_DOWN(fromWin, mode);
         EnterLeaveEvent(pDev, LeaveNotify, mode, NotifyNonlinear, fromWin,
                         None);
         LeaveNotifies(pDev, fromWin, common, mode, NotifyNonlinearVirtual);
 	EnterNotifies(pDev, common, toWin, mode, NotifyNonlinearVirtual);
-        ENTER_LEAVE_SEMAPHORE_UP(toWin, mode);
         EnterLeaveEvent(pDev, EnterNotify, mode, NotifyNonlinear, toWin,
                         None);
     }
@@ -4656,7 +4633,7 @@ static void
 FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
 {
     xEvent event;
-    int* numFoci; /* no of foci the window has already */
+    int numFoci; /* zero if no device has focus on window */
     Bool sendevent = FALSE;
 
     if (dev != inputInfo.keyboard)
@@ -4690,25 +4667,18 @@ FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
      * NotifyNonlinearVirtual to C and nothing to B.
      */
 
-    numFoci =
-        &((FocusSemaphoresPtr)dixLookupPrivate(&pWin->devPrivates,
-                    FocusPrivatesKey))->focusinout;
-    if (mode == NotifyGrab || mode == NotifyUngrab)
+    if (dev->isMaster && type == FocusOut &&
+            (detail != NotifyVirtual &&
+             detail != NotifyNonlinearVirtual &&
+             detail != NotifyPointer &&
+             detail != NotifyPointerRoot &&
+             detail != NotifyDetailNone))
+       FOCUS_SEMAPHORE_UNSET(pWin, dev);
+
+    numFoci = FocusSemaphoresIsset(pWin);
+
+    if (!numFoci)
         sendevent = TRUE;
-    else if (detail != NotifyVirtual &&
-            detail != NotifyNonlinearVirtual &&
-            detail != NotifyPointer &&
-            detail != NotifyPointerRoot &&
-            detail != NotifyDetailNone)
-    {
-        (type == FocusIn) ? (*numFoci)++ : (*numFoci)--;
-        if (((*numFoci) == (FocusOut - type)))
-            sendevent = TRUE;
-    } else
-    {
-        if (!(*numFoci))
-            sendevent = TRUE;
-    }
 
     if (sendevent)
     {
@@ -4733,6 +4703,14 @@ FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
                                         KeymapStateMask, NullGrab, 0);
         }
     }
+
+    if (dev->isMaster && type == FocusIn &&
+            (detail != NotifyVirtual &&
+             detail != NotifyNonlinearVirtual &&
+             detail != NotifyPointer &&
+             detail != NotifyPointerRoot &&
+             detail != NotifyDetailNone))
+        FOCUS_SEMAPHORE_SET(pWin, dev);
 }
 
  /*
@@ -6616,3 +6594,37 @@ ExtGrabDevice(ClientPtr client,
     return GrabSuccess;
 }
 
+/*
+ * @return Zero if no device is currently in window, non-zero otherwise.
+ */
+int
+EnterLeaveSemaphoresIsset(WindowPtr win)
+{
+    FocusSemaphoresPtr sem;
+    int set = 0;
+    int i;
+
+    sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey);
+    for (i = 0; i < (MAX_DEVICES + 7)/8; i++)
+        set += sem->enterleave[i];
+
+    return set;
+}
+
+/*
+ * @return Zero if no devices has focus on the window, non-zero otherwise.
+ */
+int
+FocusSemaphoresIsset(WindowPtr win)
+{
+    FocusSemaphoresPtr sem;
+    int set = 0;
+    int i;
+
+    sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey);
+    for (i = 0; i < (MAX_DEVICES + 7)/8; i++)
+        set += sem->focusinout[i];
+
+    return set;
+}
+
diff --git a/dix/window.c b/dix/window.c
index ee4c756..d3160c9 100644
--- a/dix/window.c
+++ b/dix/window.c
@@ -366,6 +366,7 @@ CreateRootWindow(ScreenPtr pScreen)
     WindowPtr	pWin;
     BoxRec	box;
     PixmapFormatRec *format;
+    FocusSemaphoresPtr sem;
 
     pWin = (WindowPtr)xalloc(sizeof(WindowRec));
     if (!pWin)
@@ -484,6 +485,7 @@ CreateRootWindow(ScreenPtr pScreen)
 		
     if (disableSaveUnders)
 	pScreen->saveUnderSupport = NotUseful;
+
     return TRUE;
 }
 
diff --git a/include/input.h b/include/input.h
index 9ba12db..0c993ee 100644
--- a/include/input.h
+++ b/include/input.h
@@ -80,6 +80,39 @@ SOFTWARE.
 #define RevertToFollowKeyboard	3
 #endif
 
+/* Used for enter/leave and focus in/out semaphores */
+#define SEMAPHORE_FIELD_SET(win, dev, field) \
+{ \
+    FocusSemaphoresPtr sem; \
+    sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey); \
+    sem->field[dev->id/8] |= (1 << (dev->id % 8)); \
+}
+
+#define SEMAPHORE_FIELD_UNSET(win, dev, field) \
+{ \
+    FocusSemaphoresPtr sem; \
+    sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey); \
+    sem->field[dev->id/8] &= ~(1 << (dev->id % 8)); \
+}
+
+#define ENTER_LEAVE_SEMAPHORE_SET(win, dev) \
+        SEMAPHORE_FIELD_SET(win, dev, enterleave);
+
+#define ENTER_LEAVE_SEMAPHORE_UNSET(win, dev) \
+        SEMAPHORE_FIELD_UNSET(win, dev, enterleave);
+
+#define ENTER_LEAVE_SEMAPHORE_ISSET(win, dev) \
+    ((FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey))->enterleave[dev->id/8] & (1 << (dev->id % 8))
+
+#define FOCUS_SEMAPHORE_SET(win, dev) \
+        SEMAPHORE_FIELD_SET(win, dev, focusinout);
+
+#define FOCUS_SEMAPHORE_UNSET(win, dev) \
+        SEMAPHORE_FIELD_UNSET(win, dev, focusinout);
+
+#define FOCUS_SEMAPHORE_ISSET(win, dev) \
+    ((FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey))->focusinout[dev->id/8] & (1 << (dev->id % 8))
+
 typedef unsigned long Leds;
 typedef struct _OtherClients *OtherClientsPtr;
 typedef struct _InputClients *InputClientsPtr;
@@ -488,6 +521,8 @@ extern void DeepCopyDeviceClasses(DeviceIntPtr from,
 extern void FreeDeviceClass(int type, pointer* class);
 extern void FreeFeedbackClass(int type, pointer* class);
 extern void FreeAllDeviceClasses(ClassesPtr classes);
+extern int EnterLeaveSemaphoresIsset(WindowPtr win);
+extern int FocusSemaphoresIsset(WindowPtr win);
 
 /* Window/device based access control */
 extern Bool ACRegisterClient(ClientPtr client);
diff --git a/include/windowstr.h b/include/windowstr.h
index 406087e..a36dc29 100644
--- a/include/windowstr.h
+++ b/include/windowstr.h
@@ -59,6 +59,7 @@ SOFTWARE.
 #include "miscstruct.h"
 #include <X11/Xprotostr.h>
 #include "opaque.h"
+#include "inputstr.h"
 
 #define GuaranteeNothing	0
 #define GuaranteeVisBack	1
@@ -257,11 +258,14 @@ extern ScreenSaverStuffRec savedScreenInfo[MAXSCREENS];
 extern DevPrivateKey FocusPrivatesKey;
 
 /* Used to maintain semantics of core protocol for Enter/LeaveNotifies and
- * FocusIn/Out events for multiple pointers/keyboards. 
- */ 
+ * FocusIn/Out events for multiple pointers/keyboards.
+ *
+ * Each device ID corresponds to one bit. If set, the device is in the
+ * window/has focus.
+ */
 typedef struct _FocusSemaphores {
-    int                 enterleave;
-    int                 focusinout;
+    char                enterleave[(MAX_DEVICES + 7)/8];
+    char                focusinout[(MAX_DEVICES + 7)/8];
 } FocusSemaphoresRec, *FocusSemaphoresPtr;
 
 /*
commit a88386ee277d136caaaeec305f8753f23f9b6274
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 14:36:57 2008 +0930

    Xi: only DeliverFocusedEvents if the event is not a pointer event.
    
    A pointer device may have a focus class, but even if so, pointer events must
    be delivered to the sprite window, not the focus window.

diff --git a/Xi/exevents.c b/Xi/exevents.c
index ba7f3b2..a93fef4 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -104,6 +104,32 @@ RegisterOtherDevice(DeviceIntPtr device)
     device->public.realInputProc = ProcessOtherEvent;
 }
 
+_X_EXPORT Bool
+IsPointerEvent(xEvent* xE)
+{
+    switch(xE->u.u.type)
+    {
+        case ButtonPress:
+        case ButtonRelease:
+        case MotionNotify:
+        case EnterNotify:
+        case LeaveNotify:
+            return TRUE;
+        default:
+            if (xE->u.u.type == DeviceButtonPress ||
+                xE->u.u.type == DeviceButtonRelease ||
+                xE->u.u.type == DeviceMotionNotify ||
+                xE->u.u.type == DeviceEnterNotify ||
+                xE->u.u.type == DeviceLeaveNotify ||
+                xE->u.u.type == ProximityIn ||
+                xE->u.u.type == ProximityOut)
+            {
+                return TRUE;
+            }
+    }
+    return FALSE;
+}
+
 /**
  * Copy the device->key into master->key and send a mapping notify to the
  * clients if appropriate.
@@ -830,7 +856,7 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
 
     if (grab)
         DeliverGrabbedEvent(xE, device, deactivateDeviceGrab, count);
-    else if (device->focus)
+    else if (device->focus && !IsPointerEvent(xE))
 	DeliverFocusedEvent(device, xE, GetSpriteWindow(device), count);
     else
 	DeliverDeviceEvents(GetSpriteWindow(device), xE, NullGrab, NullWindow,
diff --git a/dix/events.c b/dix/events.c
index 305502a..1445914 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1397,7 +1397,7 @@ ComputeFreezes(void)
 		replayDev->spriteInfo->sprite->spriteTrace[i])
 	    {
 		if (!CheckDeviceGrabs(replayDev, xE, i+1, count)) {
-		    if (replayDev->focus)
+		    if (replayDev->focus && !IsPointerEvent(xE))
 			DeliverFocusedEvent(replayDev, xE, w, count);
 		    else
 			DeliverDeviceEvents(w, xE, NullGrab, NullWindow,
@@ -1407,7 +1407,7 @@ ComputeFreezes(void)
 	    }
 	}
 	/* must not still be in the same stack */
-	if (replayDev->focus)
+	if (replayDev->focus && !IsPointerEvent(xE))
 	    DeliverFocusedEvent(replayDev, xE, w, count);
 	else
 	    DeliverDeviceEvents(w, xE, NullGrab, NullWindow, replayDev, count);
diff --git a/include/dix.h b/include/dix.h
index e00df29..57ffee9 100644
--- a/include/dix.h
+++ b/include/dix.h
@@ -615,6 +615,7 @@ extern int XItoCoreType(int xi_type);
 extern Bool DevHasCursor(DeviceIntPtr pDev);
 extern Bool IsPointerDevice( DeviceIntPtr dev);
 extern Bool IsKeyboardDevice(DeviceIntPtr dev);
+extern Bool IsPointerEvent(xEvent* xE);
 
 /*
  * These are deprecated compatibility functions and will be removed soon!
commit 48249425275cc90242497aee9968e5f1ffc86698
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 14:36:10 2008 +0930

    Xi: dont copy FocusClassRec if the master already has one.
    
    Blindly copying will override the focus setting of the master. If there's XI
    applications running, they may set the SD focus, while leaving the
    MD's focus as it was. In this case, after a class swap we still want to get
    the MD's events to the same window as before.

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 38f6cb5..ba7f3b2 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -459,11 +459,29 @@ DeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to)
     }
 
 
-    ALLOC_COPY_CLASS_IF(focus, FocusClassRec);
-    if (to->focus && !from->focus)
+    /* We can't just copy over the focus class. When an app sets the focus,
+     * it'll do so on the master device. Copying the SDs focus means losing
+     * the focus.
+     * So we only copy the focus class if the device didn't have one,
+     * otherwise we leave it as it is.
+     */
+    if (from->focus)
+    {
+        if (!to->focus)
+        {
+            to->focus = xcalloc(1, sizeof(FocusClassRec));
+            if (!to->focus)
+                FatalError("[Xi] no memory for class shift.\n");
+            memcpy(to->focus->trace, from->focus->trace,
+                    from->focus->traceSize * sizeof(WindowPtr));
+        }
+    } else if (to->focus)
     {
-        FreeDeviceClass(FocusClass, (pointer)&to->focus);
+        /* properly freeing the class would also free the sprite trace, which
+         * is still in use by the SD. just xfree the struct. */
+        xfree(to->focus);
     }
+
     ALLOC_COPY_CLASS_IF(proximity, ProximityClassRec);
     if (to->proximity && !from->proximity)
     {
commit bce6091c6b04ff2db704ae4f161179d21dcbec59
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 09:59:45 2008 +0930

    dix: Extend IsKeyboardDevice() to not include pointer devices.
    
    If a pointer devices has key classes as well, don't register it as a keyboard
    device. Let's see how much that change will break.

diff --git a/dix/events.c b/dix/events.c
index a2a0c1a..305502a 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -331,11 +331,14 @@ IsPointerDevice(DeviceIntPtr dev)
 /*
  * Return true if a device is a keyboard, check is the same as used by XI to
  * fill the 'use' field.
+ *
+ * Some pointer devices have keys as well (e.g. multimedia keys). Try to not
+ * count them as keyboard devices.
  */
 _X_EXPORT Bool
 IsKeyboardDevice(DeviceIntPtr dev)
 {
-    return (dev->key && dev->kbdfeed);
+    return (dev->key && dev->kbdfeed) && !IsPointerDevice(dev);;
 }
 
 #ifdef XEVIE
commit cc7dab2d04da4ca164eeec1a3296df1706585466
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 09:58:50 2008 +0930

    dix: Dont deliver grabbed pointer events to a focus window.
    
    If an pointer event is being processed during a device grab, don't deliver it
    to the focus window, even if the device has a focus class. Reason being that
    some pointers may have a focus class, thus killing drag-and-drop.

diff --git a/dix/events.c b/dix/events.c
index 6ecd90c..a2a0c1a 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -3686,7 +3686,18 @@ DeliverGrabbedEvent(xEvent *xE, DeviceIntPtr thisDev,
     {
 	WindowPtr focus;
 
-	if (thisDev->focus)
+        /* Hack: Some pointer device have a focus class. So we need to check
+         * for the type of event, to see if we really want to deliver it to
+         * the focus window. For pointer events, the answer is no.
+         */
+        if (xE->u.u.type == DeviceButtonPress ||
+                xE->u.u.type == DeviceButtonRelease ||
+                xE->u.u.type == DeviceMotionNotify ||
+                xE->u.u.type == ProximityIn ||
+                xE->u.u.type == ProximityOut)
+        {
+            focus = PointerRootWin;
+        } else if (thisDev->focus)
 	{
 	    focus = thisDev->focus->win;
 	    if (focus == FollowKeyboardWin)
commit df2545b98d888924209cb889a68737c15f1aa209
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 08:50:43 2008 +0930

    xfree86: Sanity check before retrieving the paired device.
    
    Some pointer devices send key events [1], blindly getting the paired device
    crashes the server. So let's check if the device is a pointer before we try to
    get the paired device.
    
    [1] The MS Wireless Optical Desktop 2000's multimedia keys are sent through
    the pointer device, not through the keyboard device.

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index d8e23ee..c2dd600 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -722,7 +722,10 @@ xf86PostKeyboardEvent(DeviceIntPtr      device,
     int index;
 
 #if XFreeXDGA
-    DeviceIntPtr pointer = GetPairedDevice(device);
+    DeviceIntPtr pointer;
+
+    /* Some pointers send key events, paired device is wrong then. */
+    pointer = IsPointerDevice(device) ? device : GetPairedDevice(device);
 
     if (miPointerGetScreen(pointer)) {
         index = miPointerGetScreen(pointer)->myNum;
commit 5a4c6621aaf4e886f2c3b633e837ba359fedf921
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 08:29:05 2008 +0930

    Xi: some extra checks for validity of kbd and mouse.
    
    Floating SDs are paired with themselves, so the paired device may not be a
    proper keyboard or mouse. Put some extra checks in to avoid dereferencing a
    nullpointer later.

diff --git a/Xi/exevents.c b/Xi/exevents.c
index f28952f..38f6cb5 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -730,11 +730,15 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
         {
             kbd = GetPairedDevice(device);
             mouse = device;
+            if (!kbd->key) /* can happen with floating SDs */
+                kbd = NULL;
         }
         else
         {
             mouse = GetPairedDevice(device);
             kbd = device;
+            if (!mouse->valuator || !mouse->button) /* may be float. SDs */
+                mouse = NULL;
         }
         xE->u.keyButtonPointer.state = (kbd) ? (kbd->key->state) : 0;
         xE->u.keyButtonPointer.state |= (mouse) ? (mouse->button->state) : 0;
commit 8e0a6529303a52acc10905dd47c72a0d60979676
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 08:25:36 2008 +0930

    dix: When floating, set sprite to NULL before calling InitializeSprite.
    
    InitializeSprite won't create a new one if it already exists, with the result
    of overwriting the master's sprite. This master sprite is then assigned to the
    floating slave, and freed when the slave is reattached later.
    Setting the sprite to NULL forces InitializeSprite to alloc a new one, and
    this one can be freed without further repercussions.

diff --git a/dix/devices.c b/dix/devices.c
index c4cde26..df194de 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -2506,7 +2506,7 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
         return Success;
 
     /* free the existing sprite. */
-    if (!dev->u.master && dev->spriteInfo->sprite)
+    if (!dev->u.master && dev->spriteInfo->paired == dev)
         xfree(dev->spriteInfo->sprite);
 
     oldmaster = dev->u.master;
@@ -2515,15 +2515,22 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
     /* 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.
+     * Sprite has to be forced to NULL first, otherwise InitializeSprite won't
+     * alloc new memory but overwrite the previous one.
      */
     if (!master)
     {
-                              /* current root window */
-        InitializeSprite(dev, dev->spriteInfo->sprite->spriteTrace[0]);
+        WindowPtr currentRoot = dev->spriteInfo->sprite->spriteTrace[0];
+        dev->spriteInfo->sprite = NULL;
+        InitializeSprite(dev, currentRoot);
         dev->spriteInfo->spriteOwner = FALSE;
-
+        dev->spriteInfo->paired = dev;
     } else
+    {
         dev->spriteInfo->sprite = master->spriteInfo->sprite;
+        dev->spriteInfo->paired = master;
+        dev->spriteInfo->spriteOwner = FALSE;
+    }
 
     /* If we were connected to master device before, this MD may need to
      * change back to it's original classes.
commit e7211eb0b3d10323dab681bcb18580405ea18ab2
Author: Peter Hutterer <peter at cs.unisa.edu.au>
Date:   Thu Apr 10 08:08:54 2008 +0930

    Xi: When attaching, check for ptr -> ptr and keybd -> keybd.
    
    Some pointer devices have key classes (e.g. MS Optical Desktop 2000). The
    previous test was performed as Error if ptr -> keybd or keybd -> ptr. This
    doesnt work with such devices. New test is Succeed if ptr->ptr or
    keybd->keybd.

diff --git a/Xi/chdevhier.c b/Xi/chdevhier.c
index e9a5076..36797d9 100644
--- a/Xi/chdevhier.c
+++ b/Xi/chdevhier.c
@@ -272,10 +272,10 @@ ProcXChangeDeviceHierarchy(ClientPtr client)
                             goto unwind;
                         }
 
-                        if ((IsPointerDevice(newmaster) &&
-                                    !IsPointerDevice(ptr)) ||
+                        if (!((IsPointerDevice(newmaster) &&
+                                    IsPointerDevice(ptr)) ||
                                 (IsKeyboardDevice(newmaster) &&
-                                 !IsKeyboardDevice(ptr)))
+                                 IsKeyboardDevice(ptr))))
                         {
                             rc = BadDevice;
                             goto unwind;


More information about the xorg-commit mailing list