summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2009-05-26 14:42:25 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2009-05-27 14:40:58 +1000
commita7e23a79c1fc429aedbf9b6c0e78b1c8d7e02238 (patch)
tree5fc32f0134ef45239df861c6dd8def5e509297c6
parentec2fe9660dbc0c16cdaca33b3b878011857e0fe2 (diff)
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>
-rw-r--r--Xi/exevents.c64
-rw-r--r--Xi/xipassivegrab.c36
-rw-r--r--dix/eventconvert.c8
-rw-r--r--dix/events.c122
-rw-r--r--include/dix.h5
-rw-r--r--include/exevents.h7
6 files changed, 215 insertions, 27 deletions
diff --git a/Xi/exevents.c b/Xi/exevents.c
index 83891f87f..91a346138 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -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;
}
diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c
index f53b0504c..a8807bd32 100644
--- a/Xi/xipassivegrab.c
+++ b/Xi/xipassivegrab.c
@@ -95,12 +95,21 @@ ProcXIPassiveGrabDevice(ClientPtr client)
return ret;
if (stuff->grab_type != XIGrabtypeButton &&
- stuff->grab_type != XIGrabtypeKeysym)
+ stuff->grab_type != XIGrabtypeKeysym &&
+ stuff->grab_type != XIGrabtypeEnter &&
+ stuff->grab_type != XIGrabtypeFocusIn)
{
client->errorValue = stuff->grab_type;
return BadValue;
}
+ if ((stuff->grab_type == XIGrabtypeEnter ||
+ stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0)
+ {
+ client->errorValue = stuff->detail;
+ return BadValue;
+ }
+
/* Can't grab for modifiers on an attached slave device */
if (!IsMaster(dev))
{
@@ -175,6 +184,11 @@ ProcXIPassiveGrabDevice(ClientPtr client)
status = GrabKey(client, dev, mod_dev, stuff->detail,
&param, GRABTYPE_XI2, &mask);
break;
+ case XIGrabtypeEnter:
+ case XIGrabtypeFocusIn:
+ status = GrabWindow(client, dev, stuff->grab_type,
+ &param, &mask);
+ break;
}
if (status != GrabSuccess)
@@ -251,12 +265,21 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
return rc;
if (stuff->grab_type != XIGrabtypeButton &&
- stuff->grab_type != XIGrabtypeKeysym)
+ stuff->grab_type != XIGrabtypeKeysym &&
+ stuff->grab_type != XIGrabtypeEnter &&
+ stuff->grab_type != XIGrabtypeFocusIn)
{
client->errorValue = stuff->grab_type;
return BadValue;
}
+ if ((stuff->grab_type == XIGrabtypeEnter ||
+ stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0)
+ {
+ client->errorValue = stuff->detail;
+ return BadValue;
+ }
+
rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess);
if (rc != Success)
return rc;
@@ -269,8 +292,13 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
tempGrab.resource = client->clientAsMask;
tempGrab.device = dev;
tempGrab.window = win;
- tempGrab.type =
- (stuff->grab_type == XIGrabtypeButton) ? XI_ButtonPress : XI_KeyPress;
+ switch(stuff->grab_type)
+ {
+ case XIGrabtypeButton: tempGrab.type = XI_ButtonPress; break;
+ case XIGrabtypeKeysym: tempGrab.type = XI_KeyPress; break;
+ case XIGrabtypeEnter: tempGrab.type = XI_Enter; break;
+ case XIGrabtypeFocusIn: tempGrab.type = XI_FocusIn; break;
+ }
tempGrab.grabtype = GRABTYPE_XI2;
tempGrab.modifierDevice = mod_dev;
tempGrab.modifiersDetail.pMask = NULL;
diff --git a/dix/eventconvert.c b/dix/eventconvert.c
index 403282cb3..507289179 100644
--- a/dix/eventconvert.c
+++ b/dix/eventconvert.c
@@ -155,6 +155,12 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
{
switch (ev->any.type)
{
+ /* Enter/FocusIn are for grabs. We don't need an actual event, since
+ * the real events delivered are triggered elsewhere */
+ case ET_Enter:
+ case ET_FocusIn:
+ *xi = NULL;
+ return Success;
case ET_Motion:
case ET_ButtonPress:
case ET_ButtonRelease:
@@ -525,6 +531,8 @@ GetXI2Type(InternalEvent *event)
case ET_Hierarchy: xi2type = XI_HierarchyChanged; break;
case ET_DeviceChanged: xi2type = XI_DeviceChanged; break;
case ET_Raw: xi2type = XI_RawEvent; break;
+ case ET_FocusIn: xi2type = XI_FocusIn; break;
+ case ET_FocusOut: xi2type = XI_FocusOut; break;
default:
break;
}
diff --git a/dix/events.c b/dix/events.c
index 5e1ab1fa5..5d22016f7 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -224,6 +224,10 @@ static void CheckPhysLimits(DeviceIntPtr pDev,
Bool generateEvents,
Bool confineToScreen,
ScreenPtr pScreen);
+static Bool CheckPassiveGrabsOnWindow(WindowPtr pWin,
+ DeviceIntPtr device,
+ DeviceEvent *event,
+ BOOL checkCore);
/**
* Main input device struct.
@@ -2624,6 +2628,74 @@ XYToWindow(DeviceIntPtr pDev, int x, int y)
}
/**
+ * Ungrab a currently FocusIn grabbed device and grab the device on the
+ * given window. If the win given is the NoneWin, the device is ungrabbed if
+ * applicable and FALSE is returned.
+ *
+ * @returns TRUE if the device has been grabbed, or FALSE otherwise.
+ */
+BOOL
+ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr win)
+{
+ DeviceEvent event;
+
+ if (dev->deviceGrab.grab &&
+ dev->deviceGrab.fromPassiveGrab &&
+ dev->deviceGrab.grab->type == XI_Enter)
+ {
+ if (dev->deviceGrab.grab->window == win ||
+ IsParent(dev->deviceGrab.grab->window, win))
+ return FALSE;
+ (*dev->deviceGrab.DeactivateGrab)(dev);
+ }
+
+ if (win == NoneWin || win == PointerRootWin)
+ return FALSE;
+
+ memset(&event, 0, sizeof(DeviceEvent));
+ event.header = ET_Internal;
+ event.type = ET_FocusIn;
+ event.length = sizeof(DeviceEvent);
+ event.time = GetTimeInMillis();
+ event.deviceid = dev->id;
+ event.sourceid = dev->id;
+ event.detail.button = 0;
+ return CheckPassiveGrabsOnWindow(win, dev, &event, FALSE);
+}
+
+/**
+ * Ungrab a currently Enter grabbed device and grab the deice for the given
+ * window.
+ *
+ * @returns TRUE if the device has been grabbed, or FALSE otherwise.
+ */
+static BOOL
+ActivateEnterGrab(DeviceIntPtr dev, WindowPtr win)
+{
+ DeviceEvent event;
+
+ if (dev->deviceGrab.grab &&
+ dev->deviceGrab.fromPassiveGrab &&
+ dev->deviceGrab.grab->type == XI_Enter)
+ {
+ if (dev->deviceGrab.grab->window == win ||
+ IsParent(dev->deviceGrab.grab->window, win))
+ return FALSE;
+ (*dev->deviceGrab.DeactivateGrab)(dev);
+ }
+
+ memset(&event, 0, sizeof(DeviceEvent));
+ event.header = ET_Internal;
+ event.type = ET_Enter;
+ event.length = sizeof(DeviceEvent);
+ event.time = GetTimeInMillis();
+ event.deviceid = dev->id;
+ event.sourceid = dev->id;
+ event.detail.button = 0;
+ return CheckPassiveGrabsOnWindow(win, dev, &event, FALSE);
+}
+
+/**
* Update the sprite coordinates based on the event. Update the cursor
* position, then update the event with the new coordinates that may have been
* changed. If the window underneath the sprite has changed, change to new
@@ -2637,7 +2709,7 @@ XYToWindow(DeviceIntPtr pDev, int x, int y)
Bool
CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev)
{
- WindowPtr prevSpriteWin;
+ WindowPtr prevSpriteWin, newSpriteWin;
SpritePtr pSprite = pDev->spriteInfo->sprite;
CHECKEVENT(ev);
@@ -2715,17 +2787,23 @@ CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev)
ev->root_y = pSprite->hot.y;
}
- pSprite->win = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y);
+ newSpriteWin = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y);
- if (pSprite->win != prevSpriteWin)
+ if (newSpriteWin != prevSpriteWin)
{
+ if (!ev)
+ UpdateCurrentTimeIf();
+
if (prevSpriteWin != NullWindow) {
- if (!ev)
- UpdateCurrentTimeIf();
- DoEnterLeaveEvents(pDev, prevSpriteWin, pSprite->win,
- NotifyNormal);
+ if (!ActivateEnterGrab(pDev, newSpriteWin))
+ DoEnterLeaveEvents(pDev, prevSpriteWin,
+ newSpriteWin, NotifyNormal);
}
- PostNewCursor(pDev);
+ /* set pSprite->win after ActivateEnterGrab, otherwise
+ sprite window == grab_window and no enter/leave events are
+ sent. */
+ pSprite->win = newSpriteWin;
+ PostNewCursor(pDev);
return FALSE;
}
return TRUE;
@@ -3443,11 +3521,14 @@ CheckPassiveGrabsOnWindow(
(*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE);
- FixUpEventFromWindow(device, xE, grab->window, None, TRUE);
+ if (xE)
+ {
+ FixUpEventFromWindow(device, xE, grab->window, None, TRUE);
- TryClientEvents(rClient(grab), device, xE, count,
- GetEventFilter(device, xE),
- GetEventFilter(device, xE), grab);
+ TryClientEvents(rClient(grab), device, xE, count,
+ GetEventFilter(device, xE),
+ GetEventFilter(device, xE), grab);
+ }
if (grabinfo->sync.state == FROZEN_NO_EVENT)
{
@@ -4344,9 +4425,14 @@ SetInputFocus(
return Success;
mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal;
if (focus->win == FollowKeyboardWin)
- DoFocusEvents(dev, keybd->focus->win, focusWin, mode);
- else
- DoFocusEvents(dev, focus->win, focusWin, mode);
+ {
+ if (!ActivateFocusInGrab(dev, focusWin))
+ DoFocusEvents(dev, keybd->focus->win, focusWin, mode);
+ } else
+ {
+ if (!ActivateFocusInGrab(dev, focusWin))
+ DoFocusEvents(dev, focus->win, focusWin, mode);
+ }
focus->time = time;
focus->revert = revertTo;
if (focusID == FollowKeyboard)
@@ -5327,12 +5413,14 @@ DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources)
|| clients[CLIENT_ID(parent->drawable.id)]->clientGone
#endif
);
- DoFocusEvents(keybd, pWin, parent, focusEventMode);
+ if (!ActivateFocusInGrab(keybd, parent))
+ DoFocusEvents(keybd, pWin, parent, focusEventMode);
focus->win = parent;
focus->revert = RevertToNone;
break;
case RevertToPointerRoot:
- DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode);
+ if (!ActivateFocusInGrab(keybd, PointerRootWin))
+ DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode);
focus->win = PointerRootWin;
focus->traceGood = 0;
break;
diff --git a/include/dix.h b/include/dix.h
index d4bec5f20..bfb036933 100644
--- a/include/dix.h
+++ b/include/dix.h
@@ -350,6 +350,10 @@ extern void ActivateKeyboardGrab(
extern void DeactivateKeyboardGrab(
DeviceIntPtr /* keybd */);
+extern BOOL ActivateFocusInGrab(
+ DeviceIntPtr /* dev */,
+ WindowPtr /* win */);
+
extern void AllowSome(
ClientPtr /* client */,
TimeStamp /* time */,
@@ -582,6 +586,7 @@ extern Bool IsKeyboardDevice(DeviceIntPtr dev);
extern Bool IsPointerEvent(InternalEvent *event);
extern Bool IsMaster(DeviceIntPtr dev);
+
/*
* These are deprecated compatibility functions and will be removed soon!
* Please use the noted replacements instead.
diff --git a/include/exevents.h b/include/exevents.h
index 95d08cc7f..5878413c2 100644
--- a/include/exevents.h
+++ b/include/exevents.h
@@ -107,6 +107,13 @@ extern int GrabKey(
GrabType /* grabtype */,
GrabMask* /* eventMask */);
+extern int GrabWindow(
+ ClientPtr /* client */,
+ DeviceIntPtr /* dev */,
+ int /* type */,
+ GrabParameters* /* param */,
+ GrabMask* /* eventMask */);
+
extern int SelectForWindow(
DeviceIntPtr /* dev */,
WindowPtr /* pWin */,