diff options
author | Peter Hutterer <peter@cs.unisa.edu.au> | 2007-08-08 13:10:00 +0930 |
---|---|---|
committer | Peter Hutterer <peter@cs.unisa.edu.au> | 2007-08-08 13:10:00 +0930 |
commit | c02128532e910e813fba94983733942d30c2d5cb (patch) | |
tree | aaa3cb5019cf48ac46c4f41fb57333fa49943989 /dix | |
parent | b8abeaf74ee8296d4bc3164a5a253624f984a6d4 (diff) |
dix: Allow flexible devices for passive core grabs.
A passive core grab doesn't specify the device, and is thus created with the
ClientPointer as device. When this grab is activated later, don't actually
activate the grab on the grab device, but rather change the device to the one
that caused the grab to activate. Same procedure for keyboards.
Makes core apps _A LOT_ more useable and reduces the need to set the
ClientPointer.
Only applies to core grabs!
Diffstat (limited to 'dix')
-rw-r--r-- | dix/events.c | 193 | ||||
-rw-r--r-- | dix/grabs.c | 28 |
2 files changed, 205 insertions, 16 deletions
diff --git a/dix/events.c b/dix/events.c index faf8eedd5..7627f4ebe 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1685,17 +1685,45 @@ AllowSome(ClientPtr client, * Server-side protocol handling for AllowEvents request. * * Release some events from a frozen device. + * + * In some cases, the grab the client has is not on the ClientPointer but on + * some other device (see ProcGrabPointer comments). To cover this case, we + * need to run through all devices to ensure we don't forget the device we + * actually have a grab on. */ int ProcAllowEvents(ClientPtr client) { TimeStamp time; - DeviceIntPtr mouse = PickPointer(client); - DeviceIntPtr keybd = PickKeyboard(client); + DeviceIntPtr mouse = NULL, + grabbed; + DeviceIntPtr keybd = NULL; + GrabPtr grab; REQUEST(xAllowEventsReq); REQUEST_SIZE_MATCH(xAllowEventsReq); time = ClientTimeToServerTime(stuff->time); + + for (grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next) + { + grab = grabbed->deviceGrab.grab; + if (grab && grab->coreGrab && SameClient(grab, client)) + { + if (IsPointerDevice(grabbed)) + mouse = grabbed; + else if (IsKeyboardDevice(grabbed)) + keybd = grabbed; + + if (mouse && keybd) + break; + } + } + + if (!mouse) + mouse = PickPointer(client); + if (!keybd) + keybd = PickKeyboard(client); + switch (stuff->mode) { case ReplayPointer: @@ -3104,7 +3132,8 @@ CheckPassiveGrabsOnWindow( #else grab->modifierDevice->key->state; #endif - if (GrabMatchesSecond(&tempGrab, grab) && + /* ignore the device for core events when comparing grabs */ + if (GrabMatchesSecond(&tempGrab, grab, (xE->u.u.type < LASTEvent)) && (!grab->confineTo || (grab->confineTo->realized && BorderSizeNotEmpty(device, grab->confineTo)))) @@ -3119,6 +3148,23 @@ CheckPassiveGrabsOnWindow( } #endif grabinfo = &device->deviceGrab; + /* A passive grab may have been created for a different device + than it is assigned to at this point in time. + Update the grab's device and modifier device to reflect the + current state. + XXX: Since XGrabDeviceButton requires to specify the + modifierDevice explicitly, we don't override this choice. + This essentially requires a client to re-create all + passiveGrabs when the pairing changes... oh well. + */ + if (xE->u.u.type < LASTEVENT) + { + grab->device = device; + grab->modifierDevice = GetPairedKeyboard(device); + if (!grab->modifierDevice) + grab->modifierDevice = inputInfo.keyboard; + } + (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); FixUpEventFromWindow(device, xE, grab->window, None, TRUE); @@ -4607,10 +4653,16 @@ ProcGetInputFocus(ClientPtr client) } /** - * Server-side protocol handling for Grabpointer request. + * Server-side protocol handling for GrabPointer request. * * Sets an active grab on the client's ClientPointer and returns success * status to client. + * + * A special case of GrabPointer is when there is already a grab on some + * device (by the same client). In this case, this grab is overwritten, and + * the device stays as it is. This case can happen when a client has a passive + * grab and then grabs the pointer, or when the client already has an active + * grab and the ClientPointer was changed since. */ int ProcGrabPointer(ClientPtr client) @@ -4623,6 +4675,7 @@ ProcGrabPointer(ClientPtr client) REQUEST(xGrabPointerReq); TimeStamp time; int rc; + DeviceIntPtr grabbed = NULL; REQUEST_SIZE_MATCH(xGrabPointerReq); UpdateCurrentTime(); @@ -4677,6 +4730,21 @@ ProcGrabPointer(ClientPtr client) rep.type = X_Reply; rep.sequenceNumber = client->sequence; rep.length = 0; + + /* Check if a the client already has a grab on a device */ + for(grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next) + { + if (IsPointerDevice(grabbed)) + { + grab = grabbed->deviceGrab.grab; + if (grab && grab->coreGrab && SameClient(grab, client)) + { + device = grabbed; + break; + } + } + } + grab = device->deviceGrab.grab; if ((grab) && !SameClient(grab, client)) rep.status = AlreadyGrabbed; @@ -4720,6 +4788,7 @@ ProcGrabPointer(ClientPtr client) FreeCursor (oldCursor, (Cursor)0); rep.status = GrabSuccess; + /* guarantee only one core pointer grab at a time by this client */ RemoveOtherCoreGrabs(client, device); } WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); @@ -4732,12 +4801,14 @@ ProcGrabPointer(ClientPtr client) * Changes properties of the grab hold by the client. If the client does not * hold an active grab on the device, nothing happens. * - * Works on the client's ClientPointer. + * Works on the client's ClientPointer, but in some cases the client may have + * a grab on a device that isn't the ClientPointer (see ProcGrabPointer + * comments). */ int ProcChangeActivePointerGrab(ClientPtr client) { - DeviceIntPtr device = PickPointer(client); + DeviceIntPtr device, grabbed; GrabPtr grab = device->deviceGrab.grab; CursorPtr newCursor, oldCursor; REQUEST(xChangeActivePointerGrabReq); @@ -4761,6 +4832,31 @@ ProcChangeActivePointerGrab(ClientPtr client) return BadCursor; } } + if (!grab && !SameClient(grab, client)) + { + /* no grab on ClientPointer, or some other client has a grab on our + * ClientPointer, let's check if we have a pointer grab on some other + * device. */ + for(grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next) + { + if (IsPointerDevice(grabbed)) + { + grab = grabbed->deviceGrab.grab; + if (grab && grab->coreGrab && SameClient(grab, client)) + { + device = grabbed; + break; + } + } + } + /* nope. no grab on any actual device */ + if (!grabbed) + { + device = inputInfo.pointer; + grab = inputInfo.pointer->deviceGrab.grab; + } + } + if (!grab) return Success; if (!SameClient(grab, client)) @@ -4783,12 +4879,17 @@ ProcChangeActivePointerGrab(ClientPtr client) /** * Server-side protocol handling for UngrabPointer request. * - * Deletes the pointer grab on the client's ClientPointer device. + * Deletes a pointer grab on a device the client has grabbed. This should be + * the ClientPointer, but may not be. So we search the device list for a + * device we have a pointer grab on and then ungrab this device. (see + * ProcGrabPointer comments). We are guaranteed that the client doesn't have + * more than one core pointer grab at a time. */ int ProcUngrabPointer(ClientPtr client) { - DeviceIntPtr device = PickPointer(client); + DeviceIntPtr device = PickPointer(client), + grabbed; GrabPtr grab; TimeStamp time; REQUEST(xResourceReq); @@ -4796,6 +4897,31 @@ ProcUngrabPointer(ClientPtr client) REQUEST_SIZE_MATCH(xResourceReq); UpdateCurrentTime(); grab = device->deviceGrab.grab; + + if (!grab || !grab->coreGrab || !SameClient(grab, client)) + { + /* No pointer grab on ClientPointer. May be a pointer grab on some + * other device */ + for(grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next) + { + if (IsPointerDevice(grabbed)) + { + grab = grabbed->deviceGrab.grab; + if (grab && grab->coreGrab && SameClient(grab, client)) + { + device = grabbed; + break; + } + } + } + /* nope. no grab on any actual device */ + if (!grabbed) + { + device = inputInfo.pointer; + grab = inputInfo.pointer->deviceGrab.grab; + } + } + time = ClientTimeToServerTime(stuff->id); if ((CompareTimeStamps(time, currentTime) != LATER) && (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && @@ -4935,6 +5061,15 @@ RemoveOtherCoreGrabs(ClientPtr client, DeviceIntPtr dev) * Server-side protocol handling for GrabKeyboard request. * * Grabs the client's keyboard and returns success status to client. + * + * In some special cases the client may already have a grab on a keyboard that + * is not the one that is paired with the ClientPointer. This can happen when + * the client alreay has a passive grab on some keyboard device, or when the + * client actively grabbed the keyboard and the ClientPointer or keyboard + * pairing was changed since. + * Therefore, we need to run through all the keyboards available and check if + * there's already a grab on it from our client. The client will only ever + * have one core keyboard grab at a time. */ int ProcGrabKeyboard(ClientPtr client) @@ -4942,16 +5077,32 @@ ProcGrabKeyboard(ClientPtr client) xGrabKeyboardReply rep; REQUEST(xGrabKeyboardReq); int result; - DeviceIntPtr keyboard = PickKeyboard(client); + DeviceIntPtr keyboard = PickKeyboard(client), + grabbed; + GrabPtr grab; REQUEST_SIZE_MATCH(xGrabKeyboardReq); + for (grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next) + { + if (IsKeyboardDevice(grabbed)) + { + grab = grabbed->deviceGrab.grab; + if (grab && grab->coreGrab && SameClient(grab, client)) + { + keyboard = grabbed; + break; + } + } + } + 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); + /* ensure only one core keyboard grab by this client */ RemoveOtherCoreGrabs(client, keyboard); } else { @@ -4972,18 +5123,40 @@ ProcGrabKeyboard(ClientPtr client) * Server-side protocol handling for UngrabKeyboard request. * * Deletes a possible grab on the client's keyboard. + * + * We may have a grab on a keyboard that isn't the ClientPointer's keyboard. + * Thus we need to check all keyboar devices for a grab. (see ProcGrabKeyboard + * comments) */ int ProcUngrabKeyboard(ClientPtr client) { - DeviceIntPtr device = PickKeyboard(client); + DeviceIntPtr device = PickKeyboard(client), + grabbed; GrabPtr grab; TimeStamp time; REQUEST(xResourceReq); REQUEST_SIZE_MATCH(xResourceReq); UpdateCurrentTime(); + + if (!grab || !grab->coreGrab || !SameClient(grab, client)) + { + for (grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next) + { + if (IsKeyboardDevice(grabbed)) + { + grab = device->deviceGrab.grab; + if (grab && grab->coreGrab && SameClient(grab, client)) + { + device = grabbed; + break; + } + } + } + } grab = device->deviceGrab.grab; + time = ClientTimeToServerTime(stuff->id); if ((CompareTimeStamps(time, currentTime) != LATER) && (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && diff --git a/dix/grabs.c b/dix/grabs.c index 9150c3c14..01f4b6439 100644 --- a/dix/grabs.c +++ b/dix/grabs.c @@ -240,12 +240,28 @@ GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) return FALSE; } +/** + * Compares two grabs and returns TRUE if the first grab matches the second + * grab. + * + * A match is when + * - the devices set for the grab are equal (this is optional). + * - the event types for both grabs are equal. + * - XXX + * + * @param ignoreDevice TRUE if the device settings on the grabs are to be + * ignored. + * @return TRUE if the grabs match or FALSE otherwise. + */ Bool -GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) +GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice) { - if ((pFirstGrab->device != pSecondGrab->device) || - (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || - (pFirstGrab->type != pSecondGrab->type)) + if (!ignoreDevice && + ((pFirstGrab->device != pSecondGrab->device) || + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) + return FALSE; + + if (pFirstGrab->type != pSecondGrab->type) return FALSE; if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || @@ -278,7 +294,7 @@ AddPassiveGrabToList(GrabPtr pGrab) for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) { - if (GrabMatchesSecond(pGrab, grab)) + if (GrabMatchesSecond(pGrab, grab, FALSE)) { if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) { @@ -343,7 +359,7 @@ DeletePassiveGrabFromList(GrabPtr pMinuendGrab) grab = grab->next) { if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) || - !GrabMatchesSecond(grab, pMinuendGrab)) + !GrabMatchesSecond(grab, pMinuendGrab, FALSE)) continue; if (GrabSupersedesSecond(pMinuendGrab, grab)) { |