3436 lines
109 KiB
C
3436 lines
109 KiB
C
|
/************************************************************
|
||
|
|
||
|
Copyright 1987, 1998 The Open Group
|
||
|
|
||
|
Permission to use, copy, modify, distribute, and sell this software and its
|
||
|
documentation for any purpose is hereby granted without fee, provided that
|
||
|
the above copyright notice appear in all copies and that both that
|
||
|
copyright notice and this permission notice appear in supporting
|
||
|
documentation.
|
||
|
|
||
|
The above copyright notice and this permission notice shall be included in
|
||
|
all copies or substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
|
||
|
Except as contained in this notice, the name of The Open Group shall not be
|
||
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||
|
in this Software without prior written authorization from The Open Group.
|
||
|
|
||
|
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
|
||
|
|
||
|
All Rights Reserved
|
||
|
|
||
|
Permission to use, copy, modify, and distribute this software and its
|
||
|
documentation for any purpose and without fee is hereby granted,
|
||
|
provided that the above copyright notice appear in all copies and that
|
||
|
both that copyright notice and this permission notice appear in
|
||
|
supporting documentation, and that the name of Digital not be
|
||
|
used in advertising or publicity pertaining to distribution of the
|
||
|
software without specific, written prior permission.
|
||
|
|
||
|
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
||
|
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
||
|
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
||
|
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||
|
SOFTWARE.
|
||
|
|
||
|
********************************************************/
|
||
|
|
||
|
/* The panoramix components contained the following notice */
|
||
|
/*****************************************************************
|
||
|
|
||
|
Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
of this software and associated documentation files (the "Software"), to deal
|
||
|
in the Software without restriction, including without limitation the rights
|
||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
copies of the Software.
|
||
|
|
||
|
The above copyright notice and this permission notice shall be included in
|
||
|
all copies or substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
|
||
|
BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
|
||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
|
||
|
Except as contained in this notice, the name of Digital Equipment Corporation
|
||
|
shall not be used in advertising or otherwise to promote the sale, use or other
|
||
|
dealings in this Software without prior written authorization from Digital
|
||
|
Equipment Corporation.
|
||
|
|
||
|
******************************************************************/
|
||
|
|
||
|
/*****************************************************************
|
||
|
|
||
|
Copyright 2003-2005 Sun Microsystems, Inc.
|
||
|
|
||
|
All rights reserved.
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
copy of this software and associated documentation files (the
|
||
|
"Software"), to deal in the Software without restriction, including
|
||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||
|
distribute, and/or sell copies of the Software, and to permit persons
|
||
|
to whom the Software is furnished to do so, provided that the above
|
||
|
copyright notice(s) and this permission notice appear in all copies of
|
||
|
the Software and that both the above copyright notice(s) and this
|
||
|
permission notice appear in supporting documentation.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||
|
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||
|
HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
|
||
|
INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
|
||
|
FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||
|
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||
|
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
|
||
|
Except as contained in this notice, the name of a copyright holder
|
||
|
shall not be used in advertising or otherwise to promote the sale, use
|
||
|
or other dealings in this Software without prior written authorization
|
||
|
of the copyright holder.
|
||
|
|
||
|
******************************************************************/
|
||
|
|
||
|
#ifdef HAVE_DIX_CONFIG_H
|
||
|
#include <dix-config.h>
|
||
|
#endif
|
||
|
|
||
|
#include <X11/X.h>
|
||
|
#include "misc.h"
|
||
|
#include "resource.h"
|
||
|
#include <X11/Xproto.h>
|
||
|
#include "windowstr.h"
|
||
|
#include "inputstr.h"
|
||
|
#include "scrnintstr.h"
|
||
|
#include "cursorstr.h"
|
||
|
|
||
|
#include "dixstruct.h"
|
||
|
#include "globals.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#include <X11/extensions/XIproto.h>
|
||
|
#include "exevents.h"
|
||
|
#include "extnsionst.h"
|
||
|
|
||
|
#include "dixevents.h"
|
||
|
#include "dixgrabs.h"
|
||
|
#include "dispatch.h"
|
||
|
|
||
|
#define EXTENSION_EVENT_BASE 64
|
||
|
|
||
|
#define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */
|
||
|
#define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask )
|
||
|
#define AllButtonsMask ( \
|
||
|
Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )
|
||
|
#define MotionMask ( \
|
||
|
PointerMotionMask | Button1MotionMask | \
|
||
|
Button2MotionMask | Button3MotionMask | Button4MotionMask | \
|
||
|
Button5MotionMask | ButtonMotionMask )
|
||
|
#define PropagateMask ( \
|
||
|
KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \
|
||
|
MotionMask )
|
||
|
#define PointerGrabMask ( \
|
||
|
ButtonPressMask | ButtonReleaseMask | \
|
||
|
EnterWindowMask | LeaveWindowMask | \
|
||
|
PointerMotionHintMask | KeymapStateMask | \
|
||
|
MotionMask )
|
||
|
#define AllModifiersMask ( \
|
||
|
ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \
|
||
|
Mod3Mask | Mod4Mask | Mod5Mask )
|
||
|
#define AllEventMasks (lastEventMask|(lastEventMask-1))
|
||
|
/*
|
||
|
* The following relies on the fact that the Button<n>MotionMasks are equal
|
||
|
* to the corresponding Button<n>Masks from the current modifier/button state.
|
||
|
*/
|
||
|
#define Motion_Filter(class) (PointerMotionMask | \
|
||
|
(class)->state | (class)->motionMask)
|
||
|
|
||
|
#define WID(w) ((w) ? ((w)->drawable.id) : 0)
|
||
|
|
||
|
#define XE_KBPTR (xE->u.keyButtonPointer)
|
||
|
|
||
|
#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
|
||
|
|
||
|
_X_EXPORT CallbackListPtr EventCallback;
|
||
|
|
||
|
_X_EXPORT CallbackListPtr DeviceEventCallback;
|
||
|
|
||
|
#define DNPMCOUNT 8
|
||
|
|
||
|
Mask DontPropagateMasks[DNPMCOUNT];
|
||
|
|
||
|
static int DontPropagateRefCnts[DNPMCOUNT];
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
static debug_events = 0;
|
||
|
#endif
|
||
|
_X_EXPORT InputInfo inputInfo;
|
||
|
|
||
|
static struct {
|
||
|
QdEventPtr pending, *pendtail;
|
||
|
DeviceIntPtr replayDev; /* kludgy rock to put flag for */
|
||
|
WindowPtr replayWin; /* ComputeFreezes */
|
||
|
Bool playingEvents;
|
||
|
TimeStamp time;
|
||
|
} syncEvents;
|
||
|
|
||
|
/*
|
||
|
* The window trace information is used to avoid having to compute all the
|
||
|
* windows between the root and the current pointer window each time a button
|
||
|
* or key goes down. The grabs on each of those windows must be checked.
|
||
|
*/
|
||
|
static WindowPtr *spriteTrace = (WindowPtr *) NULL;
|
||
|
|
||
|
#define ROOT spriteTrace[0]
|
||
|
static int spriteTraceSize = 0;
|
||
|
|
||
|
static int spriteTraceGood;
|
||
|
|
||
|
static struct {
|
||
|
CursorPtr current;
|
||
|
BoxRec hotLimits; /* logical constraints of hot spot */
|
||
|
Bool confined; /* confined to screen */
|
||
|
RegionPtr hotShape; /* additional logical shape constraint */
|
||
|
BoxRec physLimits; /* physical constraints of hot spot */
|
||
|
WindowPtr win; /* window of logical position */
|
||
|
HotSpot hot; /* logical pointer position */
|
||
|
HotSpot hotPhys; /* physical pointer position */
|
||
|
} sprite; /* info about the cursor sprite */
|
||
|
|
||
|
|
||
|
static void DoEnterLeaveEvents(WindowPtr fromWin, WindowPtr toWin, int mode);
|
||
|
|
||
|
static WindowPtr XYToWindow(int x, int y);
|
||
|
|
||
|
extern int lastEvent;
|
||
|
|
||
|
static Mask lastEventMask;
|
||
|
|
||
|
|
||
|
#define CantBeFiltered NoEventMask
|
||
|
static Mask filters[128];
|
||
|
|
||
|
static const Mask initialFilters[128] = {
|
||
|
NoSuchEvent, /* 0 */
|
||
|
NoSuchEvent, /* 1 */
|
||
|
KeyPressMask, /* KeyPress */
|
||
|
KeyReleaseMask, /* KeyRelease */
|
||
|
ButtonPressMask, /* ButtonPress */
|
||
|
ButtonReleaseMask, /* ButtonRelease */
|
||
|
PointerMotionMask, /* MotionNotify (initial state) */
|
||
|
EnterWindowMask, /* EnterNotify */
|
||
|
LeaveWindowMask, /* LeaveNotify */
|
||
|
FocusChangeMask, /* FocusIn */
|
||
|
FocusChangeMask, /* FocusOut */
|
||
|
KeymapStateMask, /* KeymapNotify */
|
||
|
ExposureMask, /* Expose */
|
||
|
CantBeFiltered, /* GraphicsExpose */
|
||
|
CantBeFiltered, /* NoExpose */
|
||
|
VisibilityChangeMask, /* VisibilityNotify */
|
||
|
SubstructureNotifyMask, /* CreateNotify */
|
||
|
StructureAndSubMask, /* DestroyNotify */
|
||
|
StructureAndSubMask, /* UnmapNotify */
|
||
|
StructureAndSubMask, /* MapNotify */
|
||
|
SubstructureRedirectMask, /* MapRequest */
|
||
|
StructureAndSubMask, /* ReparentNotify */
|
||
|
StructureAndSubMask, /* ConfigureNotify */
|
||
|
SubstructureRedirectMask, /* ConfigureRequest */
|
||
|
StructureAndSubMask, /* GravityNotify */
|
||
|
ResizeRedirectMask, /* ResizeRequest */
|
||
|
StructureAndSubMask, /* CirculateNotify */
|
||
|
SubstructureRedirectMask, /* CirculateRequest */
|
||
|
PropertyChangeMask, /* PropertyNotify */
|
||
|
CantBeFiltered, /* SelectionClear */
|
||
|
CantBeFiltered, /* SelectionRequest */
|
||
|
CantBeFiltered, /* SelectionNotify */
|
||
|
ColormapChangeMask, /* ColormapNotify */
|
||
|
CantBeFiltered, /* ClientMessage */
|
||
|
CantBeFiltered /* MappingNotify */
|
||
|
};
|
||
|
|
||
|
static CARD8 criticalEvents[32] = {
|
||
|
0x7c /* key and button events */
|
||
|
};
|
||
|
|
||
|
|
||
|
void
|
||
|
SetMaskForEvent(Mask mask, int event)
|
||
|
{
|
||
|
if ((event < LASTEvent) || (event >= 128))
|
||
|
FatalError("SetMaskForEvent: bogus event number");
|
||
|
filters[event] = mask;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
SetCriticalEvent(int event)
|
||
|
{
|
||
|
if (event >= 128)
|
||
|
FatalError("SetCriticalEvent: bogus event number");
|
||
|
criticalEvents[event >> 3] |= 1 << (event & 7);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
SyntheticMotion(int x, int y)
|
||
|
{
|
||
|
xEvent xE;
|
||
|
|
||
|
xE.u.keyButtonPointer.rootX = x;
|
||
|
xE.u.keyButtonPointer.rootY = y;
|
||
|
if (syncEvents.playingEvents)
|
||
|
xE.u.keyButtonPointer.time = syncEvents.time.milliseconds;
|
||
|
else
|
||
|
xE.u.keyButtonPointer.time = currentTime.milliseconds;
|
||
|
xE.u.u.type = MotionNotify;
|
||
|
(*inputInfo.pointer->public.processInputProc) (&xE, inputInfo.pointer, 1);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ConfineToShape(RegionPtr shape, int *px, int *py)
|
||
|
{
|
||
|
BoxRec box;
|
||
|
|
||
|
int x = *px, y = *py;
|
||
|
|
||
|
int incx = 1, incy = 1;
|
||
|
|
||
|
if (POINT_IN_REGION(shape, x, y, &box))
|
||
|
return;
|
||
|
box = *REGION_EXTENTS(shape);
|
||
|
/* this is rather crude */
|
||
|
do {
|
||
|
x += incx;
|
||
|
if (x >= box.x2) {
|
||
|
incx = -1;
|
||
|
x = *px - 1;
|
||
|
}
|
||
|
else if (x < box.x1) {
|
||
|
incx = 1;
|
||
|
x = *px;
|
||
|
y += incy;
|
||
|
if (y >= box.y2) {
|
||
|
incy = -1;
|
||
|
y = *py - 1;
|
||
|
}
|
||
|
else if (y < box.y1)
|
||
|
return; /* should never get here! */
|
||
|
}
|
||
|
} while (!POINT_IN_REGION(shape, x, y, &box));
|
||
|
*px = x;
|
||
|
*py = y;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
CheckPhysLimits(CursorPtr cursor,
|
||
|
Bool generateEvents, Bool confineToScreen, ScreenPtr pScreen)
|
||
|
{
|
||
|
HotSpot new;
|
||
|
|
||
|
if (!cursor)
|
||
|
return;
|
||
|
new = sprite.hotPhys;
|
||
|
if (pScreen)
|
||
|
new.pScreen = pScreen;
|
||
|
else
|
||
|
pScreen = new.pScreen;
|
||
|
(*pScreen->CursorLimits) (pScreen, cursor, &sprite.hotLimits,
|
||
|
&sprite.physLimits);
|
||
|
sprite.confined = confineToScreen;
|
||
|
(*pScreen->ConstrainCursor) (pScreen, &sprite.physLimits);
|
||
|
if (new.x < sprite.physLimits.x1)
|
||
|
new.x = sprite.physLimits.x1;
|
||
|
else if (new.x >= sprite.physLimits.x2)
|
||
|
new.x = sprite.physLimits.x2 - 1;
|
||
|
if (new.y < sprite.physLimits.y1)
|
||
|
new.y = sprite.physLimits.y1;
|
||
|
else if (new.y >= sprite.physLimits.y2)
|
||
|
new.y = sprite.physLimits.y2 - 1;
|
||
|
if (sprite.hotShape)
|
||
|
ConfineToShape(sprite.hotShape, &new.x, &new.y);
|
||
|
if ((pScreen != sprite.hotPhys.pScreen) ||
|
||
|
(new.x != sprite.hotPhys.x) || (new.y != sprite.hotPhys.y)) {
|
||
|
if (pScreen != sprite.hotPhys.pScreen)
|
||
|
sprite.hotPhys = new;
|
||
|
(*pScreen->SetCursorPosition) (pScreen, new.x, new.y, generateEvents);
|
||
|
if (!generateEvents)
|
||
|
SyntheticMotion(new.x, new.y);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
CheckVirtualMotion(register QdEventPtr qe, register WindowPtr pWin)
|
||
|
{
|
||
|
if (qe) {
|
||
|
sprite.hot.pScreen = qe->pScreen;
|
||
|
sprite.hot.x = qe->event->u.keyButtonPointer.rootX;
|
||
|
sprite.hot.y = qe->event->u.keyButtonPointer.rootY;
|
||
|
pWin = inputInfo.pointer->grab ? inputInfo.pointer->grab->confineTo :
|
||
|
NullWindow;
|
||
|
}
|
||
|
if (pWin) {
|
||
|
BoxRec lims;
|
||
|
|
||
|
if (sprite.hot.pScreen != pWin->drawable.pScreen) {
|
||
|
sprite.hot.pScreen = pWin->drawable.pScreen;
|
||
|
sprite.hot.x = sprite.hot.y = 0;
|
||
|
}
|
||
|
lims = *REGION_EXTENTS(&pWin->borderSize);
|
||
|
if (sprite.hot.x < lims.x1)
|
||
|
sprite.hot.x = lims.x1;
|
||
|
else if (sprite.hot.x >= lims.x2)
|
||
|
sprite.hot.x = lims.x2 - 1;
|
||
|
if (sprite.hot.y < lims.y1)
|
||
|
sprite.hot.y = lims.y1;
|
||
|
else if (sprite.hot.y >= lims.y2)
|
||
|
sprite.hot.y = lims.y2 - 1;
|
||
|
if (wBoundingShape(pWin))
|
||
|
ConfineToShape(&pWin->borderSize, &sprite.hot.x, &sprite.hot.y);
|
||
|
if (qe) {
|
||
|
qe->pScreen = sprite.hot.pScreen;
|
||
|
qe->event->u.keyButtonPointer.rootX = sprite.hot.x;
|
||
|
qe->event->u.keyButtonPointer.rootY = sprite.hot.y;
|
||
|
}
|
||
|
}
|
||
|
ROOT = WindowTable[sprite.hot.pScreen->myNum];
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ConfineCursorToWindow(WindowPtr pWin, Bool generateEvents, Bool confineToScreen)
|
||
|
{
|
||
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
||
|
|
||
|
|
||
|
if (syncEvents.playingEvents) {
|
||
|
CheckVirtualMotion((QdEventPtr) NULL, pWin);
|
||
|
SyntheticMotion(sprite.hot.x, sprite.hot.y);
|
||
|
}
|
||
|
else {
|
||
|
sprite.hotLimits = *REGION_EXTENTS(&pWin->borderSize);
|
||
|
sprite.hotShape = wBoundingShape(pWin) ? &pWin->borderSize : NullRegion;
|
||
|
CheckPhysLimits(sprite.current, generateEvents, confineToScreen,
|
||
|
pScreen);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_X_EXPORT Bool
|
||
|
PointerConfinedToScreen()
|
||
|
{
|
||
|
return sprite.confined;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ChangeToCursor(CursorPtr cursor)
|
||
|
{
|
||
|
|
||
|
if (cursor != sprite.current) {
|
||
|
if ((sprite.current->bits->xhot != cursor->bits->xhot) ||
|
||
|
(sprite.current->bits->yhot != cursor->bits->yhot))
|
||
|
CheckPhysLimits(cursor, FALSE, sprite.confined, (ScreenPtr) NULL);
|
||
|
(*sprite.hotPhys.pScreen->DisplayCursor) (sprite.hotPhys.pScreen,
|
||
|
cursor);
|
||
|
FreeCursor(sprite.current, (Cursor) 0);
|
||
|
sprite.current = cursor;
|
||
|
sprite.current->refcnt++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* returns true if b is a descendent of a */
|
||
|
Bool
|
||
|
IsParent(register WindowPtr a, register WindowPtr b)
|
||
|
{
|
||
|
for (b = b->parent; b; b = b->parent)
|
||
|
if (b == a)
|
||
|
return TRUE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
PostNewCursor(void)
|
||
|
{
|
||
|
WindowPtr win;
|
||
|
|
||
|
GrabPtr grab = inputInfo.pointer->grab;
|
||
|
|
||
|
if (syncEvents.playingEvents)
|
||
|
return;
|
||
|
if (grab) {
|
||
|
if (grab->cursor) {
|
||
|
ChangeToCursor(grab->cursor);
|
||
|
return;
|
||
|
}
|
||
|
if (IsParent(grab->window, sprite.win))
|
||
|
win = sprite.win;
|
||
|
else
|
||
|
win = grab->window;
|
||
|
}
|
||
|
else
|
||
|
win = sprite.win;
|
||
|
for (; win; win = win->parent)
|
||
|
if (win->optional && win->optional->cursor != NullCursor) {
|
||
|
ChangeToCursor(win->optional->cursor);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_X_EXPORT WindowPtr
|
||
|
GetCurrentRootWindow()
|
||
|
{
|
||
|
return ROOT;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT WindowPtr
|
||
|
GetSpriteWindow()
|
||
|
{
|
||
|
return sprite.win;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT CursorPtr
|
||
|
GetSpriteCursor()
|
||
|
{
|
||
|
return sprite.current;
|
||
|
}
|
||
|
|
||
|
_X_EXPORT void
|
||
|
GetSpritePosition(int *px, int *py)
|
||
|
{
|
||
|
*px = sprite.hotPhys.x;
|
||
|
*py = sprite.hotPhys.y;
|
||
|
}
|
||
|
|
||
|
|
||
|
#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */
|
||
|
|
||
|
static void
|
||
|
MonthChangedOrBadTime(register xEvent *xE)
|
||
|
{
|
||
|
/* If the ddx/OS is careless about not processing timestamped events from
|
||
|
* different sources in sorted order, then it's possible for time to go
|
||
|
* backwards when it should not. Here we ensure a decent time.
|
||
|
*/
|
||
|
if ((currentTime.milliseconds - XE_KBPTR.time) > TIMESLOP)
|
||
|
currentTime.months++;
|
||
|
else
|
||
|
XE_KBPTR.time = currentTime.milliseconds;
|
||
|
}
|
||
|
|
||
|
#define NoticeTime(xE) { \
|
||
|
if ((xE)->u.keyButtonPointer.time < currentTime.milliseconds) \
|
||
|
MonthChangedOrBadTime(xE); \
|
||
|
currentTime.milliseconds = (xE)->u.keyButtonPointer.time; \
|
||
|
lastDeviceEventTime = currentTime; }
|
||
|
|
||
|
void
|
||
|
NoticeEventTime(register xEvent *xE)
|
||
|
{
|
||
|
if (!syncEvents.playingEvents)
|
||
|
NoticeTime(xE);
|
||
|
}
|
||
|
|
||
|
/**************************************************************************
|
||
|
* The following procedures deal with synchronous events *
|
||
|
**************************************************************************/
|
||
|
|
||
|
void
|
||
|
EnqueueEvent(xEvent *xE, DeviceIntPtr device, int count)
|
||
|
{
|
||
|
QdEventPtr tail = *syncEvents.pendtail;
|
||
|
|
||
|
QdEventPtr qe;
|
||
|
|
||
|
xEvent *qxE;
|
||
|
|
||
|
NoticeTime(xE);
|
||
|
|
||
|
|
||
|
if (DeviceEventCallback) {
|
||
|
DeviceEventInfoRec eventinfo;
|
||
|
|
||
|
/* The RECORD spec says that the root window field of motion events
|
||
|
* must be valid. At this point, it hasn't been filled in yet, so
|
||
|
* we do it here. The long expression below is necessary to get
|
||
|
* the current root window; the apparently reasonable alternative
|
||
|
* GetCurrentRootWindow()->drawable.id doesn't give you the right
|
||
|
* answer on the first motion event after a screen change because
|
||
|
* the data that GetCurrentRootWindow relies on hasn't been
|
||
|
* updated yet.
|
||
|
*/
|
||
|
if (xE->u.u.type == MotionNotify)
|
||
|
XE_KBPTR.root =
|
||
|
WindowTable[sprite.hotPhys.pScreen->myNum]->drawable.id;
|
||
|
eventinfo.events = xE;
|
||
|
eventinfo.count = count;
|
||
|
CallCallbacks(&DeviceEventCallback, (pointer) &eventinfo);
|
||
|
}
|
||
|
if (xE->u.u.type == MotionNotify) {
|
||
|
sprite.hotPhys.x = XE_KBPTR.rootX;
|
||
|
sprite.hotPhys.y = XE_KBPTR.rootY;
|
||
|
/* do motion compression */
|
||
|
if (tail &&
|
||
|
(tail->event->u.u.type == MotionNotify) &&
|
||
|
(tail->pScreen == sprite.hotPhys.pScreen)) {
|
||
|
tail->event->u.keyButtonPointer.rootX = sprite.hotPhys.x;
|
||
|
tail->event->u.keyButtonPointer.rootY = sprite.hotPhys.y;
|
||
|
tail->event->u.keyButtonPointer.time = XE_KBPTR.time;
|
||
|
tail->months = currentTime.months;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
qe = malloc(sizeof(QdEventRec) + (count * sizeof(xEvent)));
|
||
|
if (!qe)
|
||
|
return;
|
||
|
qe->next = (QdEventPtr) NULL;
|
||
|
qe->device = device;
|
||
|
qe->pScreen = sprite.hotPhys.pScreen;
|
||
|
qe->months = currentTime.months;
|
||
|
qe->event = (xEvent *) (qe + 1);
|
||
|
qe->evcount = count;
|
||
|
for (qxE = qe->event; --count >= 0; qxE++, xE++)
|
||
|
*qxE = *xE;
|
||
|
if (tail)
|
||
|
syncEvents.pendtail = &tail->next;
|
||
|
*syncEvents.pendtail = qe;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
PlayReleasedEvents(void)
|
||
|
{
|
||
|
QdEventPtr *prev, qe;
|
||
|
|
||
|
DeviceIntPtr dev;
|
||
|
|
||
|
prev = &syncEvents.pending;
|
||
|
while ((qe = *prev)) {
|
||
|
if (!qe->device->sync.frozen) {
|
||
|
*prev = qe->next;
|
||
|
if (*syncEvents.pendtail == *prev)
|
||
|
syncEvents.pendtail = prev;
|
||
|
if (qe->event->u.u.type == MotionNotify)
|
||
|
CheckVirtualMotion(qe, NullWindow);
|
||
|
syncEvents.time.months = qe->months;
|
||
|
syncEvents.time.milliseconds = qe->event->u.keyButtonPointer.time;
|
||
|
(*qe->device->public.processInputProc) (qe->event, qe->device,
|
||
|
qe->evcount);
|
||
|
free(qe);
|
||
|
for (dev = inputInfo.devices; dev && dev->sync.frozen;
|
||
|
dev = dev->next);
|
||
|
if (!dev)
|
||
|
break;
|
||
|
/* Playing the event may have unfrozen another device. */
|
||
|
/* So to play it safe, restart at the head of the queue */
|
||
|
prev = &syncEvents.pending;
|
||
|
}
|
||
|
else
|
||
|
prev = &qe->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
FreezeThaw(register DeviceIntPtr dev, Bool frozen)
|
||
|
{
|
||
|
dev->sync.frozen = frozen;
|
||
|
if (frozen)
|
||
|
dev->public.processInputProc = dev->public.enqueueInputProc;
|
||
|
else
|
||
|
dev->public.processInputProc = dev->public.realInputProc;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ComputeFreezes()
|
||
|
{
|
||
|
DeviceIntPtr replayDev = syncEvents.replayDev;
|
||
|
|
||
|
int i;
|
||
|
|
||
|
WindowPtr w;
|
||
|
|
||
|
xEvent *xE;
|
||
|
|
||
|
int count;
|
||
|
|
||
|
GrabPtr grab;
|
||
|
|
||
|
DeviceIntPtr dev;
|
||
|
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next)
|
||
|
FreezeThaw(dev, dev->sync.other || (dev->sync.state >= FROZEN));
|
||
|
if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending))
|
||
|
return;
|
||
|
syncEvents.playingEvents = TRUE;
|
||
|
if (replayDev) {
|
||
|
xE = replayDev->sync.event;
|
||
|
count = replayDev->sync.evcount;
|
||
|
syncEvents.replayDev = (DeviceIntPtr) NULL;
|
||
|
|
||
|
w = XYToWindow(XE_KBPTR.rootX, XE_KBPTR.rootY);
|
||
|
for (i = 0; i < spriteTraceGood; i++) {
|
||
|
if (syncEvents.replayWin == spriteTrace[i]) {
|
||
|
if (!CheckDeviceGrabs(replayDev, xE, i + 1, count)) {
|
||
|
if (replayDev->focus)
|
||
|
DeliverFocusedEvent(replayDev, xE, w, count);
|
||
|
else
|
||
|
DeliverDeviceEvents(w, xE, NullGrab, NullWindow,
|
||
|
replayDev, count);
|
||
|
}
|
||
|
goto playmore;
|
||
|
}
|
||
|
}
|
||
|
/* must not still be in the same stack */
|
||
|
if (replayDev->focus)
|
||
|
DeliverFocusedEvent(replayDev, xE, w, count);
|
||
|
else
|
||
|
DeliverDeviceEvents(w, xE, NullGrab, NullWindow, replayDev, count);
|
||
|
}
|
||
|
playmore:
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||
|
if (!dev->sync.frozen) {
|
||
|
PlayReleasedEvents();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
syncEvents.playingEvents = FALSE;
|
||
|
/* the following may have been skipped during replay, so do it now */
|
||
|
if ((grab = inputInfo.pointer->grab) &&grab->confineTo) {
|
||
|
if (grab->confineTo->drawable.pScreen != sprite.hotPhys.pScreen)
|
||
|
sprite.hotPhys.x = sprite.hotPhys.y = 0;
|
||
|
ConfineCursorToWindow(grab->confineTo, TRUE, TRUE);
|
||
|
}
|
||
|
else
|
||
|
ConfineCursorToWindow(WindowTable[sprite.hotPhys.pScreen->myNum],
|
||
|
TRUE, FALSE);
|
||
|
PostNewCursor();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ScreenRestructured(ScreenPtr pScreen)
|
||
|
{
|
||
|
GrabPtr grab;
|
||
|
|
||
|
if ((grab = inputInfo.pointer->grab) &&grab->confineTo) {
|
||
|
if (grab->confineTo->drawable.pScreen != sprite.hotPhys.pScreen)
|
||
|
sprite.hotPhys.x = sprite.hotPhys.y = 0;
|
||
|
ConfineCursorToWindow(grab->confineTo, TRUE, TRUE);
|
||
|
}
|
||
|
else
|
||
|
ConfineCursorToWindow(WindowTable[sprite.hotPhys.pScreen->myNum],
|
||
|
TRUE, FALSE);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CheckGrabForSyncs(register DeviceIntPtr thisDev, Bool thisMode, Bool otherMode)
|
||
|
{
|
||
|
GrabPtr grab = thisDev->grab;
|
||
|
|
||
|
DeviceIntPtr dev;
|
||
|
|
||
|
if (thisMode == GrabModeSync)
|
||
|
thisDev->sync.state = FROZEN_NO_EVENT;
|
||
|
else { /* free both if same client owns both */
|
||
|
thisDev->sync.state = THAWED;
|
||
|
if (thisDev->sync.other &&
|
||
|
(CLIENT_BITS(thisDev->sync.other->resource) ==
|
||
|
CLIENT_BITS(grab->resource)))
|
||
|
thisDev->sync.other = NullGrab;
|
||
|
}
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||
|
if (dev != thisDev) {
|
||
|
if (otherMode == GrabModeSync)
|
||
|
dev->sync.other = grab;
|
||
|
else { /* free both if same client owns both */
|
||
|
if (dev->sync.other &&
|
||
|
(CLIENT_BITS(dev->sync.other->resource) ==
|
||
|
CLIENT_BITS(grab->resource)))
|
||
|
dev->sync.other = NullGrab;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
ComputeFreezes();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ActivatePointerGrab(register DeviceIntPtr mouse, register GrabPtr grab,
|
||
|
TimeStamp time, Bool autoGrab)
|
||
|
{
|
||
|
WindowPtr oldWin = (mouse->grab) ? mouse->grab->window : sprite.win;
|
||
|
|
||
|
if (grab->confineTo) {
|
||
|
if (grab->confineTo->drawable.pScreen != sprite.hotPhys.pScreen)
|
||
|
sprite.hotPhys.x = sprite.hotPhys.y = 0;
|
||
|
ConfineCursorToWindow(grab->confineTo, FALSE, TRUE);
|
||
|
}
|
||
|
DoEnterLeaveEvents(oldWin, grab->window, NotifyGrab);
|
||
|
mouse->valuator->motionHintWindow = NullWindow;
|
||
|
if (syncEvents.playingEvents)
|
||
|
mouse->grabTime = syncEvents.time;
|
||
|
else
|
||
|
mouse->grabTime = time;
|
||
|
if (grab->cursor)
|
||
|
grab->cursor->refcnt++;
|
||
|
mouse->activeGrab = *grab;
|
||
|
mouse->grab = &mouse->activeGrab;
|
||
|
mouse->fromPassiveGrab = autoGrab;
|
||
|
PostNewCursor();
|
||
|
CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
|
||
|
(Bool) grab->keyboardMode);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
DeactivatePointerGrab(register DeviceIntPtr mouse)
|
||
|
{
|
||
|
GrabPtr grab = mouse->grab;
|
||
|
|
||
|
DeviceIntPtr dev;
|
||
|
|
||
|
mouse->valuator->motionHintWindow = NullWindow;
|
||
|
mouse->grab = NullGrab;
|
||
|
mouse->sync.state = NOT_GRABBED;
|
||
|
mouse->fromPassiveGrab = FALSE;
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||
|
if (dev->sync.other == grab)
|
||
|
dev->sync.other = NullGrab;
|
||
|
}
|
||
|
DoEnterLeaveEvents(grab->window, sprite.win, NotifyUngrab);
|
||
|
if (grab->confineTo)
|
||
|
ConfineCursorToWindow(ROOT, FALSE, FALSE);
|
||
|
PostNewCursor();
|
||
|
if (grab->cursor)
|
||
|
FreeCursor(grab->cursor, (Cursor) 0);
|
||
|
ComputeFreezes();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ActivateKeyboardGrab(register DeviceIntPtr keybd, GrabPtr grab, TimeStamp time,
|
||
|
Bool passive)
|
||
|
{
|
||
|
WindowPtr oldWin;
|
||
|
|
||
|
if (keybd->grab)
|
||
|
oldWin = keybd->grab->window;
|
||
|
else if (keybd->focus)
|
||
|
oldWin = keybd->focus->win;
|
||
|
else
|
||
|
oldWin = sprite.win;
|
||
|
if (oldWin == FollowKeyboardWin)
|
||
|
oldWin = inputInfo.keyboard->focus->win;
|
||
|
if (keybd->valuator)
|
||
|
keybd->valuator->motionHintWindow = NullWindow;
|
||
|
DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab);
|
||
|
if (syncEvents.playingEvents)
|
||
|
keybd->grabTime = syncEvents.time;
|
||
|
else
|
||
|
keybd->grabTime = time;
|
||
|
keybd->activeGrab = *grab;
|
||
|
keybd->grab = &keybd->activeGrab;
|
||
|
keybd->fromPassiveGrab = passive;
|
||
|
CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode,
|
||
|
(Bool) grab->pointerMode);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
DeactivateKeyboardGrab(register DeviceIntPtr keybd)
|
||
|
{
|
||
|
GrabPtr grab = keybd->grab;
|
||
|
|
||
|
DeviceIntPtr dev;
|
||
|
|
||
|
WindowPtr focusWin = keybd->focus ? keybd->focus->win : sprite.win;
|
||
|
|
||
|
if (focusWin == FollowKeyboardWin)
|
||
|
focusWin = inputInfo.keyboard->focus->win;
|
||
|
if (keybd->valuator)
|
||
|
keybd->valuator->motionHintWindow = NullWindow;
|
||
|
keybd->grab = NullGrab;
|
||
|
keybd->sync.state = NOT_GRABBED;
|
||
|
keybd->fromPassiveGrab = FALSE;
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||
|
if (dev->sync.other == grab)
|
||
|
dev->sync.other = NullGrab;
|
||
|
}
|
||
|
DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab);
|
||
|
ComputeFreezes();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AllowSome(ClientPtr client, TimeStamp time, DeviceIntPtr thisDev, int newState)
|
||
|
{
|
||
|
Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced;
|
||
|
|
||
|
TimeStamp grabTime;
|
||
|
|
||
|
DeviceIntPtr dev;
|
||
|
|
||
|
thisGrabbed = thisDev->grab && SameClient(thisDev->grab, client);
|
||
|
thisSynced = FALSE;
|
||
|
otherGrabbed = FALSE;
|
||
|
othersFrozen = TRUE;
|
||
|
grabTime = thisDev->grabTime;
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||
|
if (dev == thisDev)
|
||
|
continue;
|
||
|
if (dev->grab && SameClient(dev->grab, client)) {
|
||
|
if (!(thisGrabbed || otherGrabbed) ||
|
||
|
(CompareTimeStamps(dev->grabTime, grabTime) == LATER))
|
||
|
grabTime = dev->grabTime;
|
||
|
otherGrabbed = TRUE;
|
||
|
if (thisDev->sync.other == dev->grab)
|
||
|
thisSynced = TRUE;
|
||
|
if (dev->sync.state < FROZEN)
|
||
|
othersFrozen = FALSE;
|
||
|
}
|
||
|
else if (!dev->sync.other || !SameClient(dev->sync.other, client))
|
||
|
othersFrozen = FALSE;
|
||
|
}
|
||
|
if (!((thisGrabbed && thisDev->sync.state >= FROZEN) || thisSynced))
|
||
|
return;
|
||
|
if ((CompareTimeStamps(time, currentTime) == LATER) ||
|
||
|
(CompareTimeStamps(time, grabTime) == EARLIER))
|
||
|
return;
|
||
|
switch (newState) {
|
||
|
case THAWED: /* Async */
|
||
|
if (thisGrabbed)
|
||
|
thisDev->sync.state = THAWED;
|
||
|
if (thisSynced)
|
||
|
thisDev->sync.other = NullGrab;
|
||
|
ComputeFreezes();
|
||
|
break;
|
||
|
case FREEZE_NEXT_EVENT: /* Sync */
|
||
|
if (thisGrabbed) {
|
||
|
thisDev->sync.state = FREEZE_NEXT_EVENT;
|
||
|
if (thisSynced)
|
||
|
thisDev->sync.other = NullGrab;
|
||
|
ComputeFreezes();
|
||
|
}
|
||
|
break;
|
||
|
case THAWED_BOTH: /* AsyncBoth */
|
||
|
if (othersFrozen) {
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||
|
if (dev->grab && SameClient(dev->grab, client))
|
||
|
dev->sync.state = THAWED;
|
||
|
if (dev->sync.other && SameClient(dev->sync.other, client))
|
||
|
dev->sync.other = NullGrab;
|
||
|
}
|
||
|
ComputeFreezes();
|
||
|
}
|
||
|
break;
|
||
|
case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */
|
||
|
if (othersFrozen) {
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||
|
if (dev->grab && SameClient(dev->grab, client))
|
||
|
dev->sync.state = FREEZE_BOTH_NEXT_EVENT;
|
||
|
if (dev->sync.other && SameClient(dev->sync.other, client))
|
||
|
dev->sync.other = NullGrab;
|
||
|
}
|
||
|
ComputeFreezes();
|
||
|
}
|
||
|
break;
|
||
|
case NOT_GRABBED: /* Replay */
|
||
|
if (thisGrabbed && thisDev->sync.state == FROZEN_WITH_EVENT) {
|
||
|
if (thisSynced)
|
||
|
thisDev->sync.other = NullGrab;
|
||
|
syncEvents.replayDev = thisDev;
|
||
|
syncEvents.replayWin = thisDev->grab->window;
|
||
|
(*thisDev->DeactivateGrab) (thisDev);
|
||
|
syncEvents.replayDev = (DeviceIntPtr) NULL;
|
||
|
}
|
||
|
break;
|
||
|
case THAW_OTHERS: /* AsyncOthers */
|
||
|
if (othersFrozen) {
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||
|
if (dev == thisDev)
|
||
|
continue;
|
||
|
if (dev->grab && SameClient(dev->grab, client))
|
||
|
dev->sync.state = THAWED;
|
||
|
if (dev->sync.other && SameClient(dev->sync.other, client))
|
||
|
dev->sync.other = NullGrab;
|
||
|
}
|
||
|
ComputeFreezes();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ProcAllowEvents(register ClientPtr client)
|
||
|
{
|
||
|
TimeStamp time;
|
||
|
|
||
|
DeviceIntPtr mouse = inputInfo.pointer;
|
||
|
|
||
|
DeviceIntPtr keybd = inputInfo.keyboard;
|
||
|
|
||
|
REQUEST(xAllowEventsReq);
|
||
|
|
||
|
REQUEST_SIZE_MATCH(xAllowEventsReq);
|
||
|
time = ClientTimeToServerTime(stuff->time);
|
||
|
switch (stuff->mode) {
|
||
|
case ReplayPointer:
|
||
|
AllowSome(client, time, mouse, NOT_GRABBED);
|
||
|
break;
|
||
|
case SyncPointer:
|
||
|
AllowSome(client, time, mouse, FREEZE_NEXT_EVENT);
|
||
|
break;
|
||
|
case AsyncPointer:
|
||
|
AllowSome(client, time, mouse, THAWED);
|
||
|
break;
|
||
|
case ReplayKeyboard:
|
||
|
AllowSome(client, time, keybd, NOT_GRABBED);
|
||
|
break;
|
||
|
case SyncKeyboard:
|
||
|
AllowSome(client, time, keybd, FREEZE_NEXT_EVENT);
|
||
|
break;
|
||
|
case AsyncKeyboard:
|
||
|
AllowSome(client, time, keybd, THAWED);
|
||
|
break;
|
||
|
case SyncBoth:
|
||
|
AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT);
|
||
|
break;
|
||
|
case AsyncBoth:
|
||
|
AllowSome(client, time, keybd, THAWED_BOTH);
|
||
|
break;
|
||
|
default:
|
||
|
client->errorValue = stuff->mode;
|
||
|
return BadValue;
|
||
|
}
|
||
|
return Success;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ReleaseActiveGrabs(ClientPtr client)
|
||
|
{
|
||
|
DeviceIntPtr dev;
|
||
|
|
||
|
Bool done;
|
||
|
|
||
|
/* XXX CloseDownClient should remove passive grabs before
|
||
|
* releasing active grabs.
|
||
|
*/
|
||
|
do {
|
||
|
done = TRUE;
|
||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||
|
if (dev->grab && SameClient(dev->grab, client)) {
|
||
|
(*dev->DeactivateGrab) (dev);
|
||
|
done = FALSE;
|
||
|
}
|
||
|
}
|
||
|
} while (!done);
|
||
|
}
|
||
|
|
||
|
/**************************************************************************
|
||
|
* The following procedures deal with delivering events *
|
||
|
**************************************************************************/
|
||
|
|
||
|
_X_EXPORT int
|
||
|
TryClientEvents(ClientPtr client, xEvent *pEvents, int count, Mask mask,
|
||
|
Mask filter, GrabPtr grab)
|
||
|
{
|
||
|
int type;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (debug_events)
|
||
|
ErrorF("Event([%d, %d], mask=0x%x), client=%d",
|
||
|
pEvents->u.u.type, pEvents->u.u.detail, mask, client->index);
|
||
|
#endif
|
||
|
if ((client) && (client != serverClient) && (!client->clientGone) &&
|
||
|
((filter == CantBeFiltered) || (mask & filter))) {
|
||
|
if (grab && !SameClient(grab, client))
|
||
|
return -1; /* don't send, but notify caller */
|
||
|
type = pEvents->u.u.type;
|
||
|
if (type == MotionNotify) {
|
||
|
if (mask & PointerMotionHintMask) {
|
||
|
if (WID(inputInfo.pointer->valuator->motionHintWindow) ==
|
||
|
pEvents->u.keyButtonPointer.event) {
|
||
|
#ifdef DEBUG
|
||
|
if (debug_events)
|
||
|
ErrorF("\n");
|
||
|
fprintf(stderr,
|
||
|
"motionHintWindow == keyButtonPointer.event\n");
|
||
|
#endif
|
||
|
return 1; /* don't send, but pretend we did */
|
||
|
}
|
||
|
pEvents->u.u.detail = NotifyHint;
|
||
|
}
|
||
|
else {
|
||
|
pEvents->u.u.detail = NotifyNormal;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (BitIsOn(criticalEvents, type)) {
|
||
|
#ifdef SMART_SCHEDULE
|
||
|
if (client->smart_priority < SMART_MAX_PRIORITY)
|
||
|
client->smart_priority++;
|
||
|
#endif
|
||
|
SetCriticalOutputPending();
|
||
|
}
|
||
|
|
||
|
WriteEventsToClient(client, count, pEvents);
|
||
|
#ifdef DEBUG
|
||
|
if (debug_events)
|
||
|
ErrorF(" delivered\n");
|
||
|
#endif
|
||
|
return 1;
|
||
|
}
|
||
|
else {
|
||
|
#ifdef DEBUG
|
||
|
if (debug_events)
|
||
|
ErrorF("\n");
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
DeliverEventsToWindow(register WindowPtr pWin, xEvent *pEvents, int count,
|
||
|