diff --git a/dix/devices.c b/dix/devices.c index 4672b2ac1..b56423a6d 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -135,6 +135,7 @@ AddInputDevice(DeviceProc deviceProc, Bool autoStart) dev->deviceGrab.grab = NullGrab; dev->deviceGrab.grabTime = currentTime; dev->deviceGrab.fromPassiveGrab = FALSE; + dev->deviceGrab.implicitGrab = FALSE; dev->key = (KeyClassPtr)NULL; dev->valuator = (ValuatorClassPtr)NULL; diff --git a/dix/events.c b/dix/events.c index 4c5f5b9e2..f6e90214d 100644 --- a/dix/events.c +++ b/dix/events.c @@ -209,6 +209,12 @@ static xEvent *xeviexE; ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ Mod3Mask | Mod4Mask | Mod5Mask ) #define AllEventMasks (lastEventMask|(lastEventMask-1)) + +/** + * Used to indicate a implicit passive grab created by a ButtonPress event. + * See DeliverEventsToWindow(). + */ +#define ImplicitGrabMask (1 << 7) /* * The following relies on the fact that the ButtonMotionMasks are equal * to the corresponding ButtonMasks from the current modifier/button state. @@ -1238,6 +1244,14 @@ PlayReleasedEvents(void) } } +/** + * Freeze or thaw the given devices. The device's processing proc is + * switched to either the real processing proc (in case of thawing) or an + * enqueuing processing proc (usually EnqueueEvent()). + * + * @param dev The device to freeze/thaw + * @param frozen True to freeze or false to thaw. + */ static void FreezeThaw(DeviceIntPtr dev, Bool frozen) { @@ -1248,6 +1262,14 @@ FreezeThaw(DeviceIntPtr dev, Bool frozen) dev->public.processInputProc = dev->public.realInputProc; } +/** + * Unfreeze devices and replay all events to the respective clients. + * + * ComputeFreezes takes the first event in the device's frozen event queue. It + * runs up the sprite tree (spriteTrace) and searches for the window to replay + * the events from. If it is found, it checks for passive grabs one down from + * the window or delivers the events. + */ void ComputeFreezes(void) { @@ -1394,7 +1416,8 @@ CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) * on, but core events will be sent to other clients. * Can cause the cursor to change if a grab cursor is set. * - * Extension devices are set up for ActivateKeyboardGrab(). + * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab + * is an implicit grab caused by a ButtonPress event. * * @param mouse The device to grab. * @param grab The grab structure, needs to be setup. @@ -1428,7 +1451,8 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, grab->cursor->refcnt++; grabinfo->activeGrab = *grab; grabinfo->grab = &grabinfo->activeGrab; - grabinfo->fromPassiveGrab = autoGrab; + grabinfo->fromPassiveGrab = autoGrab & ~ImplicitGrabMask; + grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; PostNewCursor(mouse); CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode); } @@ -1987,7 +2011,8 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent tempGrab.genericMasks = NULL; (*inputInfo.pointer->deviceGrab.ActivateGrab)(pDev, &tempGrab, - currentTime, TRUE); + currentTime, + TRUE | ImplicitGrabMask); } else if ((type == MotionNotify) && deliveries) pDev->valuator->motionHintWindow = pWin; @@ -3243,13 +3268,19 @@ DeliverGrabbedEvent(xEvent *xE, DeviceIntPtr thisDev, } else { Mask mask = grab->eventMask; - if (grabinfo->fromPassiveGrab && (xE->u.u.type & - EXTENSION_EVENT_BASE)) + if (grabinfo->fromPassiveGrab && + grabinfo->implicitGrab && + (xE->u.u.type & EXTENSION_EVENT_BASE)) mask = grab->deviceMask; FixUpEventFromWindow(thisDev, xE, grab->window, None, TRUE); - deliveries = TryClientEvents(rClient(grab), xE, count, - mask, filters[xE->u.u.type], grab); + + if (!(!(xE->u.u.type & EXTENSION_EVENT_BASE) && + IsInterferingGrab(rClient(grab), thisDev, xE))) + { + deliveries = TryClientEvents(rClient(grab), xE, count, + mask, filters[xE->u.u.type], grab); + } } if (deliveries && (xE->u.u.type == MotionNotify #ifdef XINPUT @@ -4629,6 +4660,8 @@ ProcGrabPointer(ClientPtr client) if (oldCursor) FreeCursor (oldCursor, (Cursor)0); rep.status = GrabSuccess; + + RemoveOtherCoreGrabs(client, device); } WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); return Success; @@ -4797,6 +4830,47 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev, return Success; } +/** + * Deactivate any core grabs on the given client except the given device. + * + * This fixes race conditions where clients deal with implicit passive grabs + * on one device, but then actively grab their client pointer, which is + * another device. + * + * Grabs are only removed if the other device matches the type of device. If + * dev is a pointer device, only other pointer grabs are removed. Likewise, if + * dev is a keyboard device, only keyboard grabs are removed. + * + * If dev doesn't have a grab, do nothing and go for a beer. + * + * @param client The client that is to be limited. + * @param dev The only device allowed to have a grab on the client. + */ + +_X_EXPORT void +RemoveOtherCoreGrabs(ClientPtr client, DeviceIntPtr dev) +{ + if (!dev || !dev->deviceGrab.grab) + return; + + DeviceIntPtr it = inputInfo.devices; + for (; it; it = it->next) + { + if (it == dev) + continue; + /* check for IsPointer Device */ + + if (it->deviceGrab.grab && + it->deviceGrab.grab->coreGrab && + SameClient(it->deviceGrab.grab, client)) + { + if ((IsPointerDevice(dev) && IsPointerDevice(it)) || + (IsKeyboardDevice(dev) && IsKeyboardDevice(it))) + (*it->deviceGrab.DeactivateGrab)(it); + } + } +} + /** * Server-side protocol handling for GrabKeyboard request. * @@ -4813,10 +4887,13 @@ ProcGrabKeyboard(ClientPtr client) REQUEST_SIZE_MATCH(xGrabKeyboardReq); if (XaceHook(XACE_DEVICE_ACCESS, client, keyboard, TRUE)) + { result = GrabDevice(client, keyboard, stuff->keyboardMode, stuff->pointerMode, stuff->grabWindow, stuff->ownerEvents, stuff->time, KeyPressMask | KeyReleaseMask, &rep.status, TRUE); + RemoveOtherCoreGrabs(client, keyboard); + } else { result = Success; rep.status = AlreadyGrabbed; @@ -5857,3 +5934,4 @@ ExtUngrabDevice(ClientPtr client, DeviceIntPtr dev) } + diff --git a/include/dix.h b/include/dix.h index f0e2f2ae6..be1cb95f2 100644 --- a/include/dix.h +++ b/include/dix.h @@ -494,6 +494,10 @@ extern int GrabDevice( CARD8 * /* status */, Bool /* coreGrab */); +extern void RemoveOtherCoreGrabs( + ClientPtr /* client */, + DeviceIntPtr /* dev */); + extern void InitEvents(void); extern void InitSprite( DeviceIntPtr /* pDev */, diff --git a/include/inputstr.h b/include/inputstr.h index 986232c79..d9128cce8 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -333,9 +333,11 @@ typedef struct { #define FROZEN_NO_EVENT 5 #define FROZEN_WITH_EVENT 6 #define THAW_OTHERS 7 + typedef struct _GrabInfoRec { - TimeStamp grabTime; - Bool fromPassiveGrab; + TimeStamp grabTime; + Bool fromPassiveGrab; /* true if from passive grab */ + Bool implicitGrab; /* implicit from ButtonPress */ GrabRec activeGrab; GrabPtr grab; CARD8 activatingKey;