dix: split enter/leave event handling into core and device handling.

Device events always need to be delivered, core events only in some cases.
Let's keep them completely separate so we can adjust core event delivery.

Signed-off-by: Peter Hutterer <peter.hutterer@redhat.com>
This commit is contained in:
Peter Hutterer 2008-11-14 15:37:35 +10:00
parent 5e48f5e2dd
commit 6bdc963cda
3 changed files with 125 additions and 123 deletions

View File

@ -30,6 +30,7 @@
#include <X11/X.h>
#include "windowstr.h"
#include "exglobals.h"
#include "enterleave.h"
/**
@ -47,46 +48,57 @@ CommonAncestor(
/**
* Send enter notifies to all parent windows up to ancestor.
* This function recurses.
* Send enter notifies to all windows between @ancestor and @child (excluding
* both). Events are sent running up the window hierarchy. This function
* recurses.
* If @core is TRUE, core events are sent, otherwise XI events will be sent.
*/
static void
EnterNotifies(DeviceIntPtr pDev,
EnterNotifies(DeviceIntPtr dev,
WindowPtr ancestor,
WindowPtr child,
int mode,
int detail)
int detail,
BOOL core)
{
WindowPtr parent = child->parent;
if (ancestor == parent)
return;
EnterNotifies(pDev, ancestor, parent, mode, detail);
EnterLeaveEvent(pDev, EnterNotify, mode, detail, parent,
EnterNotifies(dev, ancestor, parent, mode, detail, core);
if (core)
CoreEnterLeaveEvent(dev, EnterNotify, mode, detail, parent,
child->drawable.id);
else
DeviceEnterLeaveEvent(dev, DeviceEnterNotify, mode, detail, parent,
child->drawable.id);
}
/**
* Send leave notifies to all parent windows up to ancestor.
* This function recurses.
* Send leave notifies to all windows between @child and @ancestor.
* Events are sent running up the hierarchy.
*/
static void
LeaveNotifies(DeviceIntPtr pDev,
LeaveNotifies(DeviceIntPtr dev,
WindowPtr child,
WindowPtr ancestor,
int mode,
int detail)
int detail,
BOOL core)
{
WindowPtr pWin;
WindowPtr win;
if (ancestor == child)
return;
for (pWin = child->parent; pWin != ancestor; pWin = pWin->parent)
for (win = child->parent; win != ancestor; win = win->parent)
{
EnterLeaveEvent(pDev, LeaveNotify, mode, detail, pWin,
if (core)
CoreEnterLeaveEvent(dev, LeaveNotify, mode, detail, win,
child->drawable.id);
child = pWin;
else
DeviceEnterLeaveEvent(dev, DeviceLeaveNotify, mode, detail, win,
child->drawable.id);
child = win;
}
}
@ -108,31 +120,7 @@ DoEnterLeaveEvents(DeviceIntPtr pDev,
if (fromWin == toWin)
return;
if (IsParent(fromWin, toWin))
{
EnterLeaveEvent(pDev, LeaveNotify, mode, NotifyInferior, fromWin,
None);
EnterNotifies(pDev, fromWin, toWin, mode,
NotifyVirtual);
EnterLeaveEvent(pDev, EnterNotify, mode, NotifyAncestor, toWin, None);
}
else if (IsParent(toWin, fromWin))
{
EnterLeaveEvent(pDev, LeaveNotify, mode, NotifyAncestor, fromWin,
None);
LeaveNotifies(pDev, fromWin, toWin, mode, NotifyVirtual);
EnterLeaveEvent(pDev, EnterNotify, mode, NotifyInferior, toWin, None);
}
else
{ /* neither fromWin nor toWin is descendent of the other */
WindowPtr common = CommonAncestor(toWin, fromWin);
/* common == NullWindow ==> different screens */
EnterLeaveEvent(pDev, LeaveNotify, mode, NotifyNonlinear, fromWin,
None);
LeaveNotifies(pDev, fromWin, common, mode, NotifyNonlinearVirtual);
EnterNotifies(pDev, common, toWin, mode, NotifyNonlinearVirtual);
EnterLeaveEvent(pDev, EnterNotify, mode, NotifyNonlinear, toWin,
None);
}
}
CoreEnterLeaveEvents(pDev, fromWin, toWin, mode);
DeviceEnterLeaveEvents(pDev, fromWin, toWin, mode);
}

View File

@ -50,4 +50,17 @@ extern WindowPtr CommonAncestor(
WindowPtr a,
WindowPtr b);
extern void CoreEnterLeaveEvent(DeviceIntPtr mouse,
int type,
int mode,
int detail,
WindowPtr pWin,
Window child);
extern void DeviceEnterLeaveEvent(DeviceIntPtr mouse,
int type,
int mode,
int detail,
WindowPtr pWin,
Window child);
#endif /* _ENTERLEAVE_H_ */

View File

@ -4184,7 +4184,7 @@ EventSuppressForWindow(WindowPtr pWin, ClientPtr client,
* Uses the paired keyboard to get some additional information.
*/
void
EnterLeaveEvent(
CoreEnterLeaveEvent(
DeviceIntPtr mouse,
int type,
int mode,
@ -4197,12 +4197,6 @@ EnterLeaveEvent(
DeviceIntPtr keybd;
GrabPtr grab = mouse->deviceGrab.grab;
Mask mask;
int inWindow; /* zero if no sprites are in window */
Bool sendevent = FALSE;
deviceEnterNotify *devEnterLeave;
int mskidx;
OtherInputMasks *inputMasks;
keybd = GetPairedDevice(mouse);
@ -4250,44 +4244,7 @@ EnterLeaveEvent(
IsParent(focus, pWin)))
event.u.enterLeave.flags |= ELFlagFocus;
/*
* Sending multiple core enter/leave events to the same window confuse the
* client.
* We can send multiple events that have detail NotifyVirtual or
* NotifyNonlinearVirtual however. For most clients anyway.
*
* For standard events (NotifyAncestor, NotifyInferior, NotifyNonlinear)
* we only send an enter event for the first pointer to enter. A leave
* event is sent for the last pointer to leave.
*
* For events with Virtual detail, we send them only to a window that does
* not have a pointer inside.
*
* For a window tree in the form of
*
* A -> Bp -> C -> D
* \ (where B and E have pointers)
* -> Ep
*
* If the pointer moves from E into D, a LeaveNotify is sent to E, an
* EnterNotify is sent to D, an EnterNotify with detail
* NotifyNonlinearVirtual to C and nothing to B.
*/
/* Clear bit for device, but don't worry about SDs. */
if (mouse->isMaster && type == LeaveNotify &&
(detail != NotifyVirtual && detail != NotifyNonlinearVirtual))
if (mode != NotifyUngrab)
ENTER_LEAVE_SEMAPHORE_UNSET(pWin, mouse);
inWindow = EnterLeaveSemaphoresIsset(pWin);
if(!inWindow || mode == NotifyGrab || mode == NotifyUngrab)
sendevent = TRUE;
if ((mask & filters[mouse->id][type]) && sendevent)
if ((mask & filters[mouse->id][type]))
{
if (grab)
TryClientEvents(rClient(grab), mouse, &event, 1, mask,
@ -4297,35 +4254,6 @@ EnterLeaveEvent(
filters[mouse->id][type], NullGrab, 0);
}
if (mouse->isMaster && type == EnterNotify &&
(detail != NotifyVirtual && detail != NotifyNonlinearVirtual))
if (mode != NotifyGrab)
ENTER_LEAVE_SEMAPHORE_SET(pWin, mouse);
/* we don't have enough bytes, so we squash flags and mode into
one byte, and use the last byte for the deviceid. */
devEnterLeave = (deviceEnterNotify*)&event;
devEnterLeave->type = (type == EnterNotify) ? DeviceEnterNotify :
DeviceLeaveNotify;
devEnterLeave->mode |= (event.u.enterLeave.flags << 4);
devEnterLeave->deviceid = mouse->id;
mskidx = mouse->id;
inputMasks = wOtherInputMasks(pWin);
if (inputMasks &&
(filters[mouse->id][devEnterLeave->type] &
inputMasks->deliverableEvents[mskidx]))
{
if (grab)
(void)TryClientEvents(rClient(grab), mouse,
(xEvent*)devEnterLeave, 1,
mask, filters[mouse->id][devEnterLeave->type],
grab);
else
(void)DeliverEventsToWindow(mouse, pWin, (xEvent*)devEnterLeave,
1, filters[mouse->id][devEnterLeave->type],
NullGrab, mouse->id);
}
if ((type == EnterNotify) && (mask & KeymapStateMask))
{
xKeymapEvent ke;
@ -4338,14 +4266,87 @@ EnterLeaveEvent(
ke.type = KeymapNotify;
if (grab)
(void)TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1,
TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1,
mask, KeymapStateMask, grab);
else
(void)DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1,
DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1,
KeymapStateMask, NullGrab, 0);
}
}
void
DeviceEnterLeaveEvent(
DeviceIntPtr mouse,
int type,
int mode,
int detail,
WindowPtr pWin,
Window child)
{
xEvent event;
GrabPtr grab = mouse->deviceGrab.grab;
deviceEnterNotify *devEnterLeave;
int mskidx;
OtherInputMasks *inputMasks;
Mask mask;
DeviceIntPtr keybd = GetPairedDevice(mouse);
BOOL sameScreen;
if (grab) {
mask = (pWin == grab->window) ? grab->eventMask : 0;
if (grab->ownerEvents)
mask |= EventMaskForClient(pWin, rClient(grab));
} else {
mask = pWin->eventMask | wOtherEventMasks(pWin);
}
/* we don't have enough bytes, so we squash flags and mode into
one byte, and use the last byte for the deviceid. */
devEnterLeave = (deviceEnterNotify*)&event;
devEnterLeave->detail = detail;
devEnterLeave->time = currentTime.milliseconds;
devEnterLeave->rootX = mouse->spriteInfo->sprite->hot.x;
devEnterLeave->rootY = mouse->spriteInfo->sprite->hot.y;
FixUpEventFromWindow(mouse, &event, pWin, None, FALSE);
sameScreen = event.u.keyButtonPointer.sameScreen;
devEnterLeave->child = child;
devEnterLeave->type = type;
devEnterLeave->deviceid = mouse->id;
devEnterLeave->mode = mode;
devEnterLeave->mode |= (sameScreen ? (ELFlagSameScreen << 4) : 0);
#ifdef XKB
if (!noXkbExtension) {
devEnterLeave->state = mouse->button->state & 0x1f00;
if (keybd)
devEnterLeave->state |=
XkbGrabStateFromRec(&keybd->key->xkbInfo->state);
} else
#endif
{
devEnterLeave->state = (keybd) ? keybd->key->state : 0;
devEnterLeave->state |= mouse->button->state;
}
mskidx = mouse->id;
inputMasks = wOtherInputMasks(pWin);
if (inputMasks &&
(filters[mouse->id][devEnterLeave->type] &
inputMasks->deliverableEvents[mskidx]))
{
if (grab)
TryClientEvents(rClient(grab), mouse,
(xEvent*)devEnterLeave, 1, mask,
filters[mouse->id][devEnterLeave->type], grab);
else
DeliverEventsToWindow(mouse, pWin, (xEvent*)devEnterLeave, 1,
filters[mouse->id][devEnterLeave->type],
NullGrab, mouse->id);
}
}
static void
FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
{