Xi: Add support for Enter and FocusIn grabs.

Enter grabs are checked for in CheckMotion(), each time the sprite window
changes the current grab is deactivated (if applicable) and the new grab is
activated (if applicable). Exception - if the grab is on a parent window of
the current window since we keep the grab across descendants.

Since CheckMotion() may change the grab status of a device, we mustn't get
"dev->deviceGrab.grab" in ProcessOtherEvents until after CheckMotion().
FocusIn grabs are checked in much the same manner.

The event delivery for grabs replaces the NotifyNormal on window change with
a NotifyGrab on window change. Note that this happens before the grab
activates, so the EnterNotify(NotifyGrab) is still delivered to the window,
not to the grabbing client. This is in line with the core protocol semantics
for NotifyGrab events.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer
2009-05-26 14:42:25 +10:00
parent ec2fe9660d
commit a7e23a79c1
6 changed files with 215 additions and 27 deletions

View File

@@ -962,7 +962,7 @@ ProcessRawEvent(RawDeviceEvent *ev, DeviceIntPtr device)
void
ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
{
GrabPtr grab = device->deviceGrab.grab;
GrabPtr grab;
Bool deactivateDeviceGrab = FALSE;
int key = 0, rootX, rootY;
ButtonClassPtr b;
@@ -1060,6 +1060,7 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
CallCallbacks(&DeviceEventCallback, (pointer) & eventinfo);
}
#endif
grab = device->deviceGrab.grab;
switch(event->type)
{
@@ -1509,6 +1510,52 @@ GrabKey(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device,
return AddPassiveGrabToList(client, grab);
}
/* Enter/FocusIn grab */
int
GrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
GrabParameters *param, GrabMask *mask)
{
WindowPtr pWin;
CursorPtr cursor;
GrabPtr grab;
Mask access_mode = DixGrabAccess;
int rc;
rc = CheckGrabValues(client, param);
if (rc != Success)
return rc;
rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
if (rc != Success)
return rc;
if (param->cursor == None)
cursor = NullCursor;
else {
rc = dixLookupResourceByType((pointer *)&cursor, param->cursor,
RT_CURSOR, client, DixUseAccess);
if (rc != Success)
{
client->errorValue = param->cursor;
return (rc == BadValue) ? BadCursor : rc;
}
access_mode |= DixForceAccess;
}
if (param->this_device_mode == GrabModeSync || param->other_devices_mode == GrabModeSync)
access_mode |= DixFreezeAccess;
rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
if (rc != Success)
return rc;
grab = CreateGrab(client->index, dev, dev, pWin, GRABTYPE_XI2,
mask, param, (type == XIGrabtypeEnter) ? XI_Enter : XI_FocusIn,
0, NULL, cursor);
if (!grab)
return BadAlloc;
return AddPassiveGrabToList(client, grab);
}
int
SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client,
Mask mask, Mask exclusivemasks)
@@ -1825,7 +1872,8 @@ DeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev)
switch (dev->focus->revert) {
case RevertToNone:
DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
if (!ActivateFocusInGrab(dev, NoneWin))
DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
dev->focus->win = NoneWin;
dev->focus->traceGood = 0;
break;
@@ -1836,12 +1884,14 @@ DeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev)
dev->focus->traceGood--;
}
while (!parent->realized);
DoFocusEvents(dev, pWin, parent, focusEventMode);
if (!ActivateFocusInGrab(dev, parent))
DoFocusEvents(dev, pWin, parent, focusEventMode);
dev->focus->win = parent;
dev->focus->revert = RevertToNone;
break;
case RevertToPointerRoot:
DoFocusEvents(dev, pWin, PointerRootWin, focusEventMode);
if (!ActivateFocusInGrab(dev, PointerRootWin))
DoFocusEvents(dev, pWin, PointerRootWin, focusEventMode);
dev->focus->win = PointerRootWin;
dev->focus->traceGood = 0;
break;
@@ -1851,11 +1901,13 @@ DeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev)
if (!kbd || (kbd == dev && kbd != inputInfo.keyboard))
kbd = inputInfo.keyboard;
if (kbd->focus->win) {
DoFocusEvents(dev, pWin, kbd->focus->win, focusEventMode);
if (!ActivateFocusInGrab(dev, kbd->focus->win))
DoFocusEvents(dev, pWin, kbd->focus->win, focusEventMode);
dev->focus->win = FollowKeyboardWin;
dev->focus->traceGood = 0;
} else {
DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
if (!ActivateFocusInGrab(dev, NoneWin))
DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
dev->focus->win = NoneWin;
dev->focus->traceGood = 0;
}