dix: Rework Enter/Leave semaphore system.

Instead of a simple counter, use bits to keep track of which device is where
etc. When device enters a window (or sets focus), the bit matching the device
is set, when it leaves again, it is unset. If there are 0 bits set, then
Leave/Enter/Focus events may be sent to the client.

Same theory as before, but this should get around the insanity with
Grab/Ungrab special cases. Those cases are basically untested though.
This commit is contained in:
Peter Hutterer 2008-04-10 19:22:59 +09:30
parent a88386ee27
commit 04dff74ffd
5 changed files with 114 additions and 62 deletions

View File

@ -224,8 +224,7 @@ EnableDevice(DeviceIntPtr dev)
if (dev->spriteInfo->spriteOwner)
{
InitializeSprite(dev, WindowTable[0]);
((FocusSemaphoresPtr)dixLookupPrivate(&(WindowTable[0])->devPrivates,
FocusPrivatesKey))->enterleave++;
ENTER_LEAVE_SEMAPHORE_SET(WindowTable[0], dev);
}
else if ((other = NextFreePointerDevice()) == NULL)
{

View File

@ -4393,7 +4393,7 @@ EnterLeaveEvent(
GrabPtr grab = mouse->deviceGrab.grab;
GrabPtr devgrab = mouse->deviceGrab.grab;
Mask mask;
int* inWindow; /* no of sprites inside pWin */
int inWindow; /* zero if no sprites are in window */
Bool sendevent = FALSE;
deviceEnterNotify *devEnterLeave;
@ -4446,7 +4446,6 @@ EnterLeaveEvent(
IsParent(focus, pWin)))
event.u.enterLeave.flags |= ELFlagFocus;
inWindow = &((FocusSemaphoresPtr)dixLookupPrivate(&pWin->devPrivates, FocusPrivatesKey))->enterleave;
/*
* Sending multiple core enter/leave events to the same window confuse the
@ -4472,16 +4471,15 @@ EnterLeaveEvent(
* NotifyNonlinearVirtual to C and nothing to B.
*/
if (event.u.u.detail != NotifyVirtual &&
event.u.u.detail != NotifyNonlinearVirtual)
{
if (((*inWindow) == (LeaveNotify - type)))
sendevent = TRUE;
} else
{
if (!(*inWindow))
sendevent = TRUE;
}
/* Clear bit for device, but don't worry about SDs. */
if (mouse->isMaster && type == LeaveNotify &&
(mode != NotifyVirtual && mode != NotifyNonlinearVirtual))
ENTER_LEAVE_SEMAPHORE_UNSET(pWin, mouse);
inWindow = EnterLeaveSemaphoresIsset(pWin);
if (!inWindow)
sendevent = TRUE;
if ((mask & filters[mouse->id][type]) && sendevent)
{
@ -4493,6 +4491,10 @@ EnterLeaveEvent(
filters[mouse->id][type], NullGrab, 0);
}
if (mouse->isMaster && type == EnterNotify &&
(mode != NotifyVirtual && mode != NotifyNonlinearVirtual))
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;
@ -4582,25 +4584,6 @@ LeaveNotifies(DeviceIntPtr pDev,
}
}
/* welcome to insanity */
#define FOCUS_SEMAPHORE_MODIFY(win, field, mode, val) \
{ \
FocusSemaphoresPtr sem;\
sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey); \
if (mode != NotifyGrab && mode != NotifyUngrab) { \
sem->field += val; \
} else if (mode == NotifyUngrab) { \
if (sem->field == 0 && val > 0) \
sem->field += val; \
else if (sem->field == 1 && val < 0) \
sem->field += val; \
} \
}
#define ENTER_LEAVE_SEMAPHORE_UP(win, mode) \
FOCUS_SEMAPHORE_MODIFY(win, enterleave, mode, 1);
#define ENTER_LEAVE_SEMAPHORE_DOWN(win, mode) \
FOCUS_SEMAPHORE_MODIFY(win, enterleave, mode, -1);
/**
@ -4620,33 +4603,27 @@ DoEnterLeaveEvents(DeviceIntPtr pDev,
return;
if (IsParent(fromWin, toWin))
{
ENTER_LEAVE_SEMAPHORE_DOWN(fromWin, mode);
EnterLeaveEvent(pDev, LeaveNotify, mode, NotifyInferior, fromWin,
None);
EnterNotifies(pDev, fromWin, toWin, mode,
NotifyVirtual);
ENTER_LEAVE_SEMAPHORE_UP(toWin, mode);
EnterLeaveEvent(pDev, EnterNotify, mode, NotifyAncestor, toWin, None);
}
else if (IsParent(toWin, fromWin))
{
ENTER_LEAVE_SEMAPHORE_DOWN(fromWin, mode);
EnterLeaveEvent(pDev, LeaveNotify, mode, NotifyAncestor, fromWin,
None);
LeaveNotifies(pDev, fromWin, toWin, mode, NotifyVirtual);
ENTER_LEAVE_SEMAPHORE_UP(toWin, mode);
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 */
ENTER_LEAVE_SEMAPHORE_DOWN(fromWin, mode);
EnterLeaveEvent(pDev, LeaveNotify, mode, NotifyNonlinear, fromWin,
None);
LeaveNotifies(pDev, fromWin, common, mode, NotifyNonlinearVirtual);
EnterNotifies(pDev, common, toWin, mode, NotifyNonlinearVirtual);
ENTER_LEAVE_SEMAPHORE_UP(toWin, mode);
EnterLeaveEvent(pDev, EnterNotify, mode, NotifyNonlinear, toWin,
None);
}
@ -4656,7 +4633,7 @@ static void
FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
{
xEvent event;
int* numFoci; /* no of foci the window has already */
int numFoci; /* zero if no device has focus on window */
Bool sendevent = FALSE;
if (dev != inputInfo.keyboard)
@ -4690,25 +4667,18 @@ FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
* NotifyNonlinearVirtual to C and nothing to B.
*/
numFoci =
&((FocusSemaphoresPtr)dixLookupPrivate(&pWin->devPrivates,
FocusPrivatesKey))->focusinout;
if (mode == NotifyGrab || mode == NotifyUngrab)
if (dev->isMaster && type == FocusOut &&
(detail != NotifyVirtual &&
detail != NotifyNonlinearVirtual &&
detail != NotifyPointer &&
detail != NotifyPointerRoot &&
detail != NotifyDetailNone))
FOCUS_SEMAPHORE_UNSET(pWin, dev);
numFoci = FocusSemaphoresIsset(pWin);
if (!numFoci)
sendevent = TRUE;
else if (detail != NotifyVirtual &&
detail != NotifyNonlinearVirtual &&
detail != NotifyPointer &&
detail != NotifyPointerRoot &&
detail != NotifyDetailNone)
{
(type == FocusIn) ? (*numFoci)++ : (*numFoci)--;
if (((*numFoci) == (FocusOut - type)))
sendevent = TRUE;
} else
{
if (!(*numFoci))
sendevent = TRUE;
}
if (sendevent)
{
@ -4733,6 +4703,14 @@ FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
KeymapStateMask, NullGrab, 0);
}
}
if (dev->isMaster && type == FocusIn &&
(detail != NotifyVirtual &&
detail != NotifyNonlinearVirtual &&
detail != NotifyPointer &&
detail != NotifyPointerRoot &&
detail != NotifyDetailNone))
FOCUS_SEMAPHORE_SET(pWin, dev);
}
/*
@ -6616,3 +6594,37 @@ ExtGrabDevice(ClientPtr client,
return GrabSuccess;
}
/*
* @return Zero if no device is currently in window, non-zero otherwise.
*/
int
EnterLeaveSemaphoresIsset(WindowPtr win)
{
FocusSemaphoresPtr sem;
int set = 0;
int i;
sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey);
for (i = 0; i < (MAX_DEVICES + 7)/8; i++)
set += sem->enterleave[i];
return set;
}
/*
* @return Zero if no devices has focus on the window, non-zero otherwise.
*/
int
FocusSemaphoresIsset(WindowPtr win)
{
FocusSemaphoresPtr sem;
int set = 0;
int i;
sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey);
for (i = 0; i < (MAX_DEVICES + 7)/8; i++)
set += sem->focusinout[i];
return set;
}

