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:
parent
5e48f5e2dd
commit
6bdc963cda
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <X11/X.h>
|
#include <X11/X.h>
|
||||||
#include "windowstr.h"
|
#include "windowstr.h"
|
||||||
|
#include "exglobals.h"
|
||||||
#include "enterleave.h"
|
#include "enterleave.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,46 +48,57 @@ CommonAncestor(
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send enter notifies to all parent windows up to ancestor.
|
* Send enter notifies to all windows between @ancestor and @child (excluding
|
||||||
* This function recurses.
|
* 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
|
static void
|
||||||
EnterNotifies(DeviceIntPtr pDev,
|
EnterNotifies(DeviceIntPtr dev,
|
||||||
WindowPtr ancestor,
|
WindowPtr ancestor,
|
||||||
WindowPtr child,
|
WindowPtr child,
|
||||||
int mode,
|
int mode,
|
||||||
int detail)
|
int detail,
|
||||||
|
BOOL core)
|
||||||
{
|
{
|
||||||
WindowPtr parent = child->parent;
|
WindowPtr parent = child->parent;
|
||||||
|
|
||||||
if (ancestor == parent)
|
if (ancestor == parent)
|
||||||
return;
|
return;
|
||||||
EnterNotifies(pDev, ancestor, parent, mode, detail);
|
EnterNotifies(dev, ancestor, parent, mode, detail, core);
|
||||||
EnterLeaveEvent(pDev, EnterNotify, mode, detail, parent,
|
if (core)
|
||||||
|
CoreEnterLeaveEvent(dev, EnterNotify, mode, detail, parent,
|
||||||
|
child->drawable.id);
|
||||||
|
else
|
||||||
|
DeviceEnterLeaveEvent(dev, DeviceEnterNotify, mode, detail, parent,
|
||||||
child->drawable.id);
|
child->drawable.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send leave notifies to all parent windows up to ancestor.
|
* Send leave notifies to all windows between @child and @ancestor.
|
||||||
* This function recurses.
|
* Events are sent running up the hierarchy.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
LeaveNotifies(DeviceIntPtr pDev,
|
LeaveNotifies(DeviceIntPtr dev,
|
||||||
WindowPtr child,
|
WindowPtr child,
|
||||||
WindowPtr ancestor,
|
WindowPtr ancestor,
|
||||||
int mode,
|
int mode,
|
||||||
int detail)
|
int detail,
|
||||||
|
BOOL core)
|
||||||
{
|
{
|
||||||
WindowPtr pWin;
|
WindowPtr win;
|
||||||
|
|
||||||
if (ancestor == child)
|
if (ancestor == child)
|
||||||
return;
|
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->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)
|
if (fromWin == toWin)
|
||||||
return;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -50,4 +50,17 @@ extern WindowPtr CommonAncestor(
|
||||||
WindowPtr a,
|
WindowPtr a,
|
||||||
WindowPtr b);
|
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_ */
|
#endif /* _ENTERLEAVE_H_ */
|
||||||
|
|
153
dix/events.c
153
dix/events.c
|
@ -4184,7 +4184,7 @@ EventSuppressForWindow(WindowPtr pWin, ClientPtr client,
|
||||||
* Uses the paired keyboard to get some additional information.
|
* Uses the paired keyboard to get some additional information.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
EnterLeaveEvent(
|
CoreEnterLeaveEvent(
|
||||||
DeviceIntPtr mouse,
|
DeviceIntPtr mouse,
|
||||||
int type,
|
int type,
|
||||||
int mode,
|
int mode,
|
||||||
|
@ -4197,12 +4197,6 @@ EnterLeaveEvent(
|
||||||
DeviceIntPtr keybd;
|
DeviceIntPtr keybd;
|
||||||
GrabPtr grab = mouse->deviceGrab.grab;
|
GrabPtr grab = mouse->deviceGrab.grab;
|
||||||
Mask mask;
|
Mask mask;
|
||||||
int inWindow; /* zero if no sprites are in window */
|
|
||||||
Bool sendevent = FALSE;
|
|
||||||
|
|
||||||
deviceEnterNotify *devEnterLeave;
|
|
||||||
int mskidx;
|
|
||||||
OtherInputMasks *inputMasks;
|
|
||||||
|
|
||||||
keybd = GetPairedDevice(mouse);
|
keybd = GetPairedDevice(mouse);
|
||||||
|
|
||||||
|
@ -4250,44 +4244,7 @@ EnterLeaveEvent(
|
||||||
IsParent(focus, pWin)))
|
IsParent(focus, pWin)))
|
||||||
event.u.enterLeave.flags |= ELFlagFocus;
|
event.u.enterLeave.flags |= ELFlagFocus;
|
||||||
|
|
||||||
|
if ((mask & filters[mouse->id][type]))
|
||||||
/*
|
|
||||||
* 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 (grab)
|
if (grab)
|
||||||
TryClientEvents(rClient(grab), mouse, &event, 1, mask,
|
TryClientEvents(rClient(grab), mouse, &event, 1, mask,
|
||||||
|
@ -4297,35 +4254,6 @@ EnterLeaveEvent(
|
||||||
filters[mouse->id][type], NullGrab, 0);
|
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))
|
if ((type == EnterNotify) && (mask & KeymapStateMask))
|
||||||
{
|
{
|
||||||
xKeymapEvent ke;
|
xKeymapEvent ke;
|
||||||
|
@ -4338,14 +4266,87 @@ EnterLeaveEvent(
|
||||||
|
|
||||||
ke.type = KeymapNotify;
|
ke.type = KeymapNotify;
|
||||||
if (grab)
|
if (grab)
|
||||||
(void)TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1,
|
TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1,
|
||||||
mask, KeymapStateMask, grab);
|
mask, KeymapStateMask, grab);
|
||||||
else
|
else
|
||||||
(void)DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1,
|
DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1,
|
||||||
KeymapStateMask, NullGrab, 0);
|
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
|
static void
|
||||||
FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
|
FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue