summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter@cs.unisa.edu.au>2007-06-19 11:28:07 +0930
committerPeter Hutterer <peter@cs.unisa.edu.au>2007-06-19 11:28:07 +0930
commit9e257029c760883c4ea0715d4fd06476f3fe8053 (patch)
tree64710f4d84bab6b086e9a7bca7c3c697713daf86
parent3e894974cdd6a75683d4601f71622d1da7ec4395 (diff)
Add implicitGrab field to GrabInfoRec.
Is set when passive grab is implicit as result of a ButtonPress event. If this is the case, we need to store the XI mask as well as the core mask to ensure delivery of XI events during the grab's lifetime. Remove all core grabs on other devices when client issues a GrabPointer or GrabKeyboard request. Let's assume that the client really only wants one device to interact, so this seems like a reasonable solution.
-rw-r--r--dix/devices.c1
-rw-r--r--dix/events.c92
-rw-r--r--include/dix.h4
-rw-r--r--include/inputstr.h6
4 files changed, 94 insertions, 9 deletions
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 Button<n>MotionMasks are equal
* to the corresponding Button<n>Masks 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;
@@ -4798,6 +4831,47 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev,
}
/**
+ * 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.
*
* Grabs the client's keyboard and returns success status to client.
@@ -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;