View File

@ -366,6 +366,7 @@ CreateRootWindow(ScreenPtr pScreen)
WindowPtr pWin;
BoxRec box;
PixmapFormatRec *format;
FocusSemaphoresPtr sem;
pWin = (WindowPtr)xalloc(sizeof(WindowRec));
if (!pWin)
@ -484,6 +485,7 @@ CreateRootWindow(ScreenPtr pScreen)
if (disableSaveUnders)
pScreen->saveUnderSupport = NotUseful;
return TRUE;
}

View File

@ -80,6 +80,39 @@ SOFTWARE.
#define RevertToFollowKeyboard 3
#endif
/* Used for enter/leave and focus in/out semaphores */
#define SEMAPHORE_FIELD_SET(win, dev, field) \
{ \
FocusSemaphoresPtr sem; \
sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey); \
sem->field[dev->id/8] |= (1 << (dev->id % 8)); \
}
#define SEMAPHORE_FIELD_UNSET(win, dev, field) \
{ \
FocusSemaphoresPtr sem; \
sem = (FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey); \
sem->field[dev->id/8] &= ~(1 << (dev->id % 8)); \
}
#define ENTER_LEAVE_SEMAPHORE_SET(win, dev) \
SEMAPHORE_FIELD_SET(win, dev, enterleave);
#define ENTER_LEAVE_SEMAPHORE_UNSET(win, dev) \
SEMAPHORE_FIELD_UNSET(win, dev, enterleave);
#define ENTER_LEAVE_SEMAPHORE_ISSET(win, dev) \
((FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey))->enterleave[dev->id/8] & (1 << (dev->id % 8))
#define FOCUS_SEMAPHORE_SET(win, dev) \
SEMAPHORE_FIELD_SET(win, dev, focusinout);
#define FOCUS_SEMAPHORE_UNSET(win, dev) \
SEMAPHORE_FIELD_UNSET(win, dev, focusinout);
#define FOCUS_SEMAPHORE_ISSET(win, dev) \
((FocusSemaphoresPtr)dixLookupPrivate(&win->devPrivates, FocusPrivatesKey))->focusinout[dev->id/8] & (1 << (dev->id % 8))
typedef unsigned long Leds;
typedef struct _OtherClients *OtherClientsPtr;
typedef struct _InputClients *InputClientsPtr;
@ -488,6 +521,8 @@ extern void DeepCopyDeviceClasses(DeviceIntPtr from,
extern void FreeDeviceClass(int type, pointer* class);
extern void FreeFeedbackClass(int type, pointer* class);
extern void FreeAllDeviceClasses(ClassesPtr classes);
extern int EnterLeaveSemaphoresIsset(WindowPtr win);
extern int FocusSemaphoresIsset(WindowPtr win);
/* Window/device based access control */
extern Bool ACRegisterClient(ClientPtr client);

View File

@ -59,6 +59,7 @@ SOFTWARE.
#include "miscstruct.h"
#include <X11/Xprotostr.h>
#include "opaque.h"
#include "inputstr.h"
#define GuaranteeNothing 0
#define GuaranteeVisBack 1
@ -257,11 +258,14 @@ extern ScreenSaverStuffRec savedScreenInfo[MAXSCREENS];
extern DevPrivateKey FocusPrivatesKey;
/* Used to maintain semantics of core protocol for Enter/LeaveNotifies and
* FocusIn/Out events for multiple pointers/keyboards.
*/
* FocusIn/Out events for multiple pointers/keyboards.
*
* Each device ID corresponds to one bit. If set, the device is in the
* window/has focus.
*/
typedef struct _FocusSemaphores {
int enterleave;
int focusinout;
char enterleave[(MAX_DEVICES + 7)/8];
char focusinout[(MAX_DEVICES + 7)/8];
} FocusSemaphoresRec, *FocusSemaphoresPtr;
/*