From e7211eb0b3d10323dab681bcb18580405ea18ab2 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 08:08:54 +0930 Subject: [PATCH 01/10] 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. --- Xi/chdevhier.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Xi/chdevhier.c b/Xi/chdevhier.c index e9a5076a9..36797d90c 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; From 8e0a6529303a52acc10905dd47c72a0d60979676 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 08:25:36 +0930 Subject: [PATCH 02/10] 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. --- dix/devices.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dix/devices.c b/dix/devices.c index c4cde2660..df194de17 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. From 5a4c6621aaf4e886f2c3b633e837ba359fedf921 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 08:29:05 +0930 Subject: [PATCH 03/10] 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. --- Xi/exevents.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Xi/exevents.c b/Xi/exevents.c index f28952fdc..38f6cb57a 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; From df2545b98d888924209cb889a68737c15f1aa209 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 08:50:43 +0930 Subject: [PATCH 04/10] 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. --- hw/xfree86/common/xf86Xinput.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index d8e23ee8d..c2dd6004b 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; From cc7dab2d04da4ca164eeec1a3296df1706585466 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 09:58:50 +0930 Subject: [PATCH 05/10] 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. --- dix/events.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dix/events.c b/dix/events.c index 6ecd90c08..a2a0c1a67 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) From bce6091c6b04ff2db704ae4f161179d21dcbec59 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 09:59:45 +0930 Subject: [PATCH 06/10] 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. --- dix/events.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dix/events.c b/dix/events.c index a2a0c1a67..305502ac9 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 From 48249425275cc90242497aee9968e5f1ffc86698 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 14:36:10 +0930 Subject: [PATCH 07/10] 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. --- Xi/exevents.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 38f6cb57a..ba7f3b2bb 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) { - FreeDeviceClass(FocusClass, (pointer)&to->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) + { + /* 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) { From a88386ee277d136caaaeec305f8753f23f9b6274 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 14:36:57 +0930 Subject: [PATCH 08/10] 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. --- Xi/exevents.c | 28 +++++++++++++++++++++++++++- dix/events.c | 4 ++-- include/dix.h | 1 + 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index ba7f3b2bb..a93fef452 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 305502ac9..144591469 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 e00df29a2..57ffee9b9 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! From 04dff74ffdf727015e3721aae4ea13acc498cd1c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 19:22:59 +0930 Subject: [PATCH 09/10] 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. --- dix/devices.c | 3 +- dix/events.c | 124 ++++++++++++++++++++++++-------------------- dix/window.c | 2 + include/input.h | 35 +++++++++++++ include/windowstr.h | 12 +++-- 5 files changed, 114 insertions(+), 62 deletions(-) diff --git a/dix/devices.c b/dix/devices.c index df194de17..2d7885e28 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 144591469..1b62db05f 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 ee4c75649..d3160c903 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 9ba12db79..0c993eed0 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 406087e17..a36dc2972 100644 --- a/include/windowstr.h +++ b/include/windowstr.h @@ -59,6 +59,7 @@ SOFTWARE. #include "miscstruct.h" #include #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; /* From b4380d8030927c940ddaea83c4cf24e0b9eb7b96 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 10 Apr 2008 19:25:43 +0930 Subject: [PATCH 10/10] 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. --- dix/devices.c | 103 +------------------------------------------------- 1 file changed, 1 insertion(+), 102 deletions(-) diff --git a/dix/devices.c b/dix/devices.c index 2d7885e28..a78a1255d 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);