xserver-multidpi/dix/events.c

6137 lines
176 KiB
C
Raw Normal View History

2003-11-14 16:54:54 +01:00
/************************************************************
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.
********************************************************/
2003-11-14 17:49:22 +01:00
/* The panoramix components contained the following notice */
2004-04-23 21:54:30 +02:00
/*****************************************************************
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.
******************************************************************/
2003-11-14 16:54:54 +01:00
/*****************************************************************
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.
******************************************************************/
/*
* MPX additions
* Copyright 2006 by Peter Hutterer
* Author: Peter Hutterer <peter@cs.unisa.edu.au>
*/
2007-04-13 05:38:44 +02:00
/** @file
* This file handles event delivery and a big part of the server-side protocol
* handling (the parts for input devices).
*/
2003-11-14 16:54:54 +01:00
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <X11/X.h>
#include <X11/keysym.h>
#include "misc.h"
2003-11-14 16:54:54 +01:00
#include "resource.h"
#define NEED_EVENTS
#define NEED_REPLIES
#include <X11/Xproto.h>
2003-11-14 16:54:54 +01:00
#include "windowstr.h"
#include "inputstr.h"
#include "scrnintstr.h"
#include "cursorstr.h"
#include "dixstruct.h"
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
#include "panoramiX.h"
#include "panoramiXsrv.h"
#endif
#include "globals.h"
2003-11-14 16:54:54 +01:00
#ifdef XKB
#include <X11/extensions/XKBproto.h>
#include <xkbsrv.h>
2003-11-14 17:49:22 +01:00
extern Bool XkbFilterEvents(ClientPtr, int, xEvent *);
2003-11-14 16:54:54 +01:00
#endif
#include "xace.h"
2003-11-14 16:54:54 +01:00
#ifdef XSERVER_DTRACE
#include <sys/types.h>
typedef const char *string;
#include "Xserver-dtrace.h"
#endif
#ifdef XEVIE
extern WindowPtr *WindowTable;
extern int xevieFlag;
extern int xevieClientIndex;
extern DeviceIntPtr xeviemouse;
extern DeviceIntPtr xeviekb;
extern Mask xevieMask;
extern Mask xevieFilters[128];
extern int xevieEventSent;
extern int xevieKBEventSent;
int xeviegrabState = 0;
#endif
#include <X11/extensions/XIproto.h>
#include <X11/extensions/XI.h>
#include "exglobals.h"
2003-11-14 17:49:22 +01:00
#include "exevents.h"
#include "exglobals.h"
2003-11-14 17:49:22 +01:00
#include "extnsionst.h"
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
#include "dixevents.h"
#include "dixgrabs.h"
#include "dispatch.h"
#include <X11/extensions/ge.h>
#include "geext.h"
#include "geint.h"
2007-04-13 05:38:44 +02:00
/**
* Extension events type numbering starts at EXTENSION_EVENT_BASE.
*/
2003-11-14 16:54:54 +01:00
#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))
/**
* Used to indicate a implicit passive grab created by a ButtonPress event.
* See DeliverEventsToWindow().
*/
#define ImplicitGrabMask (1 << 7)
2003-11-14 16:54:54 +01:00
/*
* 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)
2003-11-14 17:49:22 +01:00
#define XE_KBPTR (xE->u.keyButtonPointer)
2003-11-14 16:54:54 +01:00
#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
_X_EXPORT CallbackListPtr EventCallback;
_X_EXPORT CallbackListPtr DeviceEventCallback;
2003-11-14 16:54:54 +01:00
#define DNPMCOUNT 8
Mask DontPropagateMasks[DNPMCOUNT];
static int DontPropagateRefCnts[DNPMCOUNT];
2007-04-13 05:38:44 +02:00
/**
* Main input device struct.
* inputInfo.pointer
* is the core pointer. Referred to as "virtual core pointer", "VCP",
* "core pointer" or inputInfo.pointer. There is exactly one core pointer,
2007-05-30 10:14:31 +02:00
* but multiple devices may send core events. The VCP is only used if no
* physical device is connected and does not have a visible cursor.
* Before the integration of MPX, any core request would operate on the
* VCP/VCK. Core events would always come from one of those two. Now both
* are only fallback devices if no physical devices are available.
2007-04-13 05:38:44 +02:00
*
* inputInfo.keyboard
* is the core keyboard ("virtual core keyboard", "VCK", "core keyboard").
* See inputInfo.pointer.
*
* inputInfo.devices
2007-05-30 10:14:31 +02:00
* linked list containing all devices BUT NOT INCLUDING VCK and VCP.
2007-04-13 05:38:44 +02:00
*
* inputInfo.off_devices
* Devices that have not been initialized and are thus turned off.
*
* inputInfo.numDevices
2007-05-30 10:14:31 +02:00
* Total number of devices (not counting VCP and VCK).
2007-04-13 05:38:44 +02:00
*/
_X_EXPORT InputInfo inputInfo;
2003-11-14 16:54:54 +01:00
static struct {
QdEventPtr pending, *pendtail;
DeviceIntPtr replayDev; /* kludgy rock to put flag for */
WindowPtr replayWin; /* ComputeFreezes */
Bool playingEvents;
TimeStamp time;
} syncEvents;
#define RootWindow(dev) dev->spriteInfo->sprite->spriteTrace[0]
2003-11-14 16:54:54 +01:00
static xEvent* swapEvent = NULL;
static int swapEventLen = 0;
/**
* True if device owns a cursor, false if device shares a cursor sprite with
* another device.
*/
_X_EXPORT Bool
DevHasCursor(DeviceIntPtr pDev)
{
return (pDev != inputInfo.pointer && pDev->spriteInfo->spriteOwner);
}
/*
* Return true if a device is a pointer, check is the same as used by XI to
* fill the 'use' field.
*/
_X_EXPORT Bool
IsPointerDevice(DeviceIntPtr dev)
{
return ((dev->valuator && dev->button) || dev == inputInfo.pointer);
}
/*
* Return true if a device is a keyboard, check is the same as used by XI to
* fill the 'use' field.
*/
_X_EXPORT Bool
IsKeyboardDevice(DeviceIntPtr dev)
{
return ((dev->key && dev->kbdfeed) || dev == inputInfo.keyboard);
}
#ifdef XEVIE
_X_EXPORT WindowPtr xeviewin;
_X_EXPORT HotSpot xeviehot;
#endif
2003-11-14 16:54:54 +01:00
static void DoEnterLeaveEvents(
DeviceIntPtr pDev,
WindowPtr fromWin,
WindowPtr toWin,
int mode
);
2003-11-14 16:54:54 +01:00
static WindowPtr XYToWindow(
DeviceIntPtr pDev,
int x,
int y
2003-11-14 16:54:54 +01:00
);
2007-04-13 05:38:44 +02:00
/**
* Max event opcode.
*/
2003-11-14 17:49:22 +01:00
extern int lastEvent;
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
static Mask lastEventMask;
2003-11-14 16:54:54 +01:00
#ifdef XINPUT
2003-11-14 17:49:22 +01:00
extern int DeviceMotionNotify;
2003-11-14 16:54:54 +01:00
#endif
#define CantBeFiltered NoEventMask
static Mask filters[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 */
};
/**
* same principle as filters, but one set of filters for each extension.
* The extension is responsible for setting the filters by calling
* SetGenericFilter().
*/
static Mask* generic_filters[MAXEXTENSIONS];
2003-11-14 16:54:54 +01:00
static CARD8 criticalEvents[32] =
{
2003-11-14 17:49:22 +01:00
0x7c /* key and button events */
2003-11-14 16:54:54 +01:00
};
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
static void PostNewCursor(DeviceIntPtr pDev);
2003-11-14 17:49:22 +01:00
#define SyntheticMotion(dev, x, y) \
PostSyntheticMotion(dev, x, y, noPanoramiXExtension ? 0 : \
dev->spriteInfo->sprite->screen->myNum, \
syncEvents.playingEvents ? \
syncEvents.time.milliseconds : \
currentTime.milliseconds);
2003-11-14 17:49:22 +01:00
static Bool
XineramaSetCursorPosition(
DeviceIntPtr pDev,
2003-11-14 17:49:22 +01:00
int x,
int y,
Bool generateEvent
){
ScreenPtr pScreen;
BoxRec box;
int i;
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 17:49:22 +01:00
/* x,y are in Screen 0 coordinates. We need to decide what Screen
to send the message too and what the coordinates relative to
that screen are. */
pScreen = pSprite->screen;
2003-11-14 17:49:22 +01:00
x += panoramiXdataPtr[0].x;
y += panoramiXdataPtr[0].y;
if(!POINT_IN_REGION(pScreen, &XineramaScreenRegions[pScreen->myNum],
x, y, &box))
{
FOR_NSCREENS(i)
{
if(i == pScreen->myNum)
continue;
if(POINT_IN_REGION(pScreen, &XineramaScreenRegions[i], x, y, &box))
{
pScreen = screenInfo.screens[i];
break;
}
}
}
pSprite->screen = pScreen;
pSprite->hotPhys.x = x - panoramiXdataPtr[0].x;
pSprite->hotPhys.y = y - panoramiXdataPtr[0].y;
2003-11-14 17:49:22 +01:00
x -= panoramiXdataPtr[pScreen->myNum].x;
y -= panoramiXdataPtr[pScreen->myNum].y;
return (*pScreen->SetCursorPosition)(pDev, pScreen, x, y, generateEvent);
2003-11-14 17:49:22 +01:00
}
static void
XineramaConstrainCursor(DeviceIntPtr pDev)
2003-11-14 16:54:54 +01:00
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
ScreenPtr pScreen;
BoxRec newBox;
pScreen = pSprite->screen;
newBox = pSprite->physLimits;
2003-11-14 17:49:22 +01:00
/* Translate the constraining box to the screen
the sprite is actually on */
newBox.x1 += panoramiXdataPtr[0].x - panoramiXdataPtr[pScreen->myNum].x;
newBox.x2 += panoramiXdataPtr[0].x - panoramiXdataPtr[pScreen->myNum].x;
newBox.y1 += panoramiXdataPtr[0].y - panoramiXdataPtr[pScreen->myNum].y;
newBox.y2 += panoramiXdataPtr[0].y - panoramiXdataPtr[pScreen->myNum].y;
(* pScreen->ConstrainCursor)(pDev, pScreen, &newBox);
2003-11-14 16:54:54 +01:00
}
2003-11-14 17:49:22 +01:00
static void
XineramaCheckPhysLimits(
DeviceIntPtr pDev,
2003-11-14 17:49:22 +01:00
CursorPtr cursor,
Bool generateEvents
){
HotSpot new;
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 17:49:22 +01:00
if (!cursor)
return;
new = pSprite->hotPhys;
2003-11-14 17:49:22 +01:00
/* I don't care what the DDX has to say about it */
pSprite->physLimits = pSprite->hotLimits;
2003-11-14 17:49:22 +01:00
/* constrain the pointer to those limits */
if (new.x < pSprite->physLimits.x1)
new.x = pSprite->physLimits.x1;
2003-11-14 17:49:22 +01:00
else
if (new.x >= pSprite->physLimits.x2)
new.x = pSprite->physLimits.x2 - 1;
if (new.y < pSprite->physLimits.y1)
new.y = pSprite->physLimits.y1;
2003-11-14 17:49:22 +01:00
else
if (new.y >= pSprite->physLimits.y2)
new.y = pSprite->physLimits.y2 - 1;
2003-11-14 17:49:22 +01:00
if (pSprite->hotShape) /* more work if the shape is a mess */
ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y);
2003-11-14 17:49:22 +01:00
if((new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y))
2003-11-14 17:49:22 +01:00
{
XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents);
2003-11-14 17:49:22 +01:00
if (!generateEvents)
SyntheticMotion(pDev, new.x, new.y);
2003-11-14 17:49:22 +01:00
}
/* Tell DDX what the limits are */
XineramaConstrainCursor(pDev);
2003-11-14 17:49:22 +01:00
}
static Bool
XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin)
2003-11-14 17:49:22 +01:00
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 17:49:22 +01:00
if(pWin == WindowTable[0]) {
memcpy(pSprite->windows, WindowTable,
2003-11-14 17:49:22 +01:00
PanoramiXNumScreens*sizeof(WindowPtr));
} else {
PanoramiXRes *win;
int i;
win = (PanoramiXRes*)LookupIDByType(pWin->drawable.id, XRT_WINDOW);
if(!win)
return FALSE;
for(i = 0; i < PanoramiXNumScreens; i++) {
pSprite->windows[i] = LookupIDByType(win->info[i].id, RT_WINDOW);
if(!pSprite->windows[i]) /* window is being unmapped */
2003-11-14 17:49:22 +01:00
return FALSE;
}
}
return TRUE;
}
static void
XineramaCheckVirtualMotion(
DeviceIntPtr pDev,
2003-11-14 17:49:22 +01:00
QdEventPtr qe,
WindowPtr pWin)
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 17:49:22 +01:00
if (qe)
{
pSprite->hot.pScreen = qe->pScreen; /* should always be Screen 0 */
pSprite->hot.x = qe->event->u.keyButtonPointer.rootX;
pSprite->hot.y = qe->event->u.keyButtonPointer.rootY;
pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo :
2003-11-14 17:49:22 +01:00
NullWindow;
}
if (pWin)
{
int x, y, off_x, off_y, i;
BoxRec lims;
if(!XineramaSetWindowPntrs(pDev, pWin))
2003-11-14 17:49:22 +01:00
return;
i = PanoramiXNumScreens - 1;
REGION_COPY(pSprite->screen, &pSprite->Reg2,
&pSprite->windows[i]->borderSize);
2003-11-14 17:49:22 +01:00
off_x = panoramiXdataPtr[i].x;
off_y = panoramiXdataPtr[i].y;
while(i--) {
x = off_x - panoramiXdataPtr[i].x;
y = off_y - panoramiXdataPtr[i].y;
if(x || y)
REGION_TRANSLATE(pSprite->screen, &pSprite->Reg2, x, y);
2003-11-14 17:49:22 +01:00
REGION_UNION(pSprite->screen, &pSprite->Reg2, &pSprite->Reg2,
&pSprite->windows[i]->borderSize);
2003-11-14 17:49:22 +01:00
off_x = panoramiXdataPtr[i].x;
off_y = panoramiXdataPtr[i].y;
}
lims = *REGION_EXTENTS(pSprite->screen, &pSprite->Reg2);
2003-11-14 17:49:22 +01:00
if (pSprite->hot.x < lims.x1)
pSprite->hot.x = lims.x1;
else if (pSprite->hot.x >= lims.x2)
pSprite->hot.x = lims.x2 - 1;
if (pSprite->hot.y < lims.y1)
pSprite->hot.y = lims.y1;
else if (pSprite->hot.y >= lims.y2)
pSprite->hot.y = lims.y2 - 1;
2003-11-14 17:49:22 +01:00
if (REGION_NUM_RECTS(&pSprite->Reg2) > 1)
ConfineToShape(pDev, &pSprite->Reg2,
&pSprite->hot.x, &pSprite->hot.y);
2003-11-14 17:49:22 +01:00
if (qe)
{
qe->pScreen = pSprite->hot.pScreen;
qe->event->u.keyButtonPointer.rootX = pSprite->hot.x;
qe->event->u.keyButtonPointer.rootY = pSprite->hot.y;
2003-11-14 17:49:22 +01:00
}
}
#ifdef XEVIE
xeviehot.x = pSprite->hot.x;
xeviehot.y = pSprite->hot.y;
#endif
2003-11-14 17:49:22 +01:00
}
static Bool
XineramaCheckMotion(xEvent *xE, DeviceIntPtr pDev)
2003-11-14 17:49:22 +01:00
{
WindowPtr prevSpriteWin;
SpritePtr pSprite = pDev->spriteInfo->sprite;
prevSpriteWin = pSprite->win;
2003-11-14 17:49:22 +01:00
if (xE && !syncEvents.playingEvents)
{
/* Motion events entering DIX get translated to Screen 0
coordinates. Replayed events have already been
translated since they've entered DIX before */
XE_KBPTR.rootX += panoramiXdataPtr[pSprite->screen->myNum].x -
2003-11-14 17:49:22 +01:00
panoramiXdataPtr[0].x;
XE_KBPTR.rootY += panoramiXdataPtr[pSprite->screen->myNum].y -
2003-11-14 17:49:22 +01:00
panoramiXdataPtr[0].y;
pSprite->hot.x = XE_KBPTR.rootX;
pSprite->hot.y = XE_KBPTR.rootY;
if (pSprite->hot.x < pSprite->physLimits.x1)
pSprite->hot.x = pSprite->physLimits.x1;
else if (pSprite->hot.x >= pSprite->physLimits.x2)
pSprite->hot.x = pSprite->physLimits.x2 - 1;
if (pSprite->hot.y < pSprite->physLimits.y1)
pSprite->hot.y = pSprite->physLimits.y1;
else if (pSprite->hot.y >= pSprite->physLimits.y2)
pSprite->hot.y = pSprite->physLimits.y2 - 1;
if (pSprite->hotShape)
ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y);
pSprite->hotPhys = pSprite->hot;
if ((pSprite->hotPhys.x != XE_KBPTR.rootX) ||
(pSprite->hotPhys.y != XE_KBPTR.rootY))
2003-11-14 17:49:22 +01:00
{
XineramaSetCursorPosition(
pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE);
2003-11-14 17:49:22 +01:00
}
XE_KBPTR.rootX = pSprite->hot.x;
XE_KBPTR.rootY = pSprite->hot.y;
2003-11-14 17:49:22 +01:00
}
#ifdef XEVIE
xeviehot.x = pSprite->hot.x;
xeviehot.y = pSprite->hot.y;
xeviewin =
#endif
pSprite->win = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y);
2003-11-14 17:49:22 +01:00
if (pSprite->win != prevSpriteWin)
2003-11-14 17:49:22 +01:00
{
if (prevSpriteWin != NullWindow) {
if (!xE)
UpdateCurrentTimeIf();
DoEnterLeaveEvents(pDev, prevSpriteWin, pSprite->win,
NotifyNormal);
}
PostNewCursor(pDev);
2003-11-14 17:49:22 +01:00
return FALSE;
}
return TRUE;
}
static void
XineramaConfineCursorToWindow(DeviceIntPtr pDev,
WindowPtr pWin,
Bool generateEvents)
2003-11-14 17:49:22 +01:00
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 17:49:22 +01:00
if (syncEvents.playingEvents)
{
XineramaCheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin);
SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y);
2003-11-14 17:49:22 +01:00
}
else
{
int x, y, off_x, off_y, i;
if(!XineramaSetWindowPntrs(pDev, pWin))
2003-11-14 17:49:22 +01:00
return;
i = PanoramiXNumScreens - 1;
REGION_COPY(pSprite->screen, &pSprite->Reg1,
&pSprite->windows[i]->borderSize);
2003-11-14 17:49:22 +01:00
off_x = panoramiXdataPtr[i].x;
off_y = panoramiXdataPtr[i].y;
while(i--) {
x = off_x - panoramiXdataPtr[i].x;
y = off_y - panoramiXdataPtr[i].y;
if(x || y)
REGION_TRANSLATE(pSprite->screen, &pSprite->Reg1, x, y);
2003-11-14 17:49:22 +01:00
REGION_UNION(pSprite->screen, &pSprite->Reg1, &pSprite->Reg1,
&pSprite->windows[i]->borderSize);
2003-11-14 17:49:22 +01:00
off_x = panoramiXdataPtr[i].x;
off_y = panoramiXdataPtr[i].y;
}
pSprite->hotLimits = *REGION_EXTENTS(pSprite->screen, &pSprite->Reg1);
2003-11-14 17:49:22 +01:00
if(REGION_NUM_RECTS(&pSprite->Reg1) > 1)
pSprite->hotShape = &pSprite->Reg1;
2003-11-14 17:49:22 +01:00
else
pSprite->hotShape = NullRegion;
2003-11-14 17:49:22 +01:00
pSprite->confined = FALSE;
pSprite->confineWin = (pWin == WindowTable[0]) ? NullWindow : pWin;
2003-11-14 17:49:22 +01:00
XineramaCheckPhysLimits(pDev, pSprite->current,
generateEvents);
2003-11-14 17:49:22 +01:00
}
}
static void
XineramaChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor)
2003-11-14 17:49:22 +01:00
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
if (cursor != pSprite->current)
2003-11-14 17:49:22 +01:00
{
if ((pSprite->current->bits->xhot != cursor->bits->xhot) ||
(pSprite->current->bits->yhot != cursor->bits->yhot))
XineramaCheckPhysLimits(pDev, cursor, FALSE);
(*pSprite->screen->DisplayCursor)(pDev, pSprite->screen, cursor);
FreeCursor(pSprite->current, (Cursor)0);
pSprite->current = cursor;
pSprite->current->refcnt++;
2003-11-14 17:49:22 +01:00
}
}
#else
#define SyntheticMotion(x, y) \
PostSyntheticMotion(x, y, \
0, \
syncEvents.playingEvents ? \
syncEvents.time.milliseconds : \
currentTime.milliseconds);
2003-11-14 17:49:22 +01:00
#endif /* PANORAMIX */
2003-11-14 16:54:54 +01:00
void
SetMaskForEvent(Mask mask, int event)
2003-11-14 16:54:54 +01:00
{
if ((event < LASTEvent) || (event >= 128))
FatalError("SetMaskForEvent: bogus event number");
filters[event] = mask;
}
_X_EXPORT void
SetCriticalEvent(int event)
2003-11-14 16:54:54 +01:00
{
if (event >= 128)
FatalError("SetCriticalEvent: bogus event number");
criticalEvents[event >> 3] |= 1 << (event & 7);
}
#ifdef SHAPE
void
ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py)
2003-11-14 16:54:54 +01:00
{
BoxRec box;
int x = *px, y = *py;
int incx = 1, incy = 1;
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
if (POINT_IN_REGION(pSprite->hot.pScreen, shape, x, y, &box))
2003-11-14 16:54:54 +01:00
return;
box = *REGION_EXTENTS(pSprite->hot.pScreen, shape);
2003-11-14 16:54:54 +01:00
/* 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(pSprite->hot.pScreen, shape, x, y, &box));
2003-11-14 16:54:54 +01:00
*px = x;
*py = y;
}
#endif
static void
2003-11-14 17:49:22 +01:00
CheckPhysLimits(
DeviceIntPtr pDev,
2003-11-14 17:49:22 +01:00
CursorPtr cursor,
Bool generateEvents,
Bool confineToScreen,
ScreenPtr pScreen)
2003-11-14 16:54:54 +01:00
{
HotSpot new;
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
if (!cursor)
return;
new = pSprite->hotPhys;
2003-11-14 16:54:54 +01:00
if (pScreen)
new.pScreen = pScreen;
else
pScreen = new.pScreen;
(*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits,
&pSprite->physLimits);
pSprite->confined = confineToScreen;
(* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits);
if (new.x < pSprite->physLimits.x1)
new.x = pSprite->physLimits.x1;
2003-11-14 16:54:54 +01:00
else
if (new.x >= pSprite->physLimits.x2)
new.x = pSprite->physLimits.x2 - 1;
if (new.y < pSprite->physLimits.y1)
new.y = pSprite->physLimits.y1;
2003-11-14 16:54:54 +01:00
else
if (new.y >= pSprite->physLimits.y2)
new.y = pSprite->physLimits.y2 - 1;
2003-11-14 16:54:54 +01:00
#ifdef SHAPE
if (pSprite->hotShape)
ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y);
2003-11-14 16:54:54 +01:00
#endif
if ((pScreen != pSprite->hotPhys.pScreen) ||
(new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y))
2003-11-14 16:54:54 +01:00
{
if (pScreen != pSprite->hotPhys.pScreen)
pSprite->hotPhys = new;
(*pScreen->SetCursorPosition)
(pDev, pScreen, new.x, new.y, generateEvents);
if (!generateEvents)
SyntheticMotion(pDev, new.x, new.y);
2003-11-14 16:54:54 +01:00
}
}
static void
2003-11-14 17:49:22 +01:00
CheckVirtualMotion(
DeviceIntPtr pDev,
QdEventPtr qe,
WindowPtr pWin)
2003-11-14 16:54:54 +01:00
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension) {
XineramaCheckVirtualMotion(pDev, qe, pWin);
2003-11-14 17:49:22 +01:00
return;
}
#endif
2003-11-14 16:54:54 +01:00
if (qe)
{
pSprite->hot.pScreen = qe->pScreen;
pSprite->hot.x = qe->event->u.keyButtonPointer.rootX;
pSprite->hot.y = qe->event->u.keyButtonPointer.rootY;
pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow;
2003-11-14 16:54:54 +01:00
}
if (pWin)
{
BoxRec lims;
if (pSprite->hot.pScreen != pWin->drawable.pScreen)
2003-11-14 16:54:54 +01:00
{
pSprite->hot.pScreen = pWin->drawable.pScreen;
pSprite->hot.x = pSprite->hot.y = 0;
2003-11-14 16:54:54 +01:00
}
lims = *REGION_EXTENTS(pWin->drawable.pScreen, &pWin->borderSize);
if (pSprite->hot.x < lims.x1)
pSprite->hot.x = lims.x1;
else if (pSprite->hot.x >= lims.x2)
pSprite->hot.x = lims.x2 - 1;
if (pSprite->hot.y < lims.y1)
pSprite->hot.y = lims.y1;
else if (pSprite->hot.y >= lims.y2)
pSprite->hot.y = lims.y2 - 1;
2003-11-14 16:54:54 +01:00
#ifdef SHAPE
if (wBoundingShape(pWin))
ConfineToShape(pDev, &pWin->borderSize,
&pSprite->hot.x, &pSprite->hot.y);
2003-11-14 16:54:54 +01:00
#endif
if (qe)
{
qe->pScreen = pSprite->hot.pScreen;
qe->event->u.keyButtonPointer.rootX = pSprite->hot.x;
qe->event->u.keyButtonPointer.rootY = pSprite->hot.y;
2003-11-14 16:54:54 +01:00
}
}
#ifdef XEVIE
xeviehot.x = pSprite->hot.x;
xeviehot.y = pSprite->hot.y;
#endif
RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum];
2003-11-14 16:54:54 +01:00
}
2003-11-14 17:49:22 +01:00
static void
ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bool confineToScreen)
2003-11-14 16:54:54 +01:00
{
ScreenPtr pScreen = pWin->drawable.pScreen;
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension) {
XineramaConfineCursorToWindow(pDev, pWin, generateEvents);
2003-11-14 17:49:22 +01:00
return;
}
#endif
2003-11-14 16:54:54 +01:00
if (syncEvents.playingEvents)
{
CheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin);
SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y);
2003-11-14 16:54:54 +01:00
}
else
{
pSprite->hotLimits = *REGION_EXTENTS( pScreen, &pWin->borderSize);
2003-11-14 16:54:54 +01:00
#ifdef SHAPE
pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize
2003-11-14 16:54:54 +01:00
: NullRegion;
#endif
CheckPhysLimits(pDev, pSprite->current, generateEvents,
confineToScreen, pScreen);
2003-11-14 16:54:54 +01:00
}
}
_X_EXPORT Bool
PointerConfinedToScreen(DeviceIntPtr pDev)
2003-11-14 16:54:54 +01:00
{
return pDev->spriteInfo->sprite->confined;
2003-11-14 16:54:54 +01:00
}
2007-04-13 05:38:44 +02:00
/**
* Update the sprite cursor to the given cursor.
*
* ChangeToCursor() will display the new cursor and free the old cursor (if
* applicable). If the provided cursor is already the updated cursor, nothing
* happens.
*/
2003-11-14 16:54:54 +01:00
static void
ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor)
2003-11-14 16:54:54 +01:00
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension) {
XineramaChangeToCursor(pDev, cursor);
2003-11-14 17:49:22 +01:00
return;
}
#endif
if (cursor != pSprite->current)
2003-11-14 16:54:54 +01:00
{
if ((pSprite->current->bits->xhot != cursor->bits->xhot) ||
(pSprite->current->bits->yhot != cursor->bits->yhot))
CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined,
2003-11-14 16:54:54 +01:00
(ScreenPtr)NULL);
(*pSprite->hotPhys.pScreen->DisplayCursor) (pDev,
pSprite->hotPhys.pScreen,
cursor);
FreeCursor(pSprite->current, (Cursor)0);
pSprite->current = cursor;
pSprite->current->refcnt++;
2003-11-14 16:54:54 +01:00
}
}
2007-04-13 05:38:44 +02:00
/**
* @returns true if b is a descendent of a
*/
2003-11-14 16:54:54 +01:00
Bool
IsParent(WindowPtr a, WindowPtr b)
2003-11-14 16:54:54 +01:00
{
for (b = b->parent; b; b = b->parent)
if (b == a) return TRUE;
return FALSE;
}
2007-04-13 05:38:44 +02:00
/**
* Update the cursor displayed on the screen.
*
* Called whenever a cursor may have changed shape or position.
*/
2003-11-14 16:54:54 +01:00
static void
PostNewCursor(DeviceIntPtr pDev)
2003-11-14 16:54:54 +01:00
{
WindowPtr win;
GrabPtr grab = pDev->deviceGrab.grab;
SpritePtr pSprite = pDev->spriteInfo->sprite;
2007-01-08 03:01:18 +01:00
CursorPtr pCursor;
2003-11-14 16:54:54 +01:00
if (syncEvents.playingEvents)
return;
if (grab)
{
if (grab->cursor)
{
ChangeToCursor(pDev, grab->cursor);
2003-11-14 16:54:54 +01:00
return;
}
if (IsParent(grab->window, pSprite->win))
win = pSprite->win;
2003-11-14 16:54:54 +01:00
else
win = grab->window;
}
else
win = pSprite->win;
2003-11-14 16:54:54 +01:00
for (; win; win = win->parent)
2007-01-08 03:01:18 +01:00
{
if (win->optional)
{
pCursor = WindowGetDeviceCursor(win, pDev);
if (!pCursor && win->optional->cursor != NullCursor)
pCursor = win->optional->cursor;
if (pCursor)
{
ChangeToCursor(pDev, pCursor);
return;
}
2003-11-14 16:54:54 +01:00
}
2007-01-08 03:01:18 +01:00
}
2003-11-14 16:54:54 +01:00
}
/**
* @param dev device which you want to know its current root window
* @return root window where dev's sprite is located
*/
_X_EXPORT WindowPtr
GetCurrentRootWindow(DeviceIntPtr dev)
2003-11-14 16:54:54 +01:00
{
return RootWindow(dev);
2003-11-14 16:54:54 +01:00
}
2007-04-13 05:38:44 +02:00
/**
* @return window underneath the cursor sprite.
*/
_X_EXPORT WindowPtr
GetSpriteWindow(DeviceIntPtr pDev)
2003-11-14 16:54:54 +01:00
{
return pDev->spriteInfo->sprite->win;
2003-11-14 16:54:54 +01:00
}
2007-04-13 05:38:44 +02:00
/**
* @return current sprite cursor.
*/
_X_EXPORT CursorPtr
GetSpriteCursor(DeviceIntPtr pDev)
2003-11-14 16:54:54 +01:00
{
return pDev->spriteInfo->sprite->current;
2003-11-14 16:54:54 +01:00
}
2007-04-13 05:38:44 +02:00
/**
* Set x/y current sprite position in screen coordinates.
*/
_X_EXPORT void
GetSpritePosition(DeviceIntPtr pDev, int *px, int *py)
2003-11-14 16:54:54 +01:00
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
*px = pSprite->hotPhys.x;
*py = pSprite->hotPhys.y;
2003-11-14 16:54:54 +01:00
}
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
_X_EXPORT int
XineramaGetCursorScreen(DeviceIntPtr pDev)
2003-11-14 17:49:22 +01:00
{
if(!noPanoramiXExtension) {
return pDev->spriteInfo->sprite->screen->myNum;
2003-11-14 17:49:22 +01:00
} else {
return 0;
}
}
#endif /* PANORAMIX */
2003-11-14 16:54:54 +01:00
#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */
static void
MonthChangedOrBadTime(xEvent *xE)
2003-11-14 16:54:54 +01:00
{
/* 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.
*/
2003-11-14 17:49:22 +01:00
if ((currentTime.milliseconds - XE_KBPTR.time) > TIMESLOP)
2003-11-14 16:54:54 +01:00
currentTime.months++;
else
2003-11-14 17:49:22 +01:00
XE_KBPTR.time = currentTime.milliseconds;
2003-11-14 16:54:54 +01:00
}
#define NoticeTime(xE) { \
if ((xE)->u.keyButtonPointer.time < currentTime.milliseconds) \
MonthChangedOrBadTime(xE); \
currentTime.milliseconds = (xE)->u.keyButtonPointer.time; \
lastDeviceEventTime = currentTime; }
void
NoticeEventTime(xEvent *xE)
2003-11-14 16:54:54 +01:00
{
if (!syncEvents.playingEvents)
NoticeTime(xE);
}
/**************************************************************************
* The following procedures deal with synchronous events *
**************************************************************************/
void
EnqueueEvent(xEvent *xE, DeviceIntPtr device, int count)
2003-11-14 16:54:54 +01:00
{
QdEventPtr tail = *syncEvents.pendtail;
QdEventPtr qe;
2003-11-14 16:54:54 +01:00
xEvent *qxE;
SpritePtr pSprite = device->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
NoticeTime(xE);
#ifdef XKB
/* Fix for key repeating bug. */
if (device->key != NULL && device->key->xkbInfo != NULL &&
xE->u.u.type == KeyRelease)
AccessXCancelRepeatKey(device->key->xkbInfo, xE->u.u.detail);
#endif
2003-11-14 16:54:54 +01:00
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)
2003-11-14 17:49:22 +01:00
XE_KBPTR.root =
WindowTable[pSprite->hotPhys.pScreen->myNum]->drawable.id;
2003-11-14 16:54:54 +01:00
eventinfo.events = xE;
eventinfo.count = count;
CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo);
}
if (xE->u.u.type == MotionNotify)
{
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension) {
XE_KBPTR.rootX += panoramiXdataPtr[pSprite->screen->myNum].x -
2003-11-14 17:49:22 +01:00
panoramiXdataPtr[0].x;
XE_KBPTR.rootY += panoramiXdataPtr[pSprite->screen->myNum].y -
2003-11-14 17:49:22 +01:00
panoramiXdataPtr[0].y;
}
#endif
pSprite->hotPhys.x = XE_KBPTR.rootX;
pSprite->hotPhys.y = XE_KBPTR.rootY;
2003-11-14 16:54:54 +01:00
/* do motion compression */
if (tail &&
(tail->event->u.u.type == MotionNotify) &&
(tail->pScreen == pSprite->hotPhys.pScreen))
2003-11-14 16:54:54 +01:00
{
tail->event->u.keyButtonPointer.rootX = pSprite->hotPhys.x;
tail->event->u.keyButtonPointer.rootY = pSprite->hotPhys.y;
2003-11-14 17:49:22 +01:00
tail->event->u.keyButtonPointer.time = XE_KBPTR.time;
2003-11-14 16:54:54 +01:00
tail->months = currentTime.months;
return;
}
}
qe = (QdEventPtr)xalloc(sizeof(QdEventRec) + (count * sizeof(xEvent)));
if (!qe)
return;
qe->next = (QdEventPtr)NULL;
qe->device = device;
qe->pScreen = pSprite->hotPhys.pScreen;
2003-11-14 16:54:54 +01:00
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
2003-11-14 17:49:22 +01:00
PlayReleasedEvents(void)
2003-11-14 16:54:54 +01:00
{
QdEventPtr *prev, qe;
DeviceIntPtr dev;
DeviceIntPtr pDev;
2003-11-14 16:54:54 +01:00
prev = &syncEvents.pending;
while ( (qe = *prev) )
{
if (!qe->device->deviceGrab.sync.frozen)
2003-11-14 16:54:54 +01:00
{
*prev = qe->next;
pDev = qe->device;
2003-11-14 16:54:54 +01:00
if (*syncEvents.pendtail == *prev)
syncEvents.pendtail = prev;
if (qe->event->u.u.type == MotionNotify)
CheckVirtualMotion(pDev, qe, NullWindow);
2003-11-14 16:54:54 +01:00
syncEvents.time.months = qe->months;
syncEvents.time.milliseconds = qe->event->u.keyButtonPointer.time;
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
/* Translate back to the sprite screen since processInputProc
will translate from sprite screen to screen 0 upon reentry
to the DIX layer */
if(!noPanoramiXExtension) {
qe->event->u.keyButtonPointer.rootX +=
panoramiXdataPtr[0].x -
panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].x;
2003-11-14 17:49:22 +01:00
qe->event->u.keyButtonPointer.rootY +=
panoramiXdataPtr[0].y -
panoramiXdataPtr[pDev->spriteInfo->sprite->screen->myNum].y;
2003-11-14 17:49:22 +01:00
}
#endif
2003-11-14 16:54:54 +01:00
(*qe->device->public.processInputProc)(qe->event, qe->device,
qe->evcount);
xfree(qe);
for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen; dev = dev->next)
2003-11-14 16:54:54 +01:00
;
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;
}
}
/**
* Freeze or thaw the given devices. The device's processing proc is
* switched to either the real processing proc (in case of thawing) or an
* enqueuing processing proc (usually EnqueueEvent()).
*
* @param dev The device to freeze/thaw
* @param frozen True to freeze or false to thaw.
*/
2003-11-14 16:54:54 +01:00
static void
FreezeThaw(DeviceIntPtr dev, Bool frozen)
2003-11-14 16:54:54 +01:00
{
dev->deviceGrab.sync.frozen = frozen;
2003-11-14 16:54:54 +01:00
if (frozen)
dev->public.processInputProc = dev->public.enqueueInputProc;
else
dev->public.processInputProc = dev->public.realInputProc;
}
/**
* Unfreeze devices and replay all events to the respective clients.
*
* ComputeFreezes takes the first event in the device's frozen event queue. It
* runs up the sprite tree (spriteTrace) and searches for the window to replay
* the events from. If it is found, it checks for passive grabs one down from
* the window or delivers the events.
*/
2003-11-14 16:54:54 +01:00
void
ComputeFreezes(void)
2003-11-14 16:54:54 +01:00
{
DeviceIntPtr replayDev = syncEvents.replayDev;
int i;
2003-11-14 16:54:54 +01:00
WindowPtr w;
xEvent *xE;
2003-11-14 16:54:54 +01:00
int count;
GrabPtr grab;
DeviceIntPtr dev;
2003-11-14 16:54:54 +01:00
for (dev = inputInfo.devices; dev; dev = dev->next)
FreezeThaw(dev, dev->deviceGrab.sync.other ||
(dev->deviceGrab.sync.state >= FROZEN));
2003-11-14 16:54:54 +01:00
if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending))
return;
syncEvents.playingEvents = TRUE;
if (replayDev)
{
xE = replayDev->deviceGrab.sync.event;
count = replayDev->deviceGrab.sync.evcount;
2003-11-14 16:54:54 +01:00
syncEvents.replayDev = (DeviceIntPtr)NULL;
2003-11-14 17:49:22 +01:00
w = XYToWindow(replayDev, XE_KBPTR.rootX, XE_KBPTR.rootY);
for (i = 0; i < replayDev->spriteInfo->sprite->spriteTraceGood; i++)
2003-11-14 17:49:22 +01:00
{
if (syncEvents.replayWin ==
replayDev->spriteInfo->sprite->spriteTrace[i])
2003-11-14 16:54:54 +01:00
{
2003-11-14 17:49:22 +01:00
if (!CheckDeviceGrabs(replayDev, xE, i+1, count)) {
2003-11-14 16:54:54 +01:00
if (replayDev->focus)
DeliverFocusedEvent(replayDev, xE, w, count);
else
DeliverDeviceEvents(w, xE, NullGrab, NullWindow,
2003-11-14 17:49:22 +01:00
replayDev, count);
}
2003-11-14 16:54:54 +01:00
goto playmore;
}
2003-11-14 17:49:22 +01:00
}
2003-11-14 16:54:54 +01:00
/* 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->deviceGrab.sync.frozen)
2003-11-14 16:54:54 +01:00
{
PlayReleasedEvents();
break;
}
}
syncEvents.playingEvents = FALSE;
for (dev = inputInfo.devices; dev; dev = dev->next)
2003-11-14 16:54:54 +01:00
{
if (DevHasCursor(dev))
{
/* the following may have been skipped during replay,
so do it now */
if ((grab = dev->deviceGrab.grab) && grab->confineTo)
{
if (grab->confineTo->drawable.pScreen !=
dev->spriteInfo->sprite->hotPhys.pScreen)
dev->spriteInfo->sprite->hotPhys.x =
dev->spriteInfo->sprite->hotPhys.y = 0;
ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE);
}
else
ConfineCursorToWindow(dev,
WindowTable[dev->spriteInfo->sprite->hotPhys.pScreen->myNum],
TRUE, FALSE);
PostNewCursor(dev);
}
2003-11-14 16:54:54 +01:00
}
}
2003-11-14 17:49:22 +01:00
#ifdef RANDR
void
ScreenRestructured (ScreenPtr pScreen)
{
GrabPtr grab;
DeviceIntPtr pDev;
2003-11-14 17:49:22 +01:00
for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
2003-11-14 17:49:22 +01:00
{
/* GrabDevice doesn't have a confineTo field, so we don't need to
* worry about it. */
if ((grab = pDev->deviceGrab.grab) && grab->confineTo)
{
if (grab->confineTo->drawable.pScreen
!= pDev->spriteInfo->sprite->hotPhys.pScreen)
pDev->spriteInfo->sprite->hotPhys.x = pDev->spriteInfo->sprite->hotPhys.y = 0;
ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE);
}
else
ConfineCursorToWindow(pDev,
WindowTable[pDev->spriteInfo->sprite->hotPhys.pScreen->myNum],
TRUE, FALSE);
2003-11-14 17:49:22 +01:00
}
}
#endif
2003-11-14 16:54:54 +01:00
void
CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode)
2003-11-14 16:54:54 +01:00
{
GrabPtr grab = thisDev->deviceGrab.grab;
DeviceIntPtr dev;
2003-11-14 16:54:54 +01:00
if (thisMode == GrabModeSync)
thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT;
2003-11-14 16:54:54 +01:00
else
{ /* free both if same client owns both */
thisDev->deviceGrab.sync.state = THAWED;
if (thisDev->deviceGrab.sync.other &&
(CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) ==
2003-11-14 16:54:54 +01:00
CLIENT_BITS(grab->resource)))
thisDev->deviceGrab.sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
}
for (dev = inputInfo.devices; dev; dev = dev->next)
{
if (dev != thisDev)
{
if (otherMode == GrabModeSync)
dev->deviceGrab.sync.other = grab;
2003-11-14 16:54:54 +01:00
else
{ /* free both if same client owns both */
if (dev->deviceGrab.sync.other &&
(CLIENT_BITS(dev->deviceGrab.sync.other->resource) ==
2003-11-14 16:54:54 +01:00
CLIENT_BITS(grab->resource)))
dev->deviceGrab.sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
}
}
}
ComputeFreezes();
}
2007-04-13 05:38:44 +02:00
/**
* Activate a pointer grab on the given device. A pointer grab will cause all
2007-05-30 10:14:31 +02:00
* core pointer events of this device to be delivered to the grabbing client only.
* No other device will send core events to the grab client while the grab is
* on, but core events will be sent to other clients.
* Can cause the cursor to change if a grab cursor is set.
2007-04-13 05:38:44 +02:00
*
* Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab
* is an implicit grab caused by a ButtonPress event.
2007-04-13 05:38:44 +02:00
*
* @param mouse The device to grab.
* @param grab The grab structure, needs to be setup.
* @param autoGrab True if the grab was caused by a button down event and not
* explicitely by a client.
*/
2003-11-14 16:54:54 +01:00
void
ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
TimeStamp time, Bool autoGrab)
2003-11-14 16:54:54 +01:00
{
GrabInfoPtr grabinfo = &mouse->deviceGrab;
WindowPtr oldWin = (grabinfo->grab) ?
grabinfo->grab->window
: mouse->spriteInfo->sprite->win;
2003-11-14 16:54:54 +01:00
if (grab->confineTo)
{
if (grab->confineTo->drawable.pScreen
!= mouse->spriteInfo->sprite->hotPhys.pScreen)
mouse->spriteInfo->sprite->hotPhys.x =
mouse->spriteInfo->sprite->hotPhys.y = 0;
ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE);
2003-11-14 16:54:54 +01:00
}
DoEnterLeaveEvents(mouse, oldWin, grab->window, NotifyGrab);
2003-11-14 16:54:54 +01:00
mouse->valuator->motionHintWindow = NullWindow;
if (syncEvents.playingEvents)
grabinfo->grabTime = syncEvents.time;
2003-11-14 16:54:54 +01:00
else
grabinfo->grabTime = time;
2003-11-14 16:54:54 +01:00
if (grab->cursor)
grab->cursor->refcnt++;
grabinfo->activeGrab = *grab;
grabinfo->grab = &grabinfo->activeGrab;
grabinfo->fromPassiveGrab = autoGrab & ~ImplicitGrabMask;
grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
PostNewCursor(mouse);
2003-11-14 17:49:22 +01:00
CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode);
2003-11-14 16:54:54 +01:00
}
2007-04-13 05:38:44 +02:00
/**
* Delete grab on given device, update the sprite.
*
2007-05-30 10:14:31 +02:00
* Extension devices are set up for ActivateKeyboardGrab().
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
void
DeactivatePointerGrab(DeviceIntPtr mouse)
2003-11-14 16:54:54 +01:00
{
GrabPtr grab = mouse->deviceGrab.grab;
DeviceIntPtr dev;
2003-11-14 16:54:54 +01:00
mouse->valuator->motionHintWindow = NullWindow;
mouse->deviceGrab.grab = NullGrab;
mouse->deviceGrab.sync.state = NOT_GRABBED;
mouse->deviceGrab.fromPassiveGrab = FALSE;
2003-11-14 16:54:54 +01:00
for (dev = inputInfo.devices; dev; dev = dev->next)
{
if (dev->deviceGrab.sync.other == grab)
dev->deviceGrab.sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
}
DoEnterLeaveEvents(mouse, grab->window,
mouse->spriteInfo->sprite->win, NotifyUngrab);
2003-11-14 16:54:54 +01:00
if (grab->confineTo)
ConfineCursorToWindow(mouse, RootWindow(mouse), FALSE, FALSE);
PostNewCursor(mouse);
2003-11-14 16:54:54 +01:00
if (grab->cursor)
FreeCursor(grab->cursor, (Cursor)0);
ComputeFreezes();
}
2007-04-13 05:38:44 +02:00
/**
* Activate a keyboard grab on the given device.
*
* Extension devices have ActivateKeyboardGrab() set as their grabbing proc.
*/
2003-11-14 16:54:54 +01:00
void
ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool passive)
2003-11-14 16:54:54 +01:00
{
GrabInfoPtr grabinfo = &keybd->deviceGrab;
2003-11-14 16:54:54 +01:00
WindowPtr oldWin;
if (grabinfo->grab)
oldWin = grabinfo->grab->window;
2003-11-14 16:54:54 +01:00
else if (keybd->focus)
oldWin = keybd->focus->win;
else
oldWin = keybd->spriteInfo->sprite->win;
2003-11-14 16:54:54 +01:00
if (oldWin == FollowKeyboardWin)
oldWin = inputInfo.keyboard->focus->win;
if (keybd->valuator)
keybd->valuator->motionHintWindow = NullWindow;
DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab);
if (syncEvents.playingEvents)
grabinfo->grabTime = syncEvents.time;
2003-11-14 16:54:54 +01:00
else
grabinfo->grabTime = time;
grabinfo->activeGrab = *grab;
grabinfo->grab = &grabinfo->activeGrab;
grabinfo->fromPassiveGrab = passive;
2003-11-14 17:49:22 +01:00
CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode);
2003-11-14 16:54:54 +01:00
}
2007-04-13 05:38:44 +02:00
/**
* Delete keyboard grab for the given device.
*/
2003-11-14 16:54:54 +01:00
void
DeactivateKeyboardGrab(DeviceIntPtr keybd)
2003-11-14 16:54:54 +01:00
{
GrabPtr grab = keybd->deviceGrab.grab;
DeviceIntPtr dev;
WindowPtr focusWin = keybd->focus ? keybd->focus->win
: keybd->spriteInfo->sprite->win;
2003-11-14 16:54:54 +01:00
if (!grab)
grab = keybd->deviceGrab.grab;
2003-11-14 16:54:54 +01:00
if (focusWin == FollowKeyboardWin)
focusWin = inputInfo.keyboard->focus->win;
if (keybd->valuator)
keybd->valuator->motionHintWindow = NullWindow;
keybd->deviceGrab.grab = NullGrab;
keybd->deviceGrab.sync.state = NOT_GRABBED;
keybd->deviceGrab.fromPassiveGrab = FALSE;
2003-11-14 16:54:54 +01:00
for (dev = inputInfo.devices; dev; dev = dev->next)
{
if (dev->deviceGrab.sync.other == grab)
dev->deviceGrab.sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
}
DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab);
ComputeFreezes();
}
void
AllowSome(ClientPtr client,
TimeStamp time,
DeviceIntPtr thisDev,
int newState,
Bool core)
2003-11-14 16:54:54 +01:00
{
Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced;
TimeStamp grabTime;
DeviceIntPtr dev;
GrabInfoPtr devgrabinfo,
grabinfo = &thisDev->deviceGrab;
2003-11-14 16:54:54 +01:00
thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client);
2003-11-14 16:54:54 +01:00
thisSynced = FALSE;
otherGrabbed = FALSE;
othersFrozen = TRUE;
grabTime = grabinfo->grabTime;
2003-11-14 16:54:54 +01:00
for (dev = inputInfo.devices; dev; dev = dev->next)
{
devgrabinfo = &dev->deviceGrab;
2003-11-14 16:54:54 +01:00
if (dev == thisDev)
continue;
if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client))
2003-11-14 16:54:54 +01:00
{
if (!(thisGrabbed || otherGrabbed) ||
(CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER))
grabTime = devgrabinfo->grabTime;
2003-11-14 16:54:54 +01:00
otherGrabbed = TRUE;
if (grabinfo->sync.other == devgrabinfo->grab)
2003-11-14 16:54:54 +01:00
thisSynced = TRUE;
if (devgrabinfo->sync.state < FROZEN)
2003-11-14 16:54:54 +01:00
othersFrozen = FALSE;
}
else if (!devgrabinfo->sync.other || !SameClient(devgrabinfo->sync.other, client))
2003-11-14 16:54:54 +01:00
othersFrozen = FALSE;
}
if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced))
2003-11-14 16:54:54 +01:00
return;
if ((CompareTimeStamps(time, currentTime) == LATER) ||
(CompareTimeStamps(time, grabTime) == EARLIER))
return;
switch (newState)
{
case THAWED: /* Async */
if (thisGrabbed)
grabinfo->sync.state = THAWED;
2003-11-14 16:54:54 +01:00
if (thisSynced)
grabinfo->sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
ComputeFreezes();
break;
case FREEZE_NEXT_EVENT: /* Sync */
if (thisGrabbed)
{
grabinfo->sync.state = FREEZE_NEXT_EVENT;
2003-11-14 16:54:54 +01:00
if (thisSynced)
grabinfo->sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
ComputeFreezes();
}
break;
case THAWED_BOTH: /* AsyncBoth */
if (othersFrozen)
{
for (dev = inputInfo.devices; dev; dev = dev->next)
{
devgrabinfo = &dev->deviceGrab;
if (devgrabinfo->grab
&& SameClient(devgrabinfo->grab, client))
devgrabinfo->sync.state = THAWED;
if (devgrabinfo->sync.other &&
SameClient(devgrabinfo->sync.other, client))
devgrabinfo->sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
}
ComputeFreezes();
}
break;
case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */
if (othersFrozen)
{
for (dev = inputInfo.devices; dev; dev = dev->next)
{
devgrabinfo = &dev->deviceGrab;
if (devgrabinfo->grab
&& SameClient(devgrabinfo->grab, client))
devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT;
if (devgrabinfo->sync.other
&& SameClient(devgrabinfo->sync.other, client))
devgrabinfo->sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
}
ComputeFreezes();
}
break;
case NOT_GRABBED: /* Replay */
if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT)
2003-11-14 16:54:54 +01:00
{
if (thisSynced)
grabinfo->sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
syncEvents.replayDev = thisDev;
syncEvents.replayWin = grabinfo->grab->window;
(*grabinfo->DeactivateGrab)(thisDev);
2003-11-14 16:54:54 +01:00
syncEvents.replayDev = (DeviceIntPtr)NULL;
}
break;
case THAW_OTHERS: /* AsyncOthers */
if (othersFrozen)
{
for (dev = inputInfo.devices; dev; dev = dev->next)
{
if (dev == thisDev)
continue;
devgrabinfo = (core) ? &dev->deviceGrab : &dev->deviceGrab;
if (devgrabinfo->grab
&& SameClient(devgrabinfo->grab, client))
devgrabinfo->sync.state = THAWED;
if (devgrabinfo->sync.other
&& SameClient(devgrabinfo->sync.other, client))
devgrabinfo->sync.other = NullGrab;
2003-11-14 16:54:54 +01:00
}
ComputeFreezes();
}
break;
}
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for AllowEvents request.
*
2007-05-30 10:14:31 +02:00
* Release some events from a frozen device.
*
* In some cases, the grab the client has is not on the ClientPointer but on
* some other device (see ProcGrabPointer comments). To cover this case, we
* need to run through all devices to ensure we don't forget the device we
* actually have a grab on.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcAllowEvents(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
TimeStamp time;
DeviceIntPtr mouse = NULL,
grabbed;
DeviceIntPtr keybd = NULL;
GrabPtr grab;
2003-11-14 16:54:54 +01:00
REQUEST(xAllowEventsReq);
REQUEST_SIZE_MATCH(xAllowEventsReq);
time = ClientTimeToServerTime(stuff->time);
for (grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
{
grab = grabbed->deviceGrab.grab;
if (grab && grab->coreGrab && SameClient(grab, client))
{
if (IsPointerDevice(grabbed))
mouse = grabbed;
else if (IsKeyboardDevice(grabbed))
keybd = grabbed;
if (mouse && keybd)
break;
}
}
if (!mouse)
mouse = PickPointer(client);
if (!keybd)
keybd = PickKeyboard(client);
2003-11-14 16:54:54 +01:00
switch (stuff->mode)
{
case ReplayPointer:
AllowSome(client, time, mouse, NOT_GRABBED, True);
2003-11-14 16:54:54 +01:00
break;
case SyncPointer:
AllowSome(client, time, mouse, FREEZE_NEXT_EVENT, True);
2003-11-14 16:54:54 +01:00
break;
case AsyncPointer:
AllowSome(client, time, mouse, THAWED, True);
2003-11-14 16:54:54 +01:00
break;
case ReplayKeyboard:
AllowSome(client, time, keybd, NOT_GRABBED, True);
2003-11-14 16:54:54 +01:00
break;
case SyncKeyboard:
AllowSome(client, time, keybd, FREEZE_NEXT_EVENT, True);
2003-11-14 16:54:54 +01:00
break;
case AsyncKeyboard:
AllowSome(client, time, keybd, THAWED, True);
2003-11-14 16:54:54 +01:00
break;
case SyncBoth:
AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT, True);
2003-11-14 16:54:54 +01:00
break;
case AsyncBoth:
AllowSome(client, time, keybd, THAWED_BOTH, True);
2003-11-14 16:54:54 +01:00
break;
default:
client->errorValue = stuff->mode;
return BadValue;
}
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* Deactivate grabs from any device that has been grabbed by the client.
*/
2003-11-14 16:54:54 +01:00
void
ReleaseActiveGrabs(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
DeviceIntPtr dev;
2003-11-14 16:54:54 +01:00
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->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client))
{
(*dev->deviceGrab.DeactivateGrab)(dev);
done = FALSE;
}
if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client))
2003-11-14 16:54:54 +01:00
{
(*dev->deviceGrab.DeactivateGrab)(dev);
2003-11-14 16:54:54 +01:00
done = FALSE;
}
}
} while (!done);
}
/**************************************************************************
* The following procedures deal with delivering events *
**************************************************************************/
2007-04-13 05:38:44 +02:00
/**
* Deliver the given events to the given client.
*
* More than one event may be delivered at a time. This is the case with
* DeviceMotionNotifies which may be followed by DeviceValuator events.
*
* TryClientEvents() is the last station before actually writing the events to
* the socket. Anything that is not filtered here, will get delivered to the
* client.
* An event is only delivered if
* - mask and filter match up.
* - no other client has a grab on the device that caused the event.
*
*
* @param client The target client to deliver to.
* @param pEvents The events to be delivered.
* @param count Number of elements in pEvents.
* @param mask Event mask as set by the window.
* @param filter Mask based on event type.
* @param grab Possible grab on the device that caused the event.
*
* @return 1 if event was delivered, 0 if not or -1 if grab was not set by the
* client.
*/
_X_EXPORT int
TryClientEvents (ClientPtr client, xEvent *pEvents, int count, Mask mask,
Mask filter, GrabPtr grab)
2003-11-14 16:54:54 +01:00
{
int i;
int type;
#ifdef DEBUG_EVENTS
ErrorF("Event([%d, %d], mask=0x%x), client=%d",
2003-11-14 16:54:54 +01:00
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_EVENTS
ErrorF("\n");
ErrorF("motionHintWindow == keyButtonPointer.event\n");
2003-11-14 16:54:54 +01:00
#endif
return 1; /* don't send, but pretend we did */
}
pEvents->u.u.detail = NotifyHint;
}
else
{
pEvents->u.u.detail = NotifyNormal;
}
}
#ifdef XINPUT
else
{
if ((type == DeviceMotionNotify) &&
2003-11-14 17:49:22 +01:00
MaybeSendDeviceMotionNotifyHint
((deviceKeyButtonPointer*)pEvents, mask) != 0)
2003-11-14 16:54:54 +01:00
return 1;
}
#endif
type &= 0177;
if (type != KeymapNotify)
{
/* all extension events must have a sequence number */
for (i = 0; i < count; i++)
pEvents[i].u.u.sequenceNumber = client->sequence;
}
if (BitIsOn(criticalEvents, type))
2003-11-14 17:49:22 +01:00
{
#ifdef SMART_SCHEDULE
if (client->smart_priority < SMART_MAX_PRIORITY)
client->smart_priority++;
#endif
2003-11-14 16:54:54 +01:00
SetCriticalOutputPending();
2003-11-14 17:49:22 +01:00
}
2003-11-14 16:54:54 +01:00
WriteEventsToClient(client, count, pEvents);
#ifdef DEBUG_EVENTS
ErrorF( " delivered\n");
2003-11-14 16:54:54 +01:00
#endif
return 1;
}
else
{
#ifdef DEBUG_EVENTS
ErrorF("\n");
2003-11-14 16:54:54 +01:00
#endif
return 0;
}
}
2007-04-13 05:38:44 +02:00
/**
* Deliver events to a window. At this point, we do not yet know if the event
* actually needs to be delivered. May activate a grab if the event is a
* button press.
*
* Core events are always delivered to the window owner. If the filter is
* something other than CantBeFiltered, the event is also delivered to other
* clients with the matching mask on the window.
2007-04-13 05:38:44 +02:00
*
* More than one event may be delivered at a time. This is the case with
* DeviceMotionNotifies which may be followed by DeviceValuator events.
*
* @param pWin The window that would get the event.
* @param pEvents The events to be delivered.
* @param count Number of elements in pEvents.
* @param filter Mask based on event type.
* @param grab Possible grab on the device that caused the event.
* @param mskidx Mask index, depending on device that caused event.
*
* @return Number of events delivered to various clients.
*/
2003-11-14 16:54:54 +01:00
int
DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
*pEvents, int count, Mask filter, GrabPtr grab, int mskidx)
2003-11-14 16:54:54 +01:00
{
int deliveries = 0, nondeliveries = 0;
int attempt;
InputClients *other;
2003-11-14 16:54:54 +01:00
ClientPtr client = NullClient;
2003-11-14 17:49:22 +01:00
Mask deliveryMask = 0; /* If a grab occurs due to a button press, then
2003-11-14 16:54:54 +01:00
this mask is the mask of the grab. */
int type = pEvents->u.u.type;
/* if a is denied, we return 0. This could cause the caller to
* traverse the parent. May be bad! (whot) */
if (!ACDeviceAllowed(pWin, pDev, pEvents))
{
return 0;
}
2003-11-14 16:54:54 +01:00
/* CantBeFiltered means only window owner gets the event */
if ((filter == CantBeFiltered) ||
(!(type & EXTENSION_EVENT_BASE) && type != GenericEvent))
2003-11-14 16:54:54 +01:00
{
/* if nobody ever wants to see this event, skip some work */
if (filter != CantBeFiltered &&
!((wOtherEventMasks(pWin)|pWin->eventMask) & filter))
return 0;
if (!(type & EXTENSION_EVENT_BASE) &&
IsInterferingGrab(wClient(pWin), pDev, pEvents))
return 0;
2003-11-14 16:54:54 +01:00
if ( (attempt = TryClientEvents(wClient(pWin), pEvents, count,
pWin->eventMask, filter, grab)) )
{
if (attempt > 0)
{
deliveries++;
client = wClient(pWin);
deliveryMask = pWin->eventMask;
} else
nondeliveries--;
}
}
if (filter != CantBeFiltered)
{
/* Handle generic events */
if (type == GenericEvent)
{
GenericMaskPtr pClient;
/* We don't do more than one GenericEvent at a time. */
if (count > 1)
{
ErrorF("Do not send more than one GenericEvent at a time!\n");
return 0;
}
2003-11-14 16:54:54 +01:00
/* if we get here, filter should be set to the GE specific mask.
check if any client wants it */
if (!GEMaskIsSet(pWin, GEEXT(pEvents), filter))
return 0;
/* run through all clients, deliver event */
for (pClient = GECLIENT(pWin); pClient; pClient = pClient->next)
{
if (pClient->eventMask[GEEXTIDX(pEvents)] & filter)
{
if (TryClientEvents(pClient->client, pEvents, count,
pClient->eventMask[GEEXTIDX(pEvents)], filter, grab) > 0)
{
deliveries++;
} else
nondeliveries--;
}
}
}
else {
/* Traditional event */
if (type & EXTENSION_EVENT_BASE)
{
OtherInputMasks *inputMasks;
inputMasks = wOtherInputMasks(pWin);
if (!inputMasks ||
!(inputMasks->inputEvents[mskidx] & filter))
return 0;
other = inputMasks->inputClients;
}
else
other = (InputClients *)wOtherClients(pWin);
for (; other; other = other->next)
{
/* core event? check for grab interference */
if (!(type & EXTENSION_EVENT_BASE) &&
IsInterferingGrab(rClient(other), pDev, pEvents))
continue;
if ( (attempt = TryClientEvents(rClient(other), pEvents, count,
other->mask[mskidx], filter, grab)) )
{
if (attempt > 0)
{
deliveries++;
client = rClient(other);
deliveryMask = other->mask[mskidx];
} else
nondeliveries--;
}
}
}
2003-11-14 16:54:54 +01:00
}
if ((type == ButtonPress) && deliveries && (!grab))
{
GrabRec tempGrab;
OtherInputMasks *inputMasks;
2003-11-14 16:54:54 +01:00
tempGrab.next = NULL;
tempGrab.device = pDev;
2003-11-14 16:54:54 +01:00
tempGrab.resource = client->clientAsMask;
tempGrab.window = pWin;
tempGrab.ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE;
tempGrab.eventMask = deliveryMask;
tempGrab.keyboardMode = GrabModeAsync;
tempGrab.pointerMode = GrabModeAsync;
tempGrab.confineTo = NullWindow;
tempGrab.cursor = NullCursor;
tempGrab.coreGrab = True;
/* get the XI device mask */
inputMasks = wOtherInputMasks(pWin);
tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[pDev->id]: 0;
/* get the XGE event mask.
* FIXME: needs to be freed somewhere too.
*/
tempGrab.genericMasks = NULL;
if (pWin->optional && pWin->optional->geMasks)
{
GenericClientMasksPtr gemasks = pWin->optional->geMasks;
GenericMaskPtr geclient = gemasks->geClients;
while(geclient && geclient->client != client)
geclient = geclient->next;
if (geclient)
{
tempGrab.genericMasks = xcalloc(1, sizeof(GenericMaskRec));
*tempGrab.genericMasks = *geclient;
tempGrab.genericMasks->next = NULL;
}
}
(*inputInfo.pointer->deviceGrab.ActivateGrab)(pDev, &tempGrab,
currentTime,
TRUE | ImplicitGrabMask);
2003-11-14 16:54:54 +01:00
}
else if ((type == MotionNotify) && deliveries)
pDev->valuator->motionHintWindow = pWin;
2003-11-14 16:54:54 +01:00
#ifdef XINPUT
else
{
if (((type == DeviceMotionNotify)
#ifdef XKB
|| (type == DeviceButtonPress)
#endif
) && deliveries)
2003-11-14 17:49:22 +01:00
CheckDeviceGrabAndHintWindow (pWin, type,
(deviceKeyButtonPointer*) pEvents,
grab, client, deliveryMask);
2003-11-14 16:54:54 +01:00
}
#endif
if (deliveries)
return deliveries;
return nondeliveries;
}
/* If the event goes to dontClient, don't send it and return 0. if
send works, return 1 or if send didn't work, return 2.
Only works for core events.
*/
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
static int
XineramaTryClientEventsResult(
ClientPtr client,
GrabPtr grab,
Mask mask,
Mask filter
){
if ((client) && (client != serverClient) && (!client->clientGone) &&
((filter == CantBeFiltered) || (mask & filter)))
{
if (grab && !SameClient(grab, client)) return -1;
else return 1;
}
return 0;
}
#endif
2007-04-13 05:38:44 +02:00
/**
* Try to deliver events to the interested parties.
*
* @param pWin The window that would get the event.
* @param pEvents The events to be delivered.
* @param count Number of elements in pEvents.
* @param filter Mask based on event type.
* @param dontClient Don't deliver to the dontClient.
*/
2003-11-14 16:54:54 +01:00
int
MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents,
int count, Mask filter, ClientPtr dontClient)
2003-11-14 16:54:54 +01:00
{
OtherClients *other;
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
2003-11-14 16:54:54 +01:00
if (pWin->eventMask & filter)
{
if (wClient(pWin) == dontClient)
return 0;
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
return XineramaTryClientEventsResult(
wClient(pWin), NullGrab, pWin->eventMask, filter);
#endif
2003-11-14 16:54:54 +01:00
return TryClientEvents(wClient(pWin), pEvents, count,
pWin->eventMask, filter, NullGrab);
}
for (other = wOtherClients(pWin); other; other = other->next)
{
if (other->mask & filter)
{
if (SameClient(other, dontClient))
return 0;
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
return XineramaTryClientEventsResult(
rClient(other), NullGrab, other->mask, filter);
#endif
2003-11-14 16:54:54 +01:00
return TryClientEvents(rClient(other), pEvents, count,
other->mask, filter, NullGrab);
}
}
return 2;
}
2007-04-13 05:38:44 +02:00
/**
* Adjust event fields to comply with the window properties.
*
* @param xE Event to be modified in place
* @param pWin The window to get the information from.
* @param child Child window setting for event (if applicable)
* @param calcChild If True, calculate the child window.
*/
2003-11-14 16:54:54 +01:00
static void
2003-11-14 17:49:22 +01:00
FixUpEventFromWindow(
DeviceIntPtr pDev,
2003-11-14 17:49:22 +01:00
xEvent *xE,
WindowPtr pWin,
Window child,
Bool calcChild)
2003-11-14 16:54:54 +01:00
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
if (xE->u.u.type == GenericEvent) /* just a safety barrier */
return;
2003-11-14 16:54:54 +01:00
if (calcChild)
{
WindowPtr w= pSprite->spriteTrace[pSprite->spriteTraceGood-1];
2003-11-14 16:54:54 +01:00
/* If the search ends up past the root should the child field be
set to none or should the value in the argument be passed
through. It probably doesn't matter since everyone calls
this function with child == None anyway. */
while (w)
{
/* If the source window is same as event window, child should be
none. Don't bother going all all the way back to the root. */
if (w == pWin)
{
child = None;
break;
}
if (w->parent == pWin)
{
child = w->drawable.id;
break;
}
w = w->parent;
}
}
XE_KBPTR.root = RootWindow(pDev)->drawable.id;
2003-11-14 17:49:22 +01:00
XE_KBPTR.event = pWin->drawable.id;
if (pSprite->hot.pScreen == pWin->drawable.pScreen)
2003-11-14 16:54:54 +01:00
{
2003-11-14 17:49:22 +01:00
XE_KBPTR.sameScreen = xTrue;
XE_KBPTR.child = child;
XE_KBPTR.eventX =
XE_KBPTR.rootX - pWin->drawable.x;
XE_KBPTR.eventY =
XE_KBPTR.rootY - pWin->drawable.y;
2003-11-14 16:54:54 +01:00
}
else
{
2003-11-14 17:49:22 +01:00
XE_KBPTR.sameScreen = xFalse;
XE_KBPTR.child = None;
XE_KBPTR.eventX = 0;
XE_KBPTR.eventY = 0;
2003-11-14 16:54:54 +01:00
}
}
2007-04-13 05:38:44 +02:00
/**
* Deliver events caused by input devices. Called for all core input events
* and XI events. No filtering of events happens before DeliverDeviceEvents(),
* it will be called for any event that comes out of the event queue.
*
* @param pWin Window to deliver event to.
* @param xE Events to deliver.
* @param grab Possible grab on a device.
* @param stopAt Don't recurse up to the root window.
* @param dev The device that is responsible for the event.
* @param count number of events in xE.
*
*/
2003-11-14 16:54:54 +01:00
int
DeliverDeviceEvents(WindowPtr pWin, xEvent *xE, GrabPtr grab,
WindowPtr stopAt, DeviceIntPtr dev, int count)
2003-11-14 16:54:54 +01:00
{
Window child = None;
int type = xE->u.u.type;
Mask filter = filters[type];
int deliveries = 0;
if (type & EXTENSION_EVENT_BASE)
{
OtherInputMasks *inputMasks;
2003-11-14 16:54:54 +01:00
int mskidx = dev->id;
2003-11-14 16:54:54 +01:00
inputMasks = wOtherInputMasks(pWin);
if (inputMasks && !(filter & inputMasks->deliverableEvents[mskidx]))
return 0;
while (pWin)
{
if (inputMasks && (inputMasks->inputEvents[mskidx] & filter))
{
FixUpEventFromWindow(dev, xE, pWin, child, FALSE);
deliveries = DeliverEventsToWindow(dev, pWin, xE, count, filter,
2003-11-14 16:54:54 +01:00
grab, mskidx);
if (deliveries > 0)
return deliveries;
}
if ((deliveries < 0) ||
(pWin == stopAt) ||
(inputMasks &&
(filter & inputMasks->dontPropagateMask[mskidx])))
return 0;
child = pWin->drawable.id;
pWin = pWin->parent;
if (pWin)
inputMasks = wOtherInputMasks(pWin);
}
}
else
{
/* handle generic events */
if (type == GenericEvent)
{
xGenericEvent* ge = (xGenericEvent*)xE;
if (count > 1)
{
ErrorF("Do not send more than one GenericEvent at a time!\n");
return 0;
}
filter = generic_filters[GEEXTIDX(xE)][ge->evtype];
while(pWin)
{
if (GEMaskIsSet(pWin, GEEXT(xE), filter))
{
if (GEExtensions[GEEXTIDX(xE)].evfill)
GEExtensions[GEEXTIDX(xE)].evfill(ge, dev, pWin, grab);
deliveries = DeliverEventsToWindow(dev, pWin, xE, count,
filter, grab, 0);
if (deliveries > 0)
return deliveries;
}
pWin = pWin->parent;
}
}
else
{
/* core protocol events */
if (!(filter & pWin->deliverableEvents))
return 0;
while (pWin)
{
if ((wOtherEventMasks(pWin)|pWin->eventMask) & filter)
{
FixUpEventFromWindow(dev, xE, pWin, child, FALSE);
deliveries = DeliverEventsToWindow(dev, pWin, xE, count, filter,
grab, 0);
if (deliveries > 0)
return deliveries;
}
if ((deliveries < 0) ||
(pWin == stopAt) ||
(filter & wDontPropagateMask(pWin)))
return 0;
child = pWin->drawable.id;
pWin = pWin->parent;
}
2003-11-14 16:54:54 +01:00
}
}
return 0;
}
2007-04-13 05:38:44 +02:00
/**
* Deliver event to a window and it's immediate parent. Used for most window
* events (CreateNotify, ConfigureNotify, etc.). Not useful for events that
* propagate up the tree or extension events
*
* In case of a ReparentNotify event, the event will be delivered to the
* otherParent as well.
*
* @param pWin Window to deliver events to.
* @param xE Events to deliver.
* @param count number of events in xE.
* @param otherParent Used for ReparentNotify events.
*/
_X_EXPORT int
DeliverEvents(WindowPtr pWin, xEvent *xE, int count,
WindowPtr otherParent)
2003-11-14 16:54:54 +01:00
{
Mask filter;
int deliveries;
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
return count;
#endif
2003-11-14 16:54:54 +01:00
if (!count)
return 0;
filter = filters[xE->u.u.type];
if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify))
xE->u.destroyNotify.event = pWin->drawable.id;
if (filter != StructureAndSubMask)
return DeliverEventsToWindow(inputInfo.pointer, pWin, xE, count, filter, NullGrab, 0);
deliveries = DeliverEventsToWindow(inputInfo.pointer, pWin, xE, count, StructureNotifyMask,
2003-11-14 16:54:54 +01:00
NullGrab, 0);
if (pWin->parent)
{
xE->u.destroyNotify.event = pWin->parent->drawable.id;
deliveries += DeliverEventsToWindow(inputInfo.pointer, pWin->parent, xE, count,
2003-11-14 16:54:54 +01:00
SubstructureNotifyMask, NullGrab,
0);
if (xE->u.u.type == ReparentNotify)
{
xE->u.destroyNotify.event = otherParent->drawable.id;
deliveries += DeliverEventsToWindow(inputInfo.pointer,
otherParent, xE, count, SubstructureNotifyMask,
2003-11-14 16:54:54 +01:00
NullGrab, 0);
}
}
return deliveries;
}
2003-11-14 17:49:22 +01:00
static Bool
PointInBorderSize(WindowPtr pWin, int x, int y)
{
BoxRec box;
SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite;
2003-11-14 17:49:22 +01:00
if(POINT_IN_REGION(pWin->drawable.pScreen, &pWin->borderSize, x, y, &box))
return TRUE;
#ifdef PANORAMIX
if(!noPanoramiXExtension &&
XineramaSetWindowPntrs(inputInfo.pointer, pWin)) {
2003-11-14 17:49:22 +01:00
int i;
for(i = 1; i < PanoramiXNumScreens; i++) {
if(POINT_IN_REGION(pSprite->screen,
&pSprite->windows[i]->borderSize,
2003-11-14 17:49:22 +01:00
x + panoramiXdataPtr[0].x - panoramiXdataPtr[i].x,
y + panoramiXdataPtr[0].y - panoramiXdataPtr[i].y,
&box))
return TRUE;
}
}
#endif
return FALSE;
}
2007-04-13 05:38:44 +02:00
/**
* Traversed from the root window to the window at the position x/y. While
* traversing, it sets up the traversal history in the spriteTrace array.
* After completing, the spriteTrace history is set in the following way:
* spriteTrace[0] ... root window
* spriteTrace[1] ... top level window that encloses x/y
* ...
* spriteTrace[spriteTraceGood - 1] ... window at x/y
*
* @returns the window at the given coordinates.
*/
2003-11-14 16:54:54 +01:00
static WindowPtr
XYToWindow(DeviceIntPtr pDev, int x, int y)
2003-11-14 16:54:54 +01:00
{
WindowPtr pWin;
BoxRec box;
SpritePtr pSprite;
2003-11-14 16:54:54 +01:00
pSprite = pDev->spriteInfo->sprite;
pSprite->spriteTraceGood = 1; /* root window still there */
pWin = RootWindow(pDev)->firstChild;
2003-11-14 16:54:54 +01:00
while (pWin)
{
if ((pWin->mapped) &&
(x >= pWin->drawable.x - wBorderWidth (pWin)) &&
(x < pWin->drawable.x + (int)pWin->drawable.width +
wBorderWidth(pWin)) &&
(y >= pWin->drawable.y - wBorderWidth (pWin)) &&
(y < pWin->drawable.y + (int)pWin->drawable.height +
wBorderWidth (pWin))
2003-11-14 16:54:54 +01:00
#ifdef SHAPE
/* When a window is shaped, a further check
* is made to see if the point is inside
* borderSize
*/
&& (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y))
&& (!wInputShape(pWin) ||
POINT_IN_REGION(pWin->drawable.pScreen,
wInputShape(pWin),
x - pWin->drawable.x,
y - pWin->drawable.y, &box))
#endif
)
2003-11-14 16:54:54 +01:00
{
if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize)
2003-11-14 16:54:54 +01:00
{
pSprite->spriteTraceSize += 10;
2003-11-14 16:54:54 +01:00
Must_have_memory = TRUE; /* XXX */
pSprite->spriteTrace = (WindowPtr *)xrealloc(
pSprite->spriteTrace,
pSprite->spriteTraceSize*sizeof(WindowPtr));
2003-11-14 16:54:54 +01:00
Must_have_memory = FALSE; /* XXX */
}
pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin;
2003-11-14 16:54:54 +01:00
pWin = pWin->firstChild;
}
else
pWin = pWin->nextSib;
}
return pSprite->spriteTrace[pSprite->spriteTraceGood-1];
2003-11-14 16:54:54 +01:00
}
2007-04-13 05:38:44 +02:00
/**
* 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
* cursor and send enter/leave events.
*
* CheckMotion() will not do anything and return FALSE if the event is not a
* pointer event.
*
* @return TRUE if the sprite has moved or FALSE otherwise.
2007-04-13 05:38:44 +02:00
*/
Bool
CheckMotion(xEvent *xE, DeviceIntPtr pDev)
2003-11-14 16:54:54 +01:00
{
INT16 *rootX, *rootY;
WindowPtr prevSpriteWin;
SpritePtr pSprite = pDev->spriteInfo->sprite;
prevSpriteWin = pSprite->win;
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension)
return XineramaCheckMotion(xE, pDev);
2003-11-14 17:49:22 +01:00
#endif
2003-11-14 16:54:54 +01:00
if (xE && !syncEvents.playingEvents)
{
/* GetPointerEvents() guarantees that pointer events have the correct
rootX/Y set already. */
switch(xE->u.u.type)
{
case ButtonPress:
case ButtonRelease:
case MotionNotify:
rootX = &XE_KBPTR.rootX;
rootY = &XE_KBPTR.rootY;
break;
default:
if (xE->u.u.type == DeviceButtonPress ||
xE->u.u.type == DeviceButtonRelease ||
xE->u.u.type == DeviceMotionNotify)
{
rootX = &((deviceKeyButtonPointer*)xE)->root_x;
rootY = &((deviceKeyButtonPointer*)xE)->root_y;
break;
}
/* all other events return FALSE */
return FALSE;
}
if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen)
{
pSprite->hot.pScreen = pSprite->hotPhys.pScreen;
RootWindow(pDev) = WindowTable[pSprite->hot.pScreen->myNum];
}
pSprite->hot.x = *rootX;
pSprite->hot.y = *rootY;
if (pSprite->hot.x < pSprite->physLimits.x1)
pSprite->hot.x = pSprite->physLimits.x1;
else if (pSprite->hot.x >= pSprite->physLimits.x2)
pSprite->hot.x = pSprite->physLimits.x2 - 1;
if (pSprite->hot.y < pSprite->physLimits.y1)
pSprite->hot.y = pSprite->physLimits.y1;
else if (pSprite->hot.y >= pSprite->physLimits.y2)
pSprite->hot.y = pSprite->physLimits.y2 - 1;
2003-11-14 16:54:54 +01:00
#ifdef SHAPE
if (pSprite->hotShape)
ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y);
#endif
#ifdef XEVIE
xeviehot.x = pSprite->hot.x;
xeviehot.y = pSprite->hot.y;
2003-11-14 16:54:54 +01:00
#endif
pSprite->hotPhys = pSprite->hot;
if ((pSprite->hotPhys.x != *rootX) ||
(pSprite->hotPhys.y != *rootY))
2003-11-14 17:49:22 +01:00
{
(*pSprite->hotPhys.pScreen->SetCursorPosition)(
pDev, pSprite->hotPhys.pScreen,
pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE);
2003-11-14 17:49:22 +01:00
}
*rootX = pSprite->hot.x;
*rootY = pSprite->hot.y;
2003-11-14 16:54:54 +01:00
}
#ifdef XEVIE
xeviewin =
#endif
pSprite->win = XYToWindow(pDev, pSprite->hot.x, pSprite->hot.y);
2003-11-14 16:54:54 +01:00
#ifdef notyet
if (!(pSprite->win->deliverableEvents &
Motion_Filter(pDev->button))
2003-11-14 16:54:54 +01:00
!syncEvents.playingEvents)
{
/* XXX Do PointerNonInterestBox here */
}
#endif
if (pSprite->win != prevSpriteWin)
2003-11-14 16:54:54 +01:00
{
if (prevSpriteWin != NullWindow) {
if (!xE)
UpdateCurrentTimeIf();
DoEnterLeaveEvents(pDev, prevSpriteWin, pSprite->win,
NotifyNormal);
}
PostNewCursor(pDev);
2003-11-14 16:54:54 +01:00
return FALSE;
}
return TRUE;
}
2007-04-13 05:38:44 +02:00
/**
* Windows have restructured, we need to update the sprite position and the
* sprite's cursor.
*/
_X_EXPORT void
WindowsRestructured(void)
2003-11-14 16:54:54 +01:00
{
DeviceIntPtr pDev = inputInfo.devices;
while(pDev)
{
if (DevHasCursor(pDev))
CheckMotion((xEvent *)NULL, pDev);
pDev = pDev->next;
}
2003-11-14 16:54:54 +01:00
}
#ifdef PANORAMIX
/* This was added to support reconfiguration under Xdmx. The problem is
* that if the 0th screen (i.e., WindowTable[0]) is moved to an origin
* other than 0,0, the information in the private sprite structure must
* be updated accordingly, or XYToWindow (and other routines) will not
* compute correctly. */
void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff)
{
GrabPtr grab;
DeviceIntPtr pDev;
SpritePtr pSprite;
if (noPanoramiXExtension) return;
pDev = inputInfo.devices;
while(pDev)
{
if (DevHasCursor(pDev))
{
pSprite = pDev->spriteInfo->sprite;
pSprite->hot.x -= xoff;
pSprite->hot.y -= yoff;
pSprite->hotPhys.x -= xoff;
pSprite->hotPhys.y -= yoff;
pSprite->hotLimits.x1 -= xoff;
pSprite->hotLimits.y1 -= yoff;
pSprite->hotLimits.x2 -= xoff;
pSprite->hotLimits.y2 -= yoff;
if (REGION_NOTEMPTY(pSprite->screen, &pSprite->Reg1))
REGION_TRANSLATE(pSprite->screen, &pSprite->Reg1, xoff, yoff);
if (REGION_NOTEMPTY(pSprite->screen, &pSprite->Reg2))
REGION_TRANSLATE(pSprite->screen, &pSprite->Reg2, xoff, yoff);
/* FIXME: if we call ConfineCursorToWindow, must we do anything else? */
if ((grab = pDev->deviceGrab.grab) && grab->confineTo) {
if (grab->confineTo->drawable.pScreen
!= pSprite->hotPhys.pScreen)
pSprite->hotPhys.x = pSprite->hotPhys.y = 0;
ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE);
} else
ConfineCursorToWindow(
pDev,
WindowTable[pSprite->hotPhys.pScreen->myNum],
TRUE, FALSE);
}
pDev = pDev->next;
}
}
#endif
2007-04-13 05:38:44 +02:00
/**
2007-05-30 10:14:31 +02:00
* Called from main() with the root window on the first screen. Used to do a
* lot more when MPX wasn't around yet. Things change.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
void
DefineInitialRootWindow(WindowPtr win)
2003-11-14 16:54:54 +01:00
{
#ifdef XEVIE
xeviewin = win;
#endif
}
2007-05-30 10:14:31 +02:00
/**
* Initialize a sprite for the given device and set it to some sane values. If
* the device already has a sprite alloc'd, don't realloc but just reset to
* default values.
* If a window is supplied, the sprite will be initialized with the window's
* cursor and positioned in the center of the window's screen. The root window
* is a good choice to pass in here.
*
* It's a good idea to call it only for pointer devices, unless you have a
* really talented keyboard.
*
* @param pDev The device to initialize.
* @param pWin The window where to generate the sprite in.
*
*/
void
InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin)
{
SpritePtr pSprite;
ScreenPtr pScreen;
if (!pDev->spriteInfo->sprite)
{
DeviceIntPtr it;
pDev->spriteInfo->sprite = (SpritePtr)xcalloc(1, sizeof(SpriteRec));
if (!pDev->spriteInfo->sprite)
FatalError("InitializeSprite: failed to allocate sprite struct");
/* We may have paired another device with this device before our
* device had a actual sprite. We need to check for this and reset the
* sprite field for all paired devices.
*
* The VCK is always paired with the VCP before the VCP has a sprite.
*/
for (it = inputInfo.devices; it; it = it->next)
{
if (it->spriteInfo->paired == pDev)
it->spriteInfo->sprite = pDev->spriteInfo->sprite;
}
if (inputInfo.keyboard->spriteInfo->paired == pDev)
inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite;
}
2003-11-14 17:49:22 +01:00
pSprite = pDev->spriteInfo->sprite;
pDev->spriteInfo->spriteOwner = TRUE;
pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr)NULL;
pSprite->hot.pScreen = pScreen;
pSprite->hotPhys.pScreen = pScreen;
if (pScreen)
{
pSprite->hotPhys.x = pScreen->width / 2;
pSprite->hotPhys.y = pScreen->height / 2;
pSprite->hotLimits.x2 = pScreen->width;
pSprite->hotLimits.y2 = pScreen->height;
}
pSprite->hot = pSprite->hotPhys;
pSprite->win = pWin;
if (pWin)
{
pSprite->current = wCursor(pWin);
pSprite->current->refcnt++;
pSprite->spriteTrace = (WindowPtr *)xcalloc(1, 32*sizeof(WindowPtr));
if (!pSprite->spriteTrace)
FatalError("Failed to allocate spriteTrace");
pSprite->spriteTraceSize = 32;
RootWindow(pDev) = pWin;
pSprite->spriteTraceGood = 1;
pSprite->pEnqueueScreen = pScreen;
pSprite->pDequeueScreen = pSprite->pEnqueueScreen;
} else {
pSprite->current = NullCursor;
pSprite->spriteTrace = NULL;
pSprite->spriteTraceSize = 0;
pSprite->spriteTraceGood = 0;
pSprite->pEnqueueScreen = screenInfo.screens[0];
pSprite->pDequeueScreen = pSprite->pEnqueueScreen;
}
if (pScreen)
{
(*pScreen->CursorLimits) ( pDev, pScreen, pSprite->current,
&pSprite->hotLimits, &pSprite->physLimits);
pSprite->confined = FALSE;
(*pScreen->ConstrainCursor) (pDev, pScreen,
&pSprite->physLimits);
(*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x,
pSprite->hot.y,
FALSE);
(*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current);
}
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension) {
pSprite->hotLimits.x1 = -panoramiXdataPtr[0].x;
pSprite->hotLimits.y1 = -panoramiXdataPtr[0].y;
pSprite->hotLimits.x2 = PanoramiXPixWidth - panoramiXdataPtr[0].x;
pSprite->hotLimits.y2 = PanoramiXPixHeight - panoramiXdataPtr[0].y;
pSprite->physLimits = pSprite->hotLimits;
pSprite->confineWin = NullWindow;
#ifdef SHAPE
pSprite->hotShape = NullRegion;
#endif
pSprite->screen = pScreen;
/* gotta UNINIT these someplace */
REGION_NULL(pScreen, &pSprite->Reg1);
REGION_NULL(pScreen, &pSprite->Reg2);
2003-11-14 17:49:22 +01:00
}
#endif
2003-11-14 16:54:54 +01:00
}
/*
* This does not take any shortcuts, and even ignores its argument, since
* it does not happen very often, and one has to walk up the tree since
* this might be a newly instantiated cursor for an intermediate window
* between the one the pointer is in and the one that the last cursor was
* instantiated from.
*/
void
WindowHasNewCursor(WindowPtr pWin)
2003-11-14 16:54:54 +01:00
{
DeviceIntPtr pDev;
for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
if (DevHasCursor(pDev))
PostNewCursor(pDev);
2003-11-14 16:54:54 +01:00
}
_X_EXPORT void
NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y)
2003-11-14 16:54:54 +01:00
{
SpritePtr pSprite = pDev->spriteInfo->sprite;
pSprite->hotPhys.x = x;
pSprite->hotPhys.y = y;
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension) {
pSprite->hotPhys.x += panoramiXdataPtr[newScreen->myNum].x -
2003-11-14 17:49:22 +01:00
panoramiXdataPtr[0].x;
pSprite->hotPhys.y += panoramiXdataPtr[newScreen->myNum].y -
2003-11-14 17:49:22 +01:00
panoramiXdataPtr[0].y;
if (newScreen != pSprite->screen) {
pSprite->screen = newScreen;
2003-11-14 17:49:22 +01:00
/* Make sure we tell the DDX to update its copy of the screen */
if(pSprite->confineWin)
XineramaConfineCursorToWindow(pDev,
pSprite->confineWin, TRUE);
2003-11-14 17:49:22 +01:00
else
XineramaConfineCursorToWindow(pDev, WindowTable[0], TRUE);
2003-11-14 17:49:22 +01:00
/* if the pointer wasn't confined, the DDX won't get
told of the pointer warp so we reposition it here */
if(!syncEvents.playingEvents)
(*pSprite->screen->SetCursorPosition)(
pDev,
pSprite->screen,
pSprite->hotPhys.x + panoramiXdataPtr[0].x -
panoramiXdataPtr[pSprite->screen->myNum].x,
pSprite->hotPhys.y + panoramiXdataPtr[0].y -
panoramiXdataPtr[pSprite->screen->myNum].y, FALSE);
2003-11-14 17:49:22 +01:00
}
} else
#endif
if (newScreen != pSprite->hotPhys.pScreen)
ConfineCursorToWindow(pDev, WindowTable[newScreen->myNum],
TRUE, FALSE);
2003-11-14 16:54:54 +01:00
}
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
static Bool
XineramaPointInWindowIsVisible(
WindowPtr pWin,
int x,
int y
)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
BoxRec box;
int i, xoff, yoff;
if (!pWin->realized) return FALSE;
if (POINT_IN_REGION(pScreen, &pWin->borderClip, x, y, &box))
return TRUE;
if(!XineramaSetWindowPntrs(inputInfo.pointer, pWin)) return FALSE;
2003-11-14 17:49:22 +01:00
xoff = x + panoramiXdataPtr[0].x;
yoff = y + panoramiXdataPtr[0].y;
for(i = 1; i < PanoramiXNumScreens; i++) {
pWin = inputInfo.pointer->spriteInfo->sprite->windows[i];
2003-11-14 17:49:22 +01:00
pScreen = pWin->drawable.pScreen;
x = xoff - panoramiXdataPtr[i].x;
y = yoff - panoramiXdataPtr[i].y;
if(POINT_IN_REGION(pScreen, &pWin->borderClip, x, y, &box)
&& (!wInputShape(pWin) ||
POINT_IN_REGION(pWin->drawable.pScreen,
wInputShape(pWin),
x - pWin->drawable.x,
y - pWin->drawable.y, &box)))
2003-11-14 17:49:22 +01:00
return TRUE;
}
return FALSE;
}
static int
XineramaWarpPointer(ClientPtr client)
{
WindowPtr dest = NULL;
int x, y, rc;
SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
2003-11-14 17:49:22 +01:00
REQUEST(xWarpPointerReq);
if (stuff->dstWid != None) {
rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 17:49:22 +01:00
}
x = pSprite->hotPhys.x;
y = pSprite->hotPhys.y;
2003-11-14 17:49:22 +01:00
if (stuff->srcWid != None)
{
int winX, winY;
XID winID = stuff->srcWid;
WindowPtr source;
rc = dixLookupWindow(&source, winID, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 17:49:22 +01:00
winX = source->drawable.x;
winY = source->drawable.y;
if(source == WindowTable[0]) {
winX -= panoramiXdataPtr[0].x;
winY -= panoramiXdataPtr[0].y;
}
if (x < winX + stuff->srcX ||
y < winY + stuff->srcY ||
(stuff->srcWidth != 0 &&
winX + stuff->srcX + (int)stuff->srcWidth < x) ||
(stuff->srcHeight != 0 &&
winY + stuff->srcY + (int)stuff->srcHeight < y) ||
!XineramaPointInWindowIsVisible(source, x, y))
return Success;
}
if (dest) {
x = dest->drawable.x;
y = dest->drawable.y;
if(dest == WindowTable[0]) {
x -= panoramiXdataPtr[0].x;
y -= panoramiXdataPtr[0].y;
}
}
x += stuff->dstX;
y += stuff->dstY;
if (x < pSprite->physLimits.x1)
x = pSprite->physLimits.x1;
else if (x >= pSprite->physLimits.x2)
x = pSprite->physLimits.x2 - 1;
if (y < pSprite->physLimits.y1)
y = pSprite->physLimits.y1;
else if (y >= pSprite->physLimits.y2)
y = pSprite->physLimits.y2 - 1;
if (pSprite->hotShape)
ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y);
2003-11-14 17:49:22 +01:00
XineramaSetCursorPosition(PickPointer(client), x, y, TRUE);
2003-11-14 17:49:22 +01:00
return Success;
}
#endif
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for WarpPointer request.
* Warps the cursor position to the coordinates given in the request.
*/
2003-11-14 16:54:54 +01:00
int
ProcWarpPointer(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
WindowPtr dest = NULL;
int x, y, rc;
2003-11-14 16:54:54 +01:00
ScreenPtr newScreen;
SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
REQUEST(xWarpPointerReq);
REQUEST_SIZE_MATCH(xWarpPointerReq);
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension)
return XineramaWarpPointer(client);
#endif
if (stuff->dstWid != None) {
rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
}
x = pSprite->hotPhys.x;
y = pSprite->hotPhys.y;
2003-11-14 17:49:22 +01:00
2003-11-14 16:54:54 +01:00
if (stuff->srcWid != None)
{
int winX, winY;
2003-11-14 17:49:22 +01:00
XID winID = stuff->srcWid;
WindowPtr source;
rc = dixLookupWindow(&source, winID, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 17:49:22 +01:00
2003-11-14 16:54:54 +01:00
winX = source->drawable.x;
winY = source->drawable.y;
if (source->drawable.pScreen != pSprite->hotPhys.pScreen ||
2003-11-14 16:54:54 +01:00
x < winX + stuff->srcX ||
y < winY + stuff->srcY ||
(stuff->srcWidth != 0 &&
winX + stuff->srcX + (int)stuff->srcWidth < x) ||
(stuff->srcHeight != 0 &&
winY + stuff->srcY + (int)stuff->srcHeight < y) ||
!PointInWindowIsVisible(source, x, y))
return Success;
}
2003-11-14 17:49:22 +01:00
if (dest)
2003-11-14 16:54:54 +01:00
{
x = dest->drawable.x;
y = dest->drawable.y;
newScreen = dest->drawable.pScreen;
2003-11-14 17:49:22 +01:00
} else
newScreen = pSprite->hotPhys.pScreen;
2003-11-14 17:49:22 +01:00
2003-11-14 16:54:54 +01:00
x += stuff->dstX;
y += stuff->dstY;
2003-11-14 17:49:22 +01:00
2003-11-14 16:54:54 +01:00
if (x < 0)
x = 0;
else if (x >= newScreen->width)
x = newScreen->width - 1;
if (y < 0)
y = 0;
else if (y >= newScreen->height)
y = newScreen->height - 1;
if (newScreen == pSprite->hotPhys.pScreen)
2003-11-14 16:54:54 +01:00
{
if (x < pSprite->physLimits.x1)
x = pSprite->physLimits.x1;
else if (x >= pSprite->physLimits.x2)
x = pSprite->physLimits.x2 - 1;
if (y < pSprite->physLimits.y1)
y = pSprite->physLimits.y1;
else if (y >= pSprite->physLimits.y2)
y = pSprite->physLimits.y2 - 1;
2003-11-14 17:49:22 +01:00
#if defined(SHAPE)
if (pSprite->hotShape)
ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y);
2003-11-14 16:54:54 +01:00
#endif
(*newScreen->SetCursorPosition)(PickPointer(client), newScreen, x, y,
TRUE);
2003-11-14 16:54:54 +01:00
}
else if (!PointerConfinedToScreen(PickPointer(client)))
2003-11-14 16:54:54 +01:00
{
NewCurrentScreen(PickPointer(client), newScreen, x, y);
2003-11-14 16:54:54 +01:00
}
return Success;
}
2003-11-14 17:49:22 +01:00
static Bool
BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin)
2003-11-14 17:49:22 +01:00
{
if(REGION_NOTEMPTY(pDev->spriteInfo->sprite->hotPhys.pScreen, &pWin->borderSize))
2003-11-14 17:49:22 +01:00
return TRUE;
#ifdef PANORAMIX
if(!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) {
2003-11-14 17:49:22 +01:00
int i;
for(i = 1; i < PanoramiXNumScreens; i++) {
if(REGION_NOTEMPTY(pDev->spriteInfo->sprite->screen,
&pDev->spriteInfo->sprite->windows[i]->borderSize))
2003-11-14 17:49:22 +01:00
return TRUE;
}
}
#endif
return FALSE;
}
2007-04-13 05:38:44 +02:00
/**
* "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a
* passive grab set on the window to be activated.
* If a passive grab is activated, the event will be delivered to the client.
2007-04-13 05:38:44 +02:00
*
* @param pWin The window that may be subject to a passive grab.
* @param device Device that caused the event.
* @param xE List of events (multiple ones for DeviceMotionNotify)
* @count number of elements in xE.
*/
2003-11-14 16:54:54 +01:00
static Bool
2003-11-14 17:49:22 +01:00
CheckPassiveGrabsOnWindow(
WindowPtr pWin,
DeviceIntPtr device,
xEvent *xE,
2003-11-14 17:49:22 +01:00
int count)
2003-11-14 16:54:54 +01:00
{
GrabPtr grab = wPassiveGrabs(pWin);
2003-11-14 16:54:54 +01:00
GrabRec tempGrab;
GrabInfoPtr grabinfo;
xEvent *dxE;
2003-11-14 16:54:54 +01:00
if (!grab)
return FALSE;
tempGrab.window = pWin;
tempGrab.device = device;
tempGrab.type = xE->u.u.type;
tempGrab.detail.exact = xE->u.u.detail;
tempGrab.detail.pMask = NULL;
tempGrab.modifiersDetail.pMask = NULL;
tempGrab.next = NULL;
2003-11-14 16:54:54 +01:00
for (; grab; grab = grab->next)
{
#ifdef XKB
DeviceIntPtr gdev;
XkbSrvInfoPtr xkbi;
gdev= grab->modifierDevice;
xkbi= gdev->key->xkbInfo;
#endif
tempGrab.modifierDevice = grab->modifierDevice;
if ((device == grab->modifierDevice) &&
((xE->u.u.type == KeyPress)
#if defined(XINPUT) && defined(XKB)
|| (xE->u.u.type == DeviceKeyPress)
2003-11-14 16:54:54 +01:00
#endif
))
tempGrab.modifiersDetail.exact =
#ifdef XKB
(noXkbExtension?gdev->key->prev_state:xkbi->state.grab_mods);
#else
grab->modifierDevice->key->prev_state;
#endif
else
tempGrab.modifiersDetail.exact =
#ifdef XKB
(noXkbExtension ? gdev->key->state : xkbi->state.grab_mods);
#else
grab->modifierDevice->key->state;
#endif
/* ignore the device for core events when comparing grabs */
if (GrabMatchesSecond(&tempGrab, grab, (xE->u.u.type < LASTEvent)) &&
2003-11-14 16:54:54 +01:00
(!grab->confineTo ||
2003-11-14 17:49:22 +01:00
(grab->confineTo->realized &&
BorderSizeNotEmpty(device, grab->confineTo))))
2003-11-14 16:54:54 +01:00
{
if (!XaceHook(XACE_DEVICE_ACCESS, wClient(pWin), device, FALSE))
2003-11-14 16:54:54 +01:00
return FALSE;
#ifdef XKB
if (!noXkbExtension) {
2003-11-14 17:49:22 +01:00
XE_KBPTR.state &= 0x1f00;
XE_KBPTR.state |=
2003-11-14 16:54:54 +01:00
tempGrab.modifiersDetail.exact&(~0x1f00);
}
#endif
grabinfo = &device->deviceGrab;
/* A passive grab may have been created for a different device
than it is assigned to at this point in time.
Update the grab's device and modifier device to reflect the
current state.
XXX: Since XGrabDeviceButton requires to specify the
modifierDevice explicitly, we don't override this choice.
This essentially requires a client to re-create all
passiveGrabs when the pairing changes... oh well.
*/
2007-08-08 07:30:02 +02:00
if (xE->u.u.type < LASTEvent)
{
grab->device = device;
grab->modifierDevice = GetPairedKeyboard(device);
if (!grab->modifierDevice)
grab->modifierDevice = inputInfo.keyboard;
}
(*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE);
2003-11-14 16:54:54 +01:00
FixUpEventFromWindow(device, xE, grab->window, None, TRUE);
2003-11-14 16:54:54 +01:00
(void) TryClientEvents(rClient(grab), xE, count,
filters[xE->u.u.type],
filters[xE->u.u.type], grab);
if (grabinfo->sync.state == FROZEN_NO_EVENT)
2003-11-14 16:54:54 +01:00
{
if (grabinfo->sync.evcount < count)
2003-11-14 16:54:54 +01:00
{
Must_have_memory = TRUE; /* XXX */
grabinfo->sync.event = (xEvent *)xrealloc(grabinfo->sync.event,
2003-11-14 16:54:54 +01:00
count*
sizeof(xEvent));
Must_have_memory = FALSE; /* XXX */
}
grabinfo->sync.evcount = count;
for (dxE = grabinfo->sync.event; --count >= 0; dxE++, xE++)
2003-11-14 16:54:54 +01:00
*dxE = *xE;
grabinfo->sync.state = FROZEN_WITH_EVENT;
2003-11-14 16:54:54 +01:00
}
return TRUE;
}
}
return FALSE;
}
/**
* CheckDeviceGrabs handles both keyboard and pointer events that may cause
* a passive grab to be activated.
*
* If the event is a keyboard event, the ancestors of the focus window are
* traced down and tried to see if they have any passive grabs to be
* activated. If the focus window itself is reached and it's descendants
* contain the pointer, the ancestors of the window that the pointer is in
* are then traced down starting at the focus window, otherwise no grabs are
* activated.
* If the event is a pointer event, the ancestors of the window that the
* pointer is in are traced down starting at the root until CheckPassiveGrabs
* causes a passive grab to activate or all the windows are
* tried. PRH
*
* If a grab is activated, the event has been sent to the client already!
*
* @param device The device that caused the event.
* @param xE The event to handle (most likely {Device}ButtonPress).
* @param count Number of events in list.
* @return TRUE if a grab has been activated or false otherwise.
2003-11-14 16:54:54 +01:00
*/
Bool
CheckDeviceGrabs(DeviceIntPtr device, xEvent *xE,
int checkFirst, int count)
2003-11-14 16:54:54 +01:00
{
int i;
WindowPtr pWin = NULL;
FocusClassPtr focus = device->focus;
2003-11-14 16:54:54 +01:00
if (((xE->u.u.type == ButtonPress)
#if defined(XINPUT) && defined(XKB)
|| (xE->u.u.type == DeviceButtonPress)
2003-11-14 16:54:54 +01:00
#endif
) && (device->button->buttonsDown != 1))
2003-11-14 16:54:54 +01:00
return FALSE;
i = checkFirst;
if (focus)
{
for (; i < focus->traceGood; i++)
{
pWin = focus->trace[i];
if (pWin->optional &&
CheckPassiveGrabsOnWindow(pWin, device, xE, count))
return TRUE;
}
if ((focus->win == NoneWin) ||
(i >= device->spriteInfo->sprite->spriteTraceGood) ||
((i > checkFirst) &&
(pWin != device->spriteInfo->sprite->spriteTrace[i-1])))
2003-11-14 16:54:54 +01:00
return FALSE;
}
2003-11-14 17:49:22 +01:00
for (; i < device->spriteInfo->sprite->spriteTraceGood; i++)
2003-11-14 16:54:54 +01:00
{
pWin = device->spriteInfo->sprite->spriteTrace[i];
2003-11-14 16:54:54 +01:00
if (pWin->optional &&
CheckPassiveGrabsOnWindow(pWin, device, xE, count))
return TRUE;
}
return FALSE;
}
2007-04-13 05:38:44 +02:00
/**
* Called for keyboard events to deliver event to whatever client owns the
* focus. Event is delivered to the keyboard's focus window, the root window
* or to the window owning the input focus.
*
* @param keybd The keyboard originating the event.
* @param xE The event list.
* @param window Window underneath the sprite.
* @param count number of events in xE.
*/
2003-11-14 16:54:54 +01:00
void
DeliverFocusedEvent(DeviceIntPtr keybd, xEvent *xE, WindowPtr window, int count)
2003-11-14 16:54:54 +01:00
{
DeviceIntPtr pointer;
2003-11-14 16:54:54 +01:00
WindowPtr focus = keybd->focus->win;
int mskidx = 0;
if (focus == FollowKeyboardWin)
focus = inputInfo.keyboard->focus->win;
if (!focus)
return;
if (focus == PointerRootWin)
{
DeliverDeviceEvents(window, xE, NullGrab, NullWindow, keybd, count);
return;
}
if ((focus == window) || IsParent(focus, window))
{
if (DeliverDeviceEvents(window, xE, NullGrab, focus, keybd, count))
return;
}
pointer = GetPairedPointer(keybd);
if (!pointer)
pointer = inputInfo.pointer;
2003-11-14 16:54:54 +01:00
/* just deliver it to the focus window */
FixUpEventFromWindow(pointer, xE, focus, None, FALSE);
2003-11-14 16:54:54 +01:00
if (xE->u.u.type & EXTENSION_EVENT_BASE)
mskidx = keybd->id;
(void)DeliverEventsToWindow(keybd, focus, xE, count, filters[xE->u.u.type],
2003-11-14 16:54:54 +01:00
NullGrab, mskidx);
}
2007-04-13 05:38:44 +02:00
/**
* Deliver an event from a device that is currently grabbed. Uses
* DeliverDeviceEvents() for further delivery if a ownerEvents is set on the
* grab. If not, TryClientEvents() is used.
*
* @param deactivateGrab True if the device's grab should be deactivated.
*/
2003-11-14 16:54:54 +01:00
void
DeliverGrabbedEvent(xEvent *xE, DeviceIntPtr thisDev,
Bool deactivateGrab, int count)
2003-11-14 16:54:54 +01:00
{
GrabPtr grab;
GrabInfoPtr grabinfo;
2003-11-14 16:54:54 +01:00
int deliveries = 0;
DeviceIntPtr dev;
xEvent *dxE;
SpritePtr pSprite = thisDev->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
grabinfo = &thisDev->deviceGrab;
grab = grabinfo->grab;
2003-11-14 16:54:54 +01:00
if (grab->ownerEvents)
{
WindowPtr focus;
if (thisDev->focus)
{
focus = thisDev->focus->win;
if (focus == FollowKeyboardWin)
focus = inputInfo.keyboard->focus->win;
}
else
focus = PointerRootWin;
if (focus == PointerRootWin)
deliveries = DeliverDeviceEvents(pSprite->win, xE, grab,
NullWindow, thisDev, count);
else if (focus && (focus == pSprite->win ||
IsParent(focus, pSprite->win)))
deliveries = DeliverDeviceEvents(pSprite->win, xE, grab, focus,
2003-11-14 16:54:54 +01:00
thisDev, count);
else if (focus)
deliveries = DeliverDeviceEvents(focus, xE, grab, focus,
thisDev, count);
}
if (!deliveries)
{
if (ACDeviceAllowed(grab->window, thisDev, xE))
{
if (xE->u.u.type == GenericEvent)
{
/* find evmask for event's extension */
xGenericEvent* ge = ((xGenericEvent*)xE);
GenericMaskPtr gemask = grab->genericMasks;
if (!gemask || !gemask->eventMask[GEEXTIDX(ge)])
return;
if (GEEventFill(xE))
GEEventFill(xE)(ge, thisDev, grab->window, grab);
deliveries = TryClientEvents(rClient(grab), xE, count,
gemask->eventMask[GEEXTIDX(ge)],
generic_filters[GEEXTIDX(ge)][ge->evtype],
grab);
} else
{
Mask mask = grab->eventMask;
if (grabinfo->fromPassiveGrab &&
grabinfo->implicitGrab &&
(xE->u.u.type & EXTENSION_EVENT_BASE))
mask = grab->deviceMask;
FixUpEventFromWindow(thisDev, xE, grab->window, None, TRUE);
if (!(!(xE->u.u.type & EXTENSION_EVENT_BASE) &&
IsInterferingGrab(rClient(grab), thisDev, xE)))
{
deliveries = TryClientEvents(rClient(grab), xE, count,
mask, filters[xE->u.u.type], grab);
}
}
if (deliveries && (xE->u.u.type == MotionNotify
2003-11-14 16:54:54 +01:00
#ifdef XINPUT
|| xE->u.u.type == DeviceMotionNotify
2003-11-14 16:54:54 +01:00
#endif
))
thisDev->valuator->motionHintWindow = grab->window;
}
2003-11-14 16:54:54 +01:00
}
if (deliveries && !deactivateGrab && (xE->u.u.type != MotionNotify
#ifdef XINPUT
&& xE->u.u.type != DeviceMotionNotify
#endif
))
switch (grabinfo->sync.state)
2003-11-14 16:54:54 +01:00
{
case FREEZE_BOTH_NEXT_EVENT:
for (dev = inputInfo.devices; dev; dev = dev->next)
{
if (dev == thisDev)
continue;
FreezeThaw(dev, TRUE);
if ((grabinfo->sync.state == FREEZE_BOTH_NEXT_EVENT) &&
(CLIENT_BITS(grab->resource) ==
CLIENT_BITS(grab->resource)))
grabinfo->sync.state = FROZEN_NO_EVENT;
2003-11-14 16:54:54 +01:00
else
grabinfo->sync.other = grab;
2003-11-14 16:54:54 +01:00
}
/* fall through */
case FREEZE_NEXT_EVENT:
grabinfo->sync.state = FROZEN_WITH_EVENT;
2003-11-14 16:54:54 +01:00
FreezeThaw(thisDev, TRUE);
if (grabinfo->sync.evcount < count)
2003-11-14 16:54:54 +01:00
{
Must_have_memory = TRUE; /* XXX */
grabinfo->sync.event = (xEvent *)xrealloc(grabinfo->sync.event,
2003-11-14 16:54:54 +01:00
count*sizeof(xEvent));
Must_have_memory = FALSE; /* XXX */
}
grabinfo->sync.evcount = count;
for (dxE = grabinfo->sync.event; --count >= 0; dxE++, xE++)
2003-11-14 16:54:54 +01:00
*dxE = *xE;
break;
}
}
2007-04-13 05:38:44 +02:00
/**
* Main keyboard event processing function for core keyboard events.
* Updates the events fields from the current pointer state and delivers the
* event.
*
* For key events, xE will always be a single event.
*
* @param xE Event list
* @param keybd The device that caused an event.
* @param count Number of elements in xE.
*/
2003-11-14 16:54:54 +01:00
void
#ifdef XKB
CoreProcessKeyboardEvent (xEvent *xE, DeviceIntPtr keybd, int count)
2003-11-14 16:54:54 +01:00
#else
ProcessKeyboardEvent (xEvent *xE, DeviceIntPtr keybd, int count)
2003-11-14 16:54:54 +01:00
#endif
{
int key, bit;
BYTE *kptr;
int i;
CARD8 modifiers;
CARD16 mask;
GrabPtr grab;
GrabInfoPtr grabinfo;
2003-11-14 16:54:54 +01:00
Bool deactivateGrab = FALSE;
KeyClassPtr keyc = keybd->key;
#ifdef XEVIE
static Window rootWin = 0;
if(!xeviegrabState && xevieFlag && clients[xevieClientIndex] &&
(xevieMask & xevieFilters[xE->u.u.type])) {
key = xE->u.u.detail;
kptr = &keyc->down[key >> 3];
bit = 1 << (key & 7);
if((xE->u.u.type == KeyPress && (*kptr & bit)) ||
(xE->u.u.type == KeyRelease && !(*kptr & bit)))
{} else {
#ifdef XKB
if(!noXkbExtension)
xevieKBEventSent = 1;
#endif
if(!xevieKBEventSent)
{
xeviekb = keybd;
if(!rootWin) {
rootWin = GetCurrentRootWindow(keybd)->drawable.id;
}
xE->u.keyButtonPointer.event = xeviewin->drawable.id;
xE->u.keyButtonPointer.root = rootWin;
xE->u.keyButtonPointer.child = (xeviewin->firstChild) ? xeviewin->firstChild->
drawable.id:0;
xE->u.keyButtonPointer.rootX = xeviehot.x;
xE->u.keyButtonPointer.rootY = xeviehot.y;
xE->u.keyButtonPointer.state = keyc->state;
WriteToClient(clients[xevieClientIndex], sizeof(xEvent), (char *)xE);
#ifdef XKB
if(noXkbExtension)
#endif
return;
} else {
xevieKBEventSent = 0;
}
}
}
#endif
2003-11-14 16:54:54 +01:00
if (xE->u.u.type & EXTENSION_EVENT_BASE)
grabinfo = &keybd->deviceGrab;
else
grabinfo = &keybd->deviceGrab;
grab = grabinfo->grab;
2003-11-14 16:54:54 +01:00
if (!syncEvents.playingEvents)
{
NoticeTime(xE);
if (DeviceEventCallback)
{
DeviceEventInfoRec eventinfo;
eventinfo.events = xE;
eventinfo.count = count;
CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo);
}
}
#ifdef XEVIE
/* fix for bug5094030: don't change the state bit if the event is from XEvIE client */
if(!(!xeviegrabState && xevieFlag && clients[xevieClientIndex] &&
(xevieMask & xevieFilters[xE->u.u.type]
#ifdef XKB
&& !noXkbExtension
#endif
)))
#endif
/* ProcessOtherEvent already updated the keyboard's state, so we need to
* access prev_state here! */
XE_KBPTR.state = (keyc->prev_state | GetPairedPointer(keybd)->button->state);
XE_KBPTR.rootX = keybd->spriteInfo->sprite->hot.x;
XE_KBPTR.rootY = keybd->spriteInfo->sprite->hot.y;
2003-11-14 16:54:54 +01:00
key = xE->u.u.detail;
kptr = &keyc->down[key >> 3];
bit = 1 << (key & 7);
modifiers = keyc->modifierMap[key];
2005-06-15 18:46:59 +02:00
#if defined(XKB) && defined(XEVIE)
if(!noXkbExtension && !xeviegrabState &&
xevieFlag && clients[xevieClientIndex] &&
(xevieMask & xevieFilters[xE->u.u.type])) {
switch(xE->u.u.type) {
case KeyPress: *kptr &= ~bit; break;
case KeyRelease: *kptr |= bit; break;
}
}
#endif
2003-11-14 16:54:54 +01:00
switch (xE->u.u.type)
{
case KeyPress:
/* We MUST NOT change the device itself here. All device state
* changes must be performed in ProcessOtherEvents. We're dealing
* with the same device struct, so if we change it in POE and
* here, we've just screwed up the state by setting it twice.
*
* Devices may not send core events but always send XI events, so
* the state must be changed in POE, not here.
*/
2003-11-14 16:54:54 +01:00
if (!grab && CheckDeviceGrabs(keybd, xE, 0, count))
{
grabinfo->activatingKey = key;
2003-11-14 16:54:54 +01:00
return;
}
break;
case KeyRelease:
if (!(*kptr & bit)) /* guard against duplicates */
return;
/* No device state changes, see comment for KeyPress */
if (grabinfo->fromPassiveGrab && (key == grabinfo->activatingKey))
2003-11-14 16:54:54 +01:00
deactivateGrab = TRUE;
break;
default:
FatalError("Impossible keyboard event");
}
if (grab)
DeliverGrabbedEvent(xE, keybd, deactivateGrab, count);
else
DeliverFocusedEvent(keybd, xE, keybd->spriteInfo->sprite->win, count);
2003-11-14 16:54:54 +01:00
if (deactivateGrab)
(*grabinfo->DeactivateGrab)(keybd);
XaceHook(XACE_KEY_AVAIL, xE, keybd, count);
2003-11-14 16:54:54 +01:00
}
2003-11-14 17:49:22 +01:00
#ifdef XKB
/* This function is used to set the key pressed or key released state -
this is only used when the pressing of keys does not cause
CoreProcessKeyEvent to be called, as in for example Mouse Keys.
*/
void
FixKeyState (xEvent *xE, DeviceIntPtr keybd)
2003-11-14 17:49:22 +01:00
{
int key, bit;
BYTE *kptr;
KeyClassPtr keyc = keybd->key;
2003-11-14 17:49:22 +01:00
key = xE->u.u.detail;
kptr = &keyc->down[key >> 3];
bit = 1 << (key & 7);
if (((xE->u.u.type==KeyPress)||(xE->u.u.type==KeyRelease))) {
DebugF("FixKeyState: Key %d %s\n",key,
2003-11-14 17:49:22 +01:00
(xE->u.u.type==KeyPress?"down":"up"));
}
2003-11-14 17:49:22 +01:00
switch (xE->u.u.type)
{
case KeyPress:
*kptr |= bit;
break;
case KeyRelease:
*kptr &= ~bit;
break;
default:
FatalError("Impossible keyboard event");
}
}
#endif
2007-04-13 05:38:44 +02:00
/**
* Main pointer event processing function for core pointer events.
* For motion events: update the sprite.
* For all other events: Update the event fields based on the current sprite
* state.
*
* For core pointer events, xE will always be a single event.
*
* @param xE Event list
* @param mouse The device that caused an event.
* @param count Number of elements in xE.
*/
2003-11-14 16:54:54 +01:00
void
#ifdef XKB
CoreProcessPointerEvent (xEvent *xE, DeviceIntPtr mouse, int count)
2003-11-14 16:54:54 +01:00
#else
ProcessPointerEvent (xEvent *xE, DeviceIntPtr mouse, int count)
2003-11-14 16:54:54 +01:00
#endif
{
GrabPtr grab = mouse->deviceGrab.grab;
2003-11-14 16:54:54 +01:00
Bool deactivateGrab = FALSE;
ButtonClassPtr butc = mouse->button;
SpritePtr pSprite = mouse->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
#ifdef XKB
XkbSrvInfoPtr xkbi= inputInfo.keyboard->key->xkbInfo;
#endif
#ifdef XEVIE
if(xevieFlag && clients[xevieClientIndex] && !xeviegrabState &&
(xevieMask & xevieFilters[xE->u.u.type])) {
if(xevieEventSent)
xevieEventSent = 0;
else {
xeviemouse = mouse;
WriteToClient(clients[xevieClientIndex], sizeof(xEvent), (char *)xE);
return;
}
}
#endif
2003-11-14 16:54:54 +01:00
if (!syncEvents.playingEvents)
NoticeTime(xE)
2003-11-14 17:49:22 +01:00
XE_KBPTR.state = (butc->state | (
2003-11-14 16:54:54 +01:00
#ifdef XKB
(noXkbExtension ?
inputInfo.keyboard->key->state :
xkbi->state.grab_mods)
#else
inputInfo.keyboard->key->state
#endif
));
{
NoticeTime(xE);
if (DeviceEventCallback)
{
DeviceEventInfoRec eventinfo;
/* see comment in EnqueueEvents regarding the next three lines */
if (xE->u.u.type == MotionNotify)
2003-11-14 17:49:22 +01:00
XE_KBPTR.root =
WindowTable[pSprite->hotPhys.pScreen->myNum]->drawable.id;
2003-11-14 16:54:54 +01:00
eventinfo.events = xE;
eventinfo.count = count;
CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo);
}
}
/* We need to call CheckMotion for each event. It doesn't really give us
any benefit for relative devices, but absolute devices may not send
button events to the right position otherwise. */
if (!CheckMotion(xE, mouse) && xE->u.u.type == MotionNotify)
return;
2003-11-14 16:54:54 +01:00
if (xE->u.u.type != MotionNotify)
{
int key;
BYTE *kptr;
2003-11-14 16:54:54 +01:00
int bit;
XE_KBPTR.rootX = pSprite->hot.x;
XE_KBPTR.rootY = pSprite->hot.y;
2003-11-14 17:49:22 +01:00
2003-11-14 16:54:54 +01:00
key = xE->u.u.detail;
kptr = &butc->down[key >> 3];
bit = 1 << (key & 7);
switch (xE->u.u.type)
{
case ButtonPress:
/*
* We rely on the fact that ButtonMotionMask is the same as
* DeviceButtonMotionMask, so setting the motionMask
* to this value ensures correctness for both XI and core events.
*/
2003-11-14 16:54:54 +01:00
if (xE->u.u.detail == 0)
return;
filters[MotionNotify] = Motion_Filter(butc);
if (!grab)
if (CheckDeviceGrabs(mouse, xE, 0, count))
return;
break;
case ButtonRelease:
if (xE->u.u.detail == 0)
return;
filters[MotionNotify] = Motion_Filter(butc);
if (!butc->state && mouse->deviceGrab.fromPassiveGrab)
2003-11-14 16:54:54 +01:00
deactivateGrab = TRUE;
break;
default:
FatalError("bogus pointer event from ddx");
}
}
2003-11-14 16:54:54 +01:00
if (grab)
DeliverGrabbedEvent(xE, mouse, deactivateGrab, count);
else
DeliverDeviceEvents(pSprite->win, xE, NullGrab, NullWindow,
2003-11-14 16:54:54 +01:00
mouse, count);
if (deactivateGrab)
(*mouse->deviceGrab.DeactivateGrab)(mouse);
2003-11-14 16:54:54 +01:00
}
#define AtMostOneClient \
(SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask)
2007-04-13 05:38:44 +02:00
/**
* Recalculate which events may be deliverable for the given window.
* Recalculated mask is used for quicker determination which events may be
* delivered to a window.
*
* The otherEventMasks on a WindowOptional is the combination of all event
* masks set by all clients on the window.
* deliverableEventMask is the combination of the eventMask and the
* otherEventMask.
*
* Traverses to siblings and parents of the window.
*/
2003-11-14 16:54:54 +01:00
void
RecalculateDeliverableEvents(pWin)
WindowPtr pWin;
2003-11-14 16:54:54 +01:00
{
OtherClients *others;
WindowPtr pChild;
2003-11-14 16:54:54 +01:00
pChild = pWin;
while (1)
{
if (pChild->optional)
{
pChild->optional->otherEventMasks = 0;
for (others = wOtherClients(pChild); others; others = others->next)
{
pChild->optional->otherEventMasks |= others->mask;
}
}
pChild->deliverableEvents = pChild->eventMask|
wOtherEventMasks(pChild);
if (pChild->parent)
pChild->deliverableEvents |=
(pChild->parent->deliverableEvents &
~wDontPropagateMask(pChild) & PropagateMask);
if (pChild->firstChild)
{
pChild = pChild->firstChild;
continue;
}
while (!pChild->nextSib && (pChild != pWin))
pChild = pChild->parent;
if (pChild == pWin)
break;
pChild = pChild->nextSib;
}
}
/**
*
* \param value must conform to DeleteType
*/
2003-11-14 16:54:54 +01:00
int
OtherClientGone(pointer value, XID id)
2003-11-14 16:54:54 +01:00
{
OtherClientsPtr other, prev;
WindowPtr pWin = (WindowPtr)value;
2003-11-14 16:54:54 +01:00
prev = 0;
for (other = wOtherClients(pWin); other; other = other->next)
{
if (other->resource == id)
{
if (prev)
prev->next = other->next;
else
{
if (!(pWin->optional->otherClients = other->next))
CheckWindowOptionalNeed (pWin);
}
xfree(other);
RecalculateDeliverableEvents(pWin);
return(Success);
}
prev = other;
}
FatalError("client not on event list");
/*NOTREACHED*/
return -1; /* make compiler happy */
}
int
EventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask)
2003-11-14 16:54:54 +01:00
{
Mask check;
OtherClients * others;
if (mask & ~AllEventMasks)
{
client->errorValue = mask;
return BadValue;
}
check = (mask & AtMostOneClient);
if (check & (pWin->eventMask|wOtherEventMasks(pWin)))
{ /* It is illegal for two different
clients to select on any of the
events for AtMostOneClient. However,
it is OK, for some client to
continue selecting on one of those
events. */
if ((wClient(pWin) != client) && (check & pWin->eventMask))
return BadAccess;
for (others = wOtherClients (pWin); others; others = others->next)
{
if (!SameClient(others, client) && (check & others->mask))
return BadAccess;
}
}
if (wClient (pWin) == client)
{
check = pWin->eventMask;
pWin->eventMask = mask;
}
else
{
for (others = wOtherClients (pWin); others; others = others->next)
{
if (SameClient(others, client))
{
check = others->mask;
if (mask == 0)
{
FreeResource(others->resource, RT_NONE);
return Success;
}
else
others->mask = mask;
goto maskSet;
}
}
check = 0;
if (!pWin->optional && !MakeWindowOptional (pWin))
return BadAlloc;
others = (OtherClients *) xalloc(sizeof(OtherClients));
if (!others)
return BadAlloc;
others->mask = mask;
others->resource = FakeClientID(client->index);
others->next = pWin->optional->otherClients;
pWin->optional->otherClients = others;
if (!AddResource(others->resource, RT_OTHERCLIENT, (pointer)pWin))
return BadAlloc;
}
maskSet:
if ((inputInfo.pointer->valuator->motionHintWindow == pWin) &&
(mask & PointerMotionHintMask) &&
!(check & PointerMotionHintMask) &&
!inputInfo.pointer->deviceGrab.grab) /* VCP shouldn't have deviceGrab */
2003-11-14 16:54:54 +01:00
inputInfo.pointer->valuator->motionHintWindow = NullWindow;
RecalculateDeliverableEvents(pWin);
return Success;
}
int
EventSuppressForWindow(WindowPtr pWin, ClientPtr client,
Mask mask, Bool *checkOptional)
2003-11-14 16:54:54 +01:00
{
int i, free;
2003-11-14 16:54:54 +01:00
if (mask & ~PropagateMask)
2003-11-14 16:54:54 +01:00
{
client->errorValue = mask;
return BadValue;
}
if (pWin->dontPropagate)
DontPropagateRefCnts[pWin->dontPropagate]--;
if (!mask)
i = 0;
else
{
for (i = DNPMCOUNT, free = 0; --i > 0; )
{
if (!DontPropagateRefCnts[i])
free = i;
else if (mask == DontPropagateMasks[i])
break;
}
if (!i && free)
{
i = free;
DontPropagateMasks[i] = mask;
}
}
if (i || !mask)
{
pWin->dontPropagate = i;
if (i)
DontPropagateRefCnts[i]++;
if (pWin->optional)
{
pWin->optional->dontPropagateMask = mask;
*checkOptional = TRUE;
}
}
else
{
if (!pWin->optional && !MakeWindowOptional (pWin))
{
if (pWin->dontPropagate)
DontPropagateRefCnts[pWin->dontPropagate]++;
return BadAlloc;
}
pWin->dontPropagate = 0;
pWin->optional->dontPropagateMask = mask;
}
RecalculateDeliverableEvents(pWin);
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* @return The window that is the first ancestor of both a and b.
*/
2003-11-14 16:54:54 +01:00
static WindowPtr
2003-11-14 17:49:22 +01:00
CommonAncestor(
WindowPtr a,
WindowPtr b)
2003-11-14 16:54:54 +01:00
{
for (b = b->parent; b; b = b->parent)
if (IsParent(b, a)) return b;
return NullWindow;
}
2007-04-13 05:38:44 +02:00
/**
* Assembles an EnterNotify or LeaveNotify and sends it event to the client.
2007-05-30 10:14:31 +02:00
* Uses the paired keyboard to get some additional information.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
static void
2003-11-14 17:49:22 +01:00
EnterLeaveEvent(
DeviceIntPtr mouse,
2003-11-14 17:49:22 +01:00
int type,
int mode,
int detail,
WindowPtr pWin,
2003-11-14 17:49:22 +01:00
Window child)
2003-11-14 16:54:54 +01:00
{
xEvent event;
2003-11-14 16:54:54 +01:00
WindowPtr focus;
DeviceIntPtr keybd;
GrabPtr grab = mouse->deviceGrab.grab;
GrabPtr devgrab = mouse->deviceGrab.grab;
2003-11-14 16:54:54 +01:00
Mask mask;
int* inWindow; /* no of sprites inside pWin */
Bool sendevent = FALSE;
2003-11-14 16:54:54 +01:00
deviceEnterNotify *devEnterLeave;
int mskidx;
OtherInputMasks *inputMasks;
if (!(keybd = GetPairedKeyboard(mouse)))
keybd = inputInfo.keyboard;
2003-11-14 16:54:54 +01:00
if ((pWin == mouse->valuator->motionHintWindow) &&
(detail != NotifyInferior))
mouse->valuator->motionHintWindow = NullWindow;
if (grab)
{
mask = (pWin == grab->window) ? grab->eventMask : 0;
if (grab->ownerEvents)
mask |= EventMaskForClient(pWin, rClient(grab));
}
else
{
mask = pWin->eventMask | wOtherEventMasks(pWin);
}
event.u.u.type = type;
event.u.u.detail = detail;
event.u.enterLeave.time = currentTime.milliseconds;
event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x;
event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y;
/* Counts on the same initial structure of crossing & button events! */
FixUpEventFromWindow(mouse, &event, pWin, None, FALSE);
/* Enter/Leave events always set child */
event.u.enterLeave.child = child;
event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ?
ELFlagSameScreen : 0;
#ifdef XKB
if (!noXkbExtension) {
event.u.enterLeave.state = mouse->button->state & 0x1f00;
event.u.enterLeave.state |=
XkbGrabStateFromRec(&keybd->key->xkbInfo->state);
} else
#endif
event.u.enterLeave.state = keybd->key->state | mouse->button->state;
event.u.enterLeave.mode = mode;
focus = keybd->focus->win;
if ((focus != NoneWin) &&
((pWin == focus) || (focus == PointerRootWin) ||
IsParent(focus, pWin)))
event.u.enterLeave.flags |= ELFlagFocus;
inWindow = &((FocusSemaphoresPtr)pWin->devPrivates[FocusPrivatesIndex].ptr)->enterleave;
/*
* 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 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.
*/
if (event.u.u.detail != NotifyVirtual &&
event.u.u.detail != NotifyNonlinearVirtual)
2003-11-14 16:54:54 +01:00
{
(type == EnterNotify) ? (*inWindow)++ : (*inWindow)--;
if (((*inWindow) == (LeaveNotify - type)))
sendevent = TRUE;
} else
{
if (!(*inWindow))
sendevent = TRUE;
}
if ((mask & filters[type]) && sendevent)
{
if (grab)
(void)TryClientEvents(rClient(grab), &event, 1, mask,
filters[type], grab);
else
(void)DeliverEventsToWindow(mouse, pWin, &event, 1, filters[type],
NullGrab, 0);
2003-11-14 16:54:54 +01:00
}
/* 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->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[devEnterLeave->type] & inputMasks->deliverableEvents[mskidx]))
{
if (devgrab)
(void)TryClientEvents(rClient(devgrab), (xEvent*)devEnterLeave, 1,
mask, filters[devEnterLeave->type], devgrab);
else
(void)DeliverEventsToWindow(mouse, pWin, (xEvent*)devEnterLeave,
1, filters[devEnterLeave->type],
NullGrab, mouse->id);
}
2003-11-14 16:54:54 +01:00
if ((type == EnterNotify) && (mask & KeymapStateMask))
{
xKeymapEvent ke;
ClientPtr client = grab ? rClient(grab)
: clients[CLIENT_ID(pWin->drawable.id)];
if (XaceHook(XACE_DEVICE_ACCESS, client, keybd, FALSE))
memmove((char *)&ke.map[0], (char *)&keybd->key->down[1], 31);
2003-11-14 16:54:54 +01:00
else
bzero((char *)&ke.map[0], 31);
2003-11-14 16:54:54 +01:00
ke.type = KeymapNotify;
if (grab)
(void)TryClientEvents(rClient(grab), (xEvent *)&ke, 1, mask,
KeymapStateMask, grab);
else
(void)DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1,
2003-11-14 16:54:54 +01:00
KeymapStateMask, NullGrab, 0);
}
}
2007-04-13 05:38:44 +02:00
/**
* Send enter notifies to all parent windows up to ancestor.
* This function recurses.
*/
2003-11-14 16:54:54 +01:00
static void
EnterNotifies(DeviceIntPtr pDev,
WindowPtr ancestor,
WindowPtr child,
int mode,
int detail)
2003-11-14 16:54:54 +01:00
{
WindowPtr parent = child->parent;
if (ancestor == parent)
return;
EnterNotifies(pDev, ancestor, parent, mode, detail);
EnterLeaveEvent(pDev, EnterNotify, mode, detail, parent,
child->drawable.id); }
2003-11-14 16:54:54 +01:00
2007-04-13 05:38:44 +02:00
/**
* Send leave notifies to all parent windows up to ancestor.
* This function recurses.
*/
2003-11-14 16:54:54 +01:00
static void
LeaveNotifies(DeviceIntPtr pDev,
WindowPtr child,
WindowPtr ancestor,
int mode,
int detail)
2003-11-14 16:54:54 +01:00
{
WindowPtr pWin;
2003-11-14 16:54:54 +01:00
if (ancestor == child)
return;
for (pWin = child->parent; pWin != ancestor; pWin = pWin->parent)
{
EnterLeaveEvent(pDev, LeaveNotify, mode, detail, pWin,
child->drawable.id);
child = pWin;
2003-11-14 16:54:54 +01:00
}
}
2007-04-13 05:38:44 +02:00
/**
* Figure out if enter/leave events are necessary and send them to the
* appropriate windows.
*
* @param fromWin Window the sprite moved out of.
* @param toWin Window the sprite moved into.
*/
2003-11-14 16:54:54 +01:00
static void
DoEnterLeaveEvents(DeviceIntPtr pDev,
WindowPtr fromWin,
WindowPtr toWin,
int mode)
2003-11-14 16:54:54 +01:00
{
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);
2003-11-14 16:54:54 +01:00
}
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);
2003-11-14 16:54:54 +01:00
}
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);
2003-11-14 16:54:54 +01:00
}
}
static void
FocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
2003-11-14 16:54:54 +01:00
{
xEvent event;
int* numFoci; /* no of foci the window has already */
Bool sendevent = FALSE;
2003-11-14 16:54:54 +01:00
if (dev != inputInfo.keyboard)
DeviceFocusEvent(dev, type, mode, detail, pWin);
/*
* Same procedure as for Enter/Leave events.
*
* Sending multiple core FocusIn/Out events to the same window may confuse
* the client.
* We can send multiple events that have detail NotifyVirtual,
* NotifyNonlinearVirtual, NotifyPointerRoot, NotifyDetailNone or
* NotifyPointer however.
*
* For standard events (NotifyAncestor, NotifyInferior, NotifyNonlinear)
* we only send an FocusIn event for the first kbd to set the focus. A
* FocusOut event is sent for the last kbd to set the focus away from the
* window..
*
* For events with Virtual detail, we send them only to a window that does
* not have a focus from another keyboard.
*
* For a window tree in the form of
*
* A -> Bf -> C -> D
* \ (where B and E have focus)
* -> Ef
*
* If the focus changes from E into D, a FocusOut is sent to E, a
* FocusIn is sent to D, a FocusIn with detail
* NotifyNonlinearVirtual to C and nothing to B.
*/
numFoci =
&((FocusSemaphoresPtr)pWin->devPrivates[FocusPrivatesIndex].ptr)->focusinout;
if (detail != NotifyVirtual &&
detail != NotifyNonlinearVirtual &&
detail != NotifyPointer &&
detail != NotifyPointerRoot &&
detail != NotifyDetailNone)
2003-11-14 16:54:54 +01:00
{
(type == FocusIn) ? (*numFoci)++ : (*numFoci)--;
if (((*numFoci) == (FocusOut - type)))
sendevent = TRUE;
} else
{
if (!(*numFoci))
sendevent = TRUE;
}
if (sendevent)
{
event.u.focus.mode = mode;
event.u.u.type = type;
event.u.u.detail = detail;
event.u.focus.window = pWin->drawable.id;
(void)DeliverEventsToWindow(dev, pWin, &event, 1, filters[type], NullGrab,
0);
if ((type == FocusIn) &&
((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask))
{
xKeymapEvent ke;
ClientPtr client = clients[CLIENT_ID(pWin->drawable.id)];
if (XaceHook(XACE_DEVICE_ACCESS, client, dev, FALSE))
memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31);
else
bzero((char *)&ke.map[0], 31);
ke.type = KeymapNotify;
(void)DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1,
KeymapStateMask, NullGrab, 0);
}
2003-11-14 16:54:54 +01:00
}
}
/*
* recursive because it is easier
* no-op if child not descended from ancestor
*/
static Bool
2003-11-14 17:49:22 +01:00
FocusInEvents(
DeviceIntPtr dev,
WindowPtr ancestor, WindowPtr child, WindowPtr skipChild,
int mode, int detail,
Bool doAncestor)
2003-11-14 16:54:54 +01:00
{
if (child == NullWindow)
return ancestor == NullWindow;
if (ancestor == child)
{
if (doAncestor)
FocusEvent(dev, FocusIn, mode, detail, child);
return TRUE;
}
if (FocusInEvents(dev, ancestor, child->parent, skipChild, mode, detail,
doAncestor))
{
if (child != skipChild)
FocusEvent(dev, FocusIn, mode, detail, child);
return TRUE;
}
return FALSE;
}
/* dies horribly if ancestor is not an ancestor of child */
static void
2003-11-14 17:49:22 +01:00
FocusOutEvents(
DeviceIntPtr dev,
WindowPtr child, WindowPtr ancestor,
int mode, int detail,
Bool doAncestor)
2003-11-14 16:54:54 +01:00
{
WindowPtr pWin;
2003-11-14 16:54:54 +01:00
for (pWin = child; pWin != ancestor; pWin = pWin->parent)
FocusEvent(dev, FocusOut, mode, detail, pWin);
if (doAncestor)
FocusEvent(dev, FocusOut, mode, detail, ancestor);
}
void
DoFocusEvents(DeviceIntPtr dev, WindowPtr fromWin, WindowPtr toWin, int mode)
2003-11-14 16:54:54 +01:00
{
int out, in; /* for holding details for to/from
PointerRoot/None */
int i;
SpritePtr pSprite = dev->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
if (fromWin == toWin)
return;
out = (fromWin == NoneWin) ? NotifyDetailNone : NotifyPointerRoot;
in = (toWin == NoneWin) ? NotifyDetailNone : NotifyPointerRoot;
/* wrong values if neither, but then not referenced */
if ((toWin == NullWindow) || (toWin == PointerRootWin))
{
if ((fromWin == NullWindow) || (fromWin == PointerRootWin))
{
if (fromWin == PointerRootWin)
FocusOutEvents(dev, pSprite->win, RootWindow(dev), mode,
NotifyPointer, TRUE);
2003-11-14 16:54:54 +01:00
/* Notify all the roots */
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if ( !noPanoramiXExtension )
FocusEvent(dev, FocusOut, mode, out, WindowTable[0]);
else
#endif
for (i=0; i<screenInfo.numScreens; i++)
FocusEvent(dev, FocusOut, mode, out, WindowTable[i]);
2003-11-14 16:54:54 +01:00
}
else
{
if (IsParent(fromWin, pSprite->win))
FocusOutEvents(dev, pSprite->win, fromWin, mode, NotifyPointer,
2003-11-14 16:54:54 +01:00
FALSE);
FocusEvent(dev, FocusOut, mode, NotifyNonlinear, fromWin);
/* next call catches the root too, if the screen changed */
FocusOutEvents(dev, fromWin->parent, NullWindow, mode,
NotifyNonlinearVirtual, FALSE);
}
/* Notify all the roots */
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if ( !noPanoramiXExtension )
FocusEvent(dev, FocusIn, mode, in, WindowTable[0]);
else
#endif
for (i=0; i<screenInfo.numScreens; i++)
FocusEvent(dev, FocusIn, mode, in, WindowTable[i]);
2003-11-14 16:54:54 +01:00
if (toWin == PointerRootWin)
(void)FocusInEvents(dev, RootWindow(dev), pSprite->win,
NullWindow, mode, NotifyPointer, TRUE);
2003-11-14 16:54:54 +01:00
}
else
{
if ((fromWin == NullWindow) || (fromWin == PointerRootWin))
{
if (fromWin == PointerRootWin)
FocusOutEvents(dev, pSprite->win, RootWindow(dev), mode,
NotifyPointer, TRUE);
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if ( !noPanoramiXExtension )
FocusEvent(dev, FocusOut, mode, out, WindowTable[0]);
else
#endif
for (i=0; i<screenInfo.numScreens; i++)
FocusEvent(dev, FocusOut, mode, out, WindowTable[i]);
2003-11-14 16:54:54 +01:00
if (toWin->parent != NullWindow)
(void)FocusInEvents(dev, RootWindow(dev), toWin, toWin, mode,
2003-11-14 16:54:54 +01:00
NotifyNonlinearVirtual, TRUE);
FocusEvent(dev, FocusIn, mode, NotifyNonlinear, toWin);
if (IsParent(toWin, pSprite->win))
(void)FocusInEvents(dev, toWin, pSprite->win, NullWindow, mode,
2003-11-14 16:54:54 +01:00
NotifyPointer, FALSE);
}
else
{
if (IsParent(toWin, fromWin))
{
FocusEvent(dev, FocusOut, mode, NotifyAncestor, fromWin);
FocusOutEvents(dev, fromWin->parent, toWin, mode,
NotifyVirtual, FALSE);
FocusEvent(dev, FocusIn, mode, NotifyInferior, toWin);
if ((IsParent(toWin, pSprite->win)) &&
(pSprite->win != fromWin) &&
(!IsParent(fromWin, pSprite->win)) &&
(!IsParent(pSprite->win, fromWin)))
(void)FocusInEvents(dev, toWin, pSprite->win, NullWindow,
2003-11-14 16:54:54 +01:00
mode, NotifyPointer, FALSE);
}
else
if (IsParent(fromWin, toWin))
{
if ((IsParent(fromWin, pSprite->win)) &&
(pSprite->win != fromWin) &&
(!IsParent(toWin, pSprite->win)) &&
(!IsParent(pSprite->win, toWin)))
FocusOutEvents(dev, pSprite->win, fromWin, mode,
2003-11-14 16:54:54 +01:00
NotifyPointer, FALSE);
FocusEvent(dev, FocusOut, mode, NotifyInferior, fromWin);
(void)FocusInEvents(dev, fromWin, toWin, toWin, mode,
NotifyVirtual, FALSE);
FocusEvent(dev, FocusIn, mode, NotifyAncestor, toWin);
}
else
{
/* neither fromWin or toWin is child of other */
WindowPtr common = CommonAncestor(toWin, fromWin);
/* common == NullWindow ==> different screens */
if (IsParent(fromWin, pSprite->win))
FocusOutEvents(dev, pSprite->win, fromWin, mode,
2003-11-14 16:54:54 +01:00
NotifyPointer, FALSE);
FocusEvent(dev, FocusOut, mode, NotifyNonlinear, fromWin);
if (fromWin->parent != NullWindow)
FocusOutEvents(dev, fromWin->parent, common, mode,
NotifyNonlinearVirtual, FALSE);
if (toWin->parent != NullWindow)
(void)FocusInEvents(dev, common, toWin, toWin, mode,
NotifyNonlinearVirtual, FALSE);
FocusEvent(dev, FocusIn, mode, NotifyNonlinear, toWin);
if (IsParent(toWin, pSprite->win))
(void)FocusInEvents(dev, toWin, pSprite->win, NullWindow,
2003-11-14 16:54:54 +01:00
mode, NotifyPointer, FALSE);
}
}
}
}
2007-04-13 05:38:44 +02:00
/**
* Set the input focus to the given window. Subsequent keyboard events will be
* delivered to the given window.
*
* Usually called from ProcSetInputFocus as result of a client request. If so,
* the device is the inputInfo.keyboard.
* If called from ProcXSetInputFocus as result of a client xinput request, the
* device is set to the device specified by the client.
*
* @param client Client that requested input focus change.
* @param dev Focus device.
* @param focusID The window to obtain the focus. Can be PointerRoot or None.
* @param revertTo Specifies where the focus reverts to when window becomes
* unviewable.
* @param ctime Specifies the time.
* @param followOK True if pointer is allowed to follow the keyboard.
*/
2003-11-14 16:54:54 +01:00
int
2003-11-14 17:49:22 +01:00
SetInputFocus(
ClientPtr client,
DeviceIntPtr dev,
Window focusID,
CARD8 revertTo,
Time ctime,
Bool followOK)
2003-11-14 16:54:54 +01:00
{
FocusClassPtr focus;
WindowPtr focusWin;
int mode, rc;
2003-11-14 16:54:54 +01:00
TimeStamp time;
DeviceIntPtr keybd; /* used for FollowKeyboard or FollowKeyboardWin */
2003-11-14 16:54:54 +01:00
UpdateCurrentTime();
if ((revertTo != RevertToParent) &&
(revertTo != RevertToPointerRoot) &&
(revertTo != RevertToNone) &&
((revertTo != RevertToFollowKeyboard) || !followOK))
{
client->errorValue = revertTo;
return BadValue;
}
time = ClientTimeToServerTime(ctime);
if (IsKeyboardDevice(dev))
keybd = dev;
else
{
keybd = GetPairedKeyboard(dev);
if (!keybd)
keybd = inputInfo.keyboard;
}
2003-11-14 16:54:54 +01:00
if ((focusID == None) || (focusID == PointerRoot))
2003-11-14 17:49:22 +01:00
focusWin = (WindowPtr)(long)focusID;
2003-11-14 16:54:54 +01:00
else if ((focusID == FollowKeyboard) && followOK)
{
focusWin = keybd->focus->win;
}
else {
rc = dixLookupWindow(&focusWin, focusID, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
/* It is a match error to try to set the input focus to an
unviewable window. */
if(!focusWin->realized)
return(BadMatch);
}
focus = dev->focus;
if ((CompareTimeStamps(time, currentTime) == LATER) ||
(CompareTimeStamps(time, focus->time) == EARLIER))
return Success;
mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal;
2003-11-14 16:54:54 +01:00
if (focus->win == FollowKeyboardWin)
DoFocusEvents(dev, keybd->focus->win, focusWin, mode);
2003-11-14 16:54:54 +01:00
else
DoFocusEvents(dev, focus->win, focusWin, mode);
focus->time = time;
focus->revert = revertTo;
if (focusID == FollowKeyboard)
focus->win = FollowKeyboardWin;
else
focus->win = focusWin;
if ((focusWin == NoneWin) || (focusWin == PointerRootWin))
focus->traceGood = 0;
else
{
int depth = 0;
WindowPtr pWin;
2003-11-14 16:54:54 +01:00
for (pWin = focusWin; pWin; pWin = pWin->parent) depth++;
if (depth > focus->traceSize)
{
focus->traceSize = depth+1;
Must_have_memory = TRUE; /* XXX */
focus->trace = (WindowPtr *)xrealloc(focus->trace,
focus->traceSize *
sizeof(WindowPtr));
Must_have_memory = FALSE; /* XXX */
}
focus->traceGood = depth;
for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--)
focus->trace[depth] = pWin;
}
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for SetInputFocus request.
*
* Sets the input focus for the virtual core keyboard.
*/
2003-11-14 16:54:54 +01:00
int
ProcSetInputFocus(client)
ClientPtr client;
{
DeviceIntPtr kbd = PickKeyboard(client);
2003-11-14 16:54:54 +01:00
REQUEST(xSetInputFocusReq);
REQUEST_SIZE_MATCH(xSetInputFocusReq);
if (!XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.keyboard, TRUE))
2003-11-14 16:54:54 +01:00
return Success;
return SetInputFocus(client, kbd, stuff->focus,
2003-11-14 16:54:54 +01:00
stuff->revertTo, stuff->time, FALSE);
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for GetInputFocus request.
*
2007-05-30 10:14:31 +02:00
* Sends the current input focus for the client's keyboard back to the
2007-04-13 05:38:44 +02:00
* client.
*/
2003-11-14 16:54:54 +01:00
int
ProcGetInputFocus(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
DeviceIntPtr kbd = PickKeyboard(client);
2003-11-14 16:54:54 +01:00
xGetInputFocusReply rep;
2003-11-14 17:49:22 +01:00
/* REQUEST(xReq); */
FocusClassPtr focus = kbd->focus;
2003-11-14 16:54:54 +01:00
REQUEST_SIZE_MATCH(xReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
if (focus->win == NoneWin)
rep.focus = None;
else if (focus->win == PointerRootWin)
rep.focus = PointerRoot;
else rep.focus = focus->win->drawable.id;
rep.revertTo = focus->revert;
WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep);
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for GrabPointer request.
2007-04-13 05:38:44 +02:00
*
2007-05-30 10:14:31 +02:00
* Sets an active grab on the client's ClientPointer and returns success
* status to client.
*
* A special case of GrabPointer is when there is already a grab on some
* device (by the same client). In this case, this grab is overwritten, and
* the device stays as it is. This case can happen when a client has a passive
* grab and then grabs the pointer, or when the client already has an active
* grab and the ClientPointer was changed since.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcGrabPointer(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
xGrabPointerReply rep;
DeviceIntPtr device = PickPointer(client);
2003-11-14 16:54:54 +01:00
GrabPtr grab;
WindowPtr pWin, confineTo;
CursorPtr cursor, oldCursor;
REQUEST(xGrabPointerReq);
TimeStamp time;
int rc;
DeviceIntPtr grabbed = NULL;
2003-11-14 16:54:54 +01:00
REQUEST_SIZE_MATCH(xGrabPointerReq);
UpdateCurrentTime();
if ((stuff->pointerMode != GrabModeSync) &&
(stuff->pointerMode != GrabModeAsync))
{
client->errorValue = stuff->pointerMode;
return BadValue;
}
if ((stuff->keyboardMode != GrabModeSync) &&
(stuff->keyboardMode != GrabModeAsync))
{
client->errorValue = stuff->keyboardMode;
return BadValue;
}
if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue))
{
client->errorValue = stuff->ownerEvents;
return BadValue;
}
if (stuff->eventMask & ~PointerGrabMask)
2003-11-14 16:54:54 +01:00
{
client->errorValue = stuff->eventMask;
return BadValue;
}
rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
if (stuff->confineTo == None)
confineTo = NullWindow;
2003-11-14 17:49:22 +01:00
else
2003-11-14 16:54:54 +01:00
{
rc = dixLookupWindow(&confineTo, stuff->confineTo, client,
DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
}
if (stuff->cursor == None)
cursor = NullCursor;
else
{
cursor = (CursorPtr)SecurityLookupIDByType(client, stuff->cursor,
RT_CURSOR, DixReadAccess);
2003-11-14 16:54:54 +01:00
if (!cursor)
{
client->errorValue = stuff->cursor;
return BadCursor;
}
}
/* at this point, some sort of reply is guaranteed. */
time = ClientTimeToServerTime(stuff->time);
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.length = 0;
/* Check if a the client already has a grab on a device */
for(grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
{
if (IsPointerDevice(grabbed))
{
grab = grabbed->deviceGrab.grab;
if (grab && grab->coreGrab && SameClient(grab, client))
{
device = grabbed;
break;
}
}
}
grab = device->deviceGrab.grab;
2003-11-14 16:54:54 +01:00
if ((grab) && !SameClient(grab, client))
rep.status = AlreadyGrabbed;
else if ((!pWin->realized) ||
2003-11-14 17:49:22 +01:00
(confineTo &&
!(confineTo->realized
&& BorderSizeNotEmpty(device, confineTo))))
2003-11-14 16:54:54 +01:00
rep.status = GrabNotViewable;
else if (device->deviceGrab.sync.frozen &&
device->deviceGrab.sync.other &&
!SameClient(device->deviceGrab.sync.other, client))
2003-11-14 16:54:54 +01:00
rep.status = GrabFrozen;
else if ((CompareTimeStamps(time, currentTime) == LATER) ||
(CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER))
2003-11-14 16:54:54 +01:00
rep.status = GrabInvalidTime;
else
{
GrabRec tempGrab;
oldCursor = NullCursor;
if (grab)
{
if (grab->confineTo && !confineTo)
ConfineCursorToWindow(device, RootWindow(device), FALSE, FALSE);
2003-11-14 16:54:54 +01:00
oldCursor = grab->cursor;
}
tempGrab.next = NULL;
2003-11-14 16:54:54 +01:00
tempGrab.cursor = cursor;
tempGrab.resource = client->clientAsMask;
tempGrab.ownerEvents = stuff->ownerEvents;
tempGrab.eventMask = stuff->eventMask;
tempGrab.confineTo = confineTo;
tempGrab.window = pWin;
tempGrab.keyboardMode = stuff->keyboardMode;
tempGrab.pointerMode = stuff->pointerMode;
tempGrab.device = device;
tempGrab.coreGrab = True;
tempGrab.genericMasks = NULL;
(*device->deviceGrab.ActivateGrab)(device, &tempGrab, time, FALSE);
2003-11-14 16:54:54 +01:00
if (oldCursor)
FreeCursor (oldCursor, (Cursor)0);
rep.status = GrabSuccess;
/* guarantee only one core pointer grab at a time by this client */
RemoveOtherCoreGrabs(client, device);
2003-11-14 16:54:54 +01:00
}
WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep);
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for ChangeActivePointerGrab request.
*
* Changes properties of the grab hold by the client. If the client does not
* hold an active grab on the device, nothing happens.
*
* Works on the client's ClientPointer, but in some cases the client may have
* a grab on a device that isn't the ClientPointer (see ProcGrabPointer
* comments).
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcChangeActivePointerGrab(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
DeviceIntPtr device, grabbed;
GrabPtr grab;
2003-11-14 16:54:54 +01:00
CursorPtr newCursor, oldCursor;
REQUEST(xChangeActivePointerGrabReq);
TimeStamp time;
REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq);
if (stuff->eventMask & ~PointerGrabMask)
2003-11-14 16:54:54 +01:00
{
client->errorValue = stuff->eventMask;
return BadValue;
}
if (stuff->cursor == None)
newCursor = NullCursor;
else
{
newCursor = (CursorPtr)SecurityLookupIDByType(client, stuff->cursor,
RT_CURSOR, DixReadAccess);
2003-11-14 16:54:54 +01:00
if (!newCursor)
{
client->errorValue = stuff->cursor;
return BadCursor;
}
}
device = PickPointer(client);
grab = device->deviceGrab.grab;
if (!grab || !SameClient(grab, client))
{
/* no grab on ClientPointer, or some other client has a grab on our
* ClientPointer, let's check if we have a pointer grab on some other
* device. */
for(grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
{
if (IsPointerDevice(grabbed))
{
grab = grabbed->deviceGrab.grab;
if (grab && grab->coreGrab && SameClient(grab, client))
{
device = grabbed;
break;
}
}
}
/* nope. no grab on any actual device */
if (!grabbed)
{
device = inputInfo.pointer;
grab = inputInfo.pointer->deviceGrab.grab;
}
}
2003-11-14 16:54:54 +01:00
if (!grab)
return Success;
if (!SameClient(grab, client))
return Success;
time = ClientTimeToServerTime(stuff->time);
if ((CompareTimeStamps(time, currentTime) == LATER) ||
(CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER))
2003-11-14 16:54:54 +01:00
return Success;
oldCursor = grab->cursor;
grab->cursor = newCursor;
if (newCursor)
newCursor->refcnt++;
PostNewCursor(device);
2003-11-14 16:54:54 +01:00
if (oldCursor)
FreeCursor(oldCursor, (Cursor)0);
grab->eventMask = stuff->eventMask;
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for UngrabPointer request.
*
* Deletes a pointer grab on a device the client has grabbed. This should be
* the ClientPointer, but may not be. So we search the device list for a
* device we have a pointer grab on and then ungrab this device. (see
* ProcGrabPointer comments). We are guaranteed that the client doesn't have
* more than one core pointer grab at a time.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcUngrabPointer(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
DeviceIntPtr device = PickPointer(client),
grabbed;
2003-11-14 16:54:54 +01:00
GrabPtr grab;
TimeStamp time;
REQUEST(xResourceReq);
REQUEST_SIZE_MATCH(xResourceReq);
UpdateCurrentTime();
grab = device->deviceGrab.grab;
if (!grab || !grab->coreGrab || !SameClient(grab, client))
{
/* No pointer grab on ClientPointer. May be a pointer grab on some
* other device */
for(grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
{
if (IsPointerDevice(grabbed))
{
grab = grabbed->deviceGrab.grab;
if (grab && grab->coreGrab && SameClient(grab, client))
{
device = grabbed;
break;
}
}
}
/* nope. no grab on any actual device */
if (!grabbed)
{
device = inputInfo.pointer;
grab = inputInfo.pointer->deviceGrab.grab;
}
}
2003-11-14 16:54:54 +01:00
time = ClientTimeToServerTime(stuff->id);
if ((CompareTimeStamps(time, currentTime) != LATER) &&
(CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
2003-11-14 16:54:54 +01:00
(grab) && SameClient(grab, client))
(*device->deviceGrab.DeactivateGrab)(device);
2003-11-14 16:54:54 +01:00
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* Sets a grab on the given device.
*
2007-05-30 10:14:31 +02:00
* Called from ProcGrabKeyboard to work on the client's keyboard.
2007-04-13 05:38:44 +02:00
* Called from ProcXGrabDevice to work on the device specified by the client.
*
* The parameters this_mode and other_mode represent the keyboard_mode and
* pointer_mode parameters of XGrabKeyboard().
* See man page for details on all the parameters
*
* @param client Client that owns the grab.
* @param dev The device to grab.
* @param this_mode GrabModeSync or GrabModeAsync
* @param other_mode GrabModeSync or GrabModeAsync
* @param status Return code to be returned to the caller.
*
* @returns Success or BadValue.
*/
2003-11-14 16:54:54 +01:00
int
GrabDevice(ClientPtr client, DeviceIntPtr dev,
unsigned this_mode, unsigned other_mode, Window grabWindow,
unsigned ownerEvents, Time ctime, Mask mask, CARD8 *status,
Bool coreGrab)
2003-11-14 16:54:54 +01:00
{
WindowPtr pWin;
GrabPtr grab;
2003-11-14 16:54:54 +01:00
TimeStamp time;
int rc;
GrabInfoPtr grabInfo = &dev->deviceGrab;
2003-11-14 16:54:54 +01:00
UpdateCurrentTime();
if ((this_mode != GrabModeSync) && (this_mode != GrabModeAsync))
{
client->errorValue = this_mode;
return BadValue;
}
if ((other_mode != GrabModeSync) && (other_mode != GrabModeAsync))
{
client->errorValue = other_mode;
return BadValue;
}
if ((ownerEvents != xFalse) && (ownerEvents != xTrue))
{
client->errorValue = ownerEvents;
return BadValue;
}
rc = dixLookupWindow(&pWin, grabWindow, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
time = ClientTimeToServerTime(ctime);
grab = grabInfo->grab;
2003-11-14 16:54:54 +01:00
if (grab && !SameClient(grab, client))
*status = AlreadyGrabbed;
else if (!pWin->realized)
*status = GrabNotViewable;
else if ((CompareTimeStamps(time, currentTime) == LATER) ||
(CompareTimeStamps(time, grabInfo->grabTime) == EARLIER))
2003-11-14 16:54:54 +01:00
*status = GrabInvalidTime;
else if (grabInfo->sync.frozen &&
grabInfo->sync.other && !SameClient(grabInfo->sync.other, client))
2003-11-14 16:54:54 +01:00
*status = GrabFrozen;
else
{
GrabRec tempGrab;
/* Otherwise segfaults happen on grabbed MPX devices */
memset(&tempGrab, 0, sizeof(GrabRec));
tempGrab.next = NULL;
2003-11-14 16:54:54 +01:00
tempGrab.window = pWin;
tempGrab.resource = client->clientAsMask;
tempGrab.ownerEvents = ownerEvents;
tempGrab.keyboardMode = this_mode;
tempGrab.pointerMode = other_mode;
tempGrab.eventMask = mask;
tempGrab.device = dev;
tempGrab.cursor = NULL;
tempGrab.coreGrab = coreGrab;
tempGrab.genericMasks = NULL;
(*grabInfo->ActivateGrab)(dev, &tempGrab, time, FALSE);
2003-11-14 16:54:54 +01:00
*status = GrabSuccess;
}
return Success;
}
/**
* Deactivate any core grabs on the given client except the given device.
*
* This fixes race conditions where clients deal with implicit passive grabs
* on one device, but then actively grab their client pointer, which is
* another device.
*
* Grabs are only removed if the other device matches the type of device. If
* dev is a pointer device, only other pointer grabs are removed. Likewise, if
* dev is a keyboard device, only keyboard grabs are removed.
*
* If dev doesn't have a grab, do nothing and go for a beer.
*
* @param client The client that is to be limited.
* @param dev The only device allowed to have a grab on the client.
*/
_X_EXPORT void
RemoveOtherCoreGrabs(ClientPtr client, DeviceIntPtr dev)
{
if (!dev || !dev->deviceGrab.grab)
return;
DeviceIntPtr it = inputInfo.devices;
for (; it; it = it->next)
{
if (it == dev)
continue;
/* check for IsPointer Device */
if (it->deviceGrab.grab &&
it->deviceGrab.grab->coreGrab &&
SameClient(it->deviceGrab.grab, client))
{
if ((IsPointerDevice(dev) && IsPointerDevice(it)) ||
(IsKeyboardDevice(dev) && IsKeyboardDevice(it)))
(*it->deviceGrab.DeactivateGrab)(it);
}
}
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for GrabKeyboard request.
*
2007-05-30 10:14:31 +02:00
* Grabs the client's keyboard and returns success status to client.
*
* In some special cases the client may already have a grab on a keyboard that
* is not the one that is paired with the ClientPointer. This can happen when
* the client alreay has a passive grab on some keyboard device, or when the
* client actively grabbed the keyboard and the ClientPointer or keyboard
* pairing was changed since.
* Therefore, we need to run through all the keyboards available and check if
* there's already a grab on it from our client. The client will only ever
* have one core keyboard grab at a time.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcGrabKeyboard(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
xGrabKeyboardReply rep;
REQUEST(xGrabKeyboardReq);
int result;
DeviceIntPtr keyboard = PickKeyboard(client),
grabbed;
GrabPtr grab;
2003-11-14 16:54:54 +01:00
REQUEST_SIZE_MATCH(xGrabKeyboardReq);
for (grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
{
if (IsKeyboardDevice(grabbed))
{
grab = grabbed->deviceGrab.grab;
if (grab && grab->coreGrab && SameClient(grab, client))
{
keyboard = grabbed;
break;
}
}
}
if (XaceHook(XACE_DEVICE_ACCESS, client, keyboard, TRUE))
{
result = GrabDevice(client, keyboard, stuff->keyboardMode,
stuff->pointerMode, stuff->grabWindow,
stuff->ownerEvents, stuff->time,
KeyPressMask | KeyReleaseMask, &rep.status, TRUE);
/* ensure only one core keyboard grab by this client */
RemoveOtherCoreGrabs(client, keyboard);
}
else {
2003-11-14 16:54:54 +01:00
result = Success;
rep.status = AlreadyGrabbed;
}
2003-11-14 16:54:54 +01:00
if (result != Success)
return result;
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.length = 0;
WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep);
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for UngrabKeyboard request.
*
2007-05-30 10:14:31 +02:00
* Deletes a possible grab on the client's keyboard.
*
* We may have a grab on a keyboard that isn't the ClientPointer's keyboard.
* Thus we need to check all keyboar devices for a grab. (see ProcGrabKeyboard
* comments)
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcUngrabKeyboard(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
DeviceIntPtr device = PickKeyboard(client),
grabbed;
2003-11-14 16:54:54 +01:00
GrabPtr grab;
TimeStamp time;
REQUEST(xResourceReq);
REQUEST_SIZE_MATCH(xResourceReq);
UpdateCurrentTime();
grab = device->deviceGrab.grab;
if (!grab || !grab->coreGrab || !SameClient(grab, client))
{
for (grabbed = inputInfo.devices; grabbed; grabbed = grabbed->next)
{
if (IsKeyboardDevice(grabbed))
{
grab = device->deviceGrab.grab;
if (grab && grab->coreGrab && SameClient(grab, client))
{
device = grabbed;
break;
}
}
}
}
grab = device->deviceGrab.grab;
2003-11-14 16:54:54 +01:00
time = ClientTimeToServerTime(stuff->id);
if ((CompareTimeStamps(time, currentTime) != LATER) &&
(CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
(grab) && SameClient(grab, client) && grab->coreGrab)
(*device->deviceGrab.DeactivateGrab)(device);
2003-11-14 16:54:54 +01:00
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for QueryPointer request.
*
2007-05-30 10:14:31 +02:00
* Returns the current state and position of the client's ClientPointer to the
* client.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcQueryPointer(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
xQueryPointerReply rep;
WindowPtr pWin, t;
DeviceIntPtr mouse = PickPointer(client);
SpritePtr pSprite = mouse->spriteInfo->sprite;
int rc;
2003-11-14 16:54:54 +01:00
REQUEST(xResourceReq);
2003-11-14 16:54:54 +01:00
REQUEST_SIZE_MATCH(xResourceReq);
rc = dixLookupWindow(&pWin, stuff->id, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
if (mouse->valuator->motionHintWindow)
MaybeStopHint(mouse, client);
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.mask = mouse->button->state | inputInfo.keyboard->key->state;
rep.length = 0;
rep.root = (RootWindow(mouse))->drawable.id;
rep.rootX = pSprite->hot.x;
rep.rootY = pSprite->hot.y;
2003-11-14 16:54:54 +01:00
rep.child = None;
if (pSprite->hot.pScreen == pWin->drawable.pScreen)
2003-11-14 16:54:54 +01:00
{
rep.sameScreen = xTrue;
rep.winX = pSprite->hot.x - pWin->drawable.x;
rep.winY = pSprite->hot.y - pWin->drawable.y;
for (t = pSprite->win; t; t = t->parent)
2003-11-14 16:54:54 +01:00
if (t->parent == pWin)
{
rep.child = t->drawable.id;
break;
}
}
else
{
rep.sameScreen = xFalse;
rep.winX = 0;
rep.winY = 0;
}
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension) {
rep.rootX += panoramiXdataPtr[0].x;
rep.rootY += panoramiXdataPtr[0].y;
if(stuff->id == rep.root) {
rep.winX += panoramiXdataPtr[0].x;
rep.winY += panoramiXdataPtr[0].y;
}
}
#endif
2003-11-14 16:54:54 +01:00
WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep);
return(Success);
}
2007-04-13 05:38:44 +02:00
/**
* Initializes the device list and the DIX sprite to sane values. Allocates
* trace memory used for quick window traversal.
*/
2003-11-14 16:54:54 +01:00
void
InitEvents(void)
2003-11-14 16:54:54 +01:00
{
int i;
inputInfo.numDevices = 0;
inputInfo.devices = (DeviceIntPtr)NULL;
inputInfo.off_devices = (DeviceIntPtr)NULL;
inputInfo.keyboard = (DeviceIntPtr)NULL;
inputInfo.pointer = (DeviceIntPtr)NULL;
lastEventMask = OwnerGrabButtonMask;
filters[MotionNotify] = PointerMotionMask;
#ifdef XEVIE
xeviewin = NULL;
#endif
2003-11-14 16:54:54 +01:00
syncEvents.replayDev = (DeviceIntPtr)NULL;
syncEvents.replayWin = NullWindow;
while (syncEvents.pending)
{
QdEventPtr next = syncEvents.pending->next;
xfree(syncEvents.pending);
syncEvents.pending = next;
}
syncEvents.pendtail = &syncEvents.pending;
syncEvents.playingEvents = FALSE;
syncEvents.time.months = 0;
syncEvents.time.milliseconds = 0; /* hardly matters */
currentTime.months = 0;
currentTime.milliseconds = GetTimeInMillis();
lastDeviceEventTime = currentTime;
for (i = 0; i < DNPMCOUNT; i++)
{
DontPropagateMasks[i] = 0;
DontPropagateRefCnts[i] = 0;
}
}
/**
* This function is deprecated! It shouldn't be used anymore. It used to free
* the spriteTraces, but now they are freed when the SpriteRec is freed.
*/
_X_DEPRECATED void
2003-11-14 17:49:22 +01:00
CloseDownEvents(void)
{
2003-11-14 17:49:22 +01:00
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for SendEvent request.
*
* Locates the window to send the event to and forwards the event.
*/
2003-11-14 16:54:54 +01:00
int
ProcSendEvent(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
WindowPtr pWin;
WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */
SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
REQUEST(xSendEventReq);
REQUEST_SIZE_MATCH(xSendEventReq);
/* The client's event type must be a core event type or one defined by an
extension. */
if ( ! ((stuff->event.u.u.type > X_Reply &&
stuff->event.u.u.type < LASTEvent) ||
(stuff->event.u.u.type >= EXTENSION_EVENT_BASE &&
stuff->event.u.u.type < (unsigned)lastEvent)))
{
client->errorValue = stuff->event.u.u.type;
return BadValue;
}
if (stuff->event.u.u.type == ClientMessage &&
stuff->event.u.u.detail != 8 &&
stuff->event.u.u.detail != 16 &&
stuff->event.u.u.detail != 32)
2003-11-14 16:54:54 +01:00
{
client->errorValue = stuff->event.u.u.detail;
return BadValue;
}
if (stuff->eventMask & ~AllEventMasks)
2003-11-14 16:54:54 +01:00
{
client->errorValue = stuff->eventMask;
return BadValue;
}
if (stuff->destination == PointerWindow)
pWin = pSprite->win;
2003-11-14 16:54:54 +01:00
else if (stuff->destination == InputFocus)
{
WindowPtr inputFocus = inputInfo.keyboard->focus->win;
if (inputFocus == NoneWin)
return Success;
/* If the input focus is PointerRootWin, send the event to where
the pointer is if possible, then perhaps propogate up to root. */
if (inputFocus == PointerRootWin)
inputFocus = pSprite->spriteTrace[0]; /* Root window! */
2003-11-14 16:54:54 +01:00
if (IsParent(inputFocus, pSprite->win))
2003-11-14 16:54:54 +01:00
{
effectiveFocus = inputFocus;
pWin = pSprite->win;
2003-11-14 16:54:54 +01:00
}
else
effectiveFocus = pWin = inputFocus;
}
else
dixLookupWindow(&pWin, stuff->destination, client, DixReadAccess);
2003-11-14 16:54:54 +01:00
if (!pWin)
return BadWindow;
if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue))
{
client->errorValue = stuff->propagate;
return BadValue;
}
stuff->event.u.u.type |= 0x80;
if (stuff->propagate)
{
for (;pWin; pWin = pWin->parent)
{
if (DeliverEventsToWindow(PickPointer(client), pWin,
&stuff->event, 1, stuff->eventMask, NullGrab, 0))
2003-11-14 16:54:54 +01:00
return Success;
if (pWin == effectiveFocus)
return Success;
stuff->eventMask &= ~wDontPropagateMask(pWin);
if (!stuff->eventMask)
break;
}
}
else
(void)DeliverEventsToWindow(PickPointer(client), pWin, &stuff->event,
1, stuff->eventMask, NullGrab, 0);
2003-11-14 16:54:54 +01:00
return Success;
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for UngrabKey request.
*
2007-05-30 10:14:31 +02:00
* Deletes a passive grab for the given key. Works on the
* client's keyboard.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcUngrabKey(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
REQUEST(xUngrabKeyReq);
WindowPtr pWin;
GrabRec tempGrab;
DeviceIntPtr keybd = PickKeyboard(client);
int rc;
2003-11-14 16:54:54 +01:00
REQUEST_SIZE_MATCH(xUngrabKeyReq);
rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 17:49:22 +01:00
2003-11-14 16:54:54 +01:00
if (((stuff->key > keybd->key->curKeySyms.maxKeyCode) ||
(stuff->key < keybd->key->curKeySyms.minKeyCode))
&& (stuff->key != AnyKey))
{
client->errorValue = stuff->key;
return BadValue;
}
if ((stuff->modifiers != AnyModifier) &&
(stuff->modifiers & ~AllModifiersMask))
{
client->errorValue = stuff->modifiers;
return BadValue;
}
tempGrab.resource = client->clientAsMask;
tempGrab.device = keybd;
tempGrab.window = pWin;
tempGrab.modifiersDetail.exact = stuff->modifiers;
tempGrab.modifiersDetail.pMask = NULL;
tempGrab.modifierDevice = inputInfo.keyboard;
tempGrab.type = KeyPress;
tempGrab.detail.exact = stuff->key;
tempGrab.detail.pMask = NULL;
tempGrab.next = NULL;
2003-11-14 16:54:54 +01:00
if (!DeletePassiveGrabFromList(&tempGrab))
return(BadAlloc);
return(Success);
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for GrabKey request.
*
2007-05-30 10:14:31 +02:00
* Creates a grab for the client's keyboard and adds it to the list of passive
* grabs.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcGrabKey(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
WindowPtr pWin;
REQUEST(xGrabKeyReq);
GrabPtr grab;
DeviceIntPtr keybd = PickKeyboard(client);
int rc;
2003-11-14 16:54:54 +01:00
REQUEST_SIZE_MATCH(xGrabKeyReq);
if ((stuff->ownerEvents != xTrue) && (stuff->ownerEvents != xFalse))
{
client->errorValue = stuff->ownerEvents;
return(BadValue);
}
if ((stuff->pointerMode != GrabModeSync) &&
(stuff->pointerMode != GrabModeAsync))
{
client->errorValue = stuff->pointerMode;
return BadValue;
}
if ((stuff->keyboardMode != GrabModeSync) &&
(stuff->keyboardMode != GrabModeAsync))
{
client->errorValue = stuff->keyboardMode;
return BadValue;
}
if (((stuff->key > keybd->key->curKeySyms.maxKeyCode) ||
(stuff->key < keybd->key->curKeySyms.minKeyCode))
&& (stuff->key != AnyKey))
{
client->errorValue = stuff->key;
return BadValue;
}
if ((stuff->modifiers != AnyModifier) &&
(stuff->modifiers & ~AllModifiersMask))
{
client->errorValue = stuff->modifiers;
return BadValue;
}
rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
grab = CreateGrab(client->index, keybd, pWin,
(Mask)(KeyPressMask | KeyReleaseMask), (Bool)stuff->ownerEvents,
(Bool)stuff->keyboardMode, (Bool)stuff->pointerMode,
2003-11-14 17:49:22 +01:00
keybd, stuff->modifiers, KeyPress, stuff->key,
NullWindow, NullCursor);
2003-11-14 16:54:54 +01:00
if (!grab)
return BadAlloc;
return AddPassiveGrabToList(grab);
}
2003-11-14 17:49:22 +01:00
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for GrabButton request.
*
2007-05-30 10:14:31 +02:00
* Creates a grab for the client's ClientPointer and adds it as a passive grab
* to the list.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcGrabButton(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
WindowPtr pWin, confineTo;
REQUEST(xGrabButtonReq);
CursorPtr cursor;
GrabPtr grab;
DeviceIntPtr pointer, modifierDevice;
int rc;
2003-11-14 16:54:54 +01:00
REQUEST_SIZE_MATCH(xGrabButtonReq);
if ((stuff->pointerMode != GrabModeSync) &&
(stuff->pointerMode != GrabModeAsync))
{
client->errorValue = stuff->pointerMode;
return BadValue;
}
if ((stuff->keyboardMode != GrabModeSync) &&
(stuff->keyboardMode != GrabModeAsync))
{
client->errorValue = stuff->keyboardMode;
return BadValue;
}
if ((stuff->modifiers != AnyModifier) &&
(stuff->modifiers & ~AllModifiersMask))
{
client->errorValue = stuff->modifiers;
return BadValue;
}
if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue))
{
client->errorValue = stuff->ownerEvents;
return BadValue;
}
if (stuff->eventMask & ~PointerGrabMask)
{
client->errorValue = stuff->eventMask;
return BadValue;
}
rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
if (stuff->confineTo == None)
2003-11-14 17:49:22 +01:00
confineTo = NullWindow;
else {
rc = dixLookupWindow(&confineTo, stuff->confineTo, client,
DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
}
if (stuff->cursor == None)
cursor = NullCursor;
else
{
cursor = (CursorPtr)SecurityLookupIDByType(client, stuff->cursor,
RT_CURSOR, DixReadAccess);
2003-11-14 16:54:54 +01:00
if (!cursor)
{
client->errorValue = stuff->cursor;
return BadCursor;
}
}
pointer = PickPointer(client);
modifierDevice = GetPairedKeyboard(pointer);
if (!modifierDevice)
modifierDevice = inputInfo.keyboard;
2003-11-14 17:49:22 +01:00
grab = CreateGrab(client->index, pointer, pWin,
(Mask)stuff->eventMask, (Bool)stuff->ownerEvents,
(Bool) stuff->keyboardMode, (Bool)stuff->pointerMode,
modifierDevice, stuff->modifiers, ButtonPress,
stuff->button, confineTo, cursor);
2003-11-14 16:54:54 +01:00
if (!grab)
return BadAlloc;
return AddPassiveGrabToList(grab);
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for UngrabButton request.
*
2007-05-30 10:14:31 +02:00
* Deletes a passive grab on the client's ClientPointer from the list.
2007-04-13 05:38:44 +02:00
*/
2003-11-14 16:54:54 +01:00
int
ProcUngrabButton(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
REQUEST(xUngrabButtonReq);
WindowPtr pWin;
GrabRec tempGrab;
int rc;
2003-11-14 16:54:54 +01:00
REQUEST_SIZE_MATCH(xUngrabButtonReq);
if ((stuff->modifiers != AnyModifier) &&
(stuff->modifiers & ~AllModifiersMask))
{
client->errorValue = stuff->modifiers;
return BadValue;
}
rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess);
if (rc != Success)
return rc;
2003-11-14 16:54:54 +01:00
tempGrab.resource = client->clientAsMask;
tempGrab.device = PickPointer(client);
2003-11-14 16:54:54 +01:00
tempGrab.window = pWin;
tempGrab.modifiersDetail.exact = stuff->modifiers;
tempGrab.modifiersDetail.pMask = NULL;
tempGrab.modifierDevice = inputInfo.keyboard;
tempGrab.type = ButtonPress;
tempGrab.detail.exact = stuff->button;
tempGrab.detail.pMask = NULL;
tempGrab.next = NULL;
2003-11-14 16:54:54 +01:00
if (!DeletePassiveGrabFromList(&tempGrab))
return(BadAlloc);
return(Success);
}
2007-04-13 05:38:44 +02:00
/**
* Deactivate any grab that may be on the window, remove the focus.
* Delete any XInput extension events from the window too. Does not change the
* window mask. Use just before the window is deleted.
*
* If freeResources is set, passive grabs on the window are deleted.
*
* @param pWin The window to delete events from.
* @param freeResources True if resources associated with the window should be
* deleted.
*/
2003-11-14 16:54:54 +01:00
void
DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources)
2003-11-14 16:54:54 +01:00
{
WindowPtr parent;
DeviceIntPtr mouse = inputInfo.pointer;
DeviceIntPtr keybd = inputInfo.keyboard;
FocusClassPtr focus;
2003-11-14 16:54:54 +01:00
OtherClientsPtr oc;
GrabPtr passive;
GrabPtr grab;
2003-11-14 16:54:54 +01:00
/* Deactivate any grabs performed on this window, before making any
input focus changes. */
grab = mouse->deviceGrab.grab;
if (grab &&
((grab->window == pWin) || (grab->confineTo == pWin)))
(*mouse->deviceGrab.DeactivateGrab)(mouse);
2003-11-14 16:54:54 +01:00
/* Deactivating a keyboard grab should cause focus events. */
grab = keybd->deviceGrab.grab;
if (grab && (grab->window == pWin))
(*keybd->deviceGrab.DeactivateGrab)(keybd);
2003-11-14 16:54:54 +01:00
/* And now the real devices */
for (mouse = inputInfo.devices; mouse; mouse = mouse->next)
2003-11-14 16:54:54 +01:00
{
grab = mouse->deviceGrab.grab;
if (grab && ((grab->window == pWin) || (grab->confineTo == pWin)))
(*mouse->deviceGrab.DeactivateGrab)(mouse);
}
2003-11-14 16:54:54 +01:00
for (keybd = inputInfo.devices; keybd; keybd = keybd->next)
{
if (IsKeyboardDevice(keybd))
{
focus = keybd->focus;
2003-11-14 16:54:54 +01:00
/* If the focus window is a root window (ie. has no parent) then don't
delete the focus from it. */
if ((pWin == focus->win) && (pWin->parent != NullWindow))
{
int focusEventMode = NotifyNormal;
/* If a grab is in progress, then alter the mode of focus events. */
if (keybd->deviceGrab.grab)
focusEventMode = NotifyWhileGrabbed;
switch (focus->revert)
{
case RevertToNone:
DoFocusEvents(keybd, pWin, NoneWin, focusEventMode);
focus->win = NoneWin;
focus->traceGood = 0;
break;
case RevertToParent:
parent = pWin;
do
{
parent = parent->parent;
focus->traceGood--;
} while (!parent->realized
/* This would be a good protocol change -- windows being reparented
during SaveSet processing would cause the focus to revert to the
nearest enclosing window which will survive the death of the exiting
client, instead of ending up reverting to a dying window and thence
to None
*/
2003-11-14 16:54:54 +01:00
#ifdef NOTDEF
|| clients[CLIENT_ID(parent->drawable.id)]->clientGone
2003-11-14 16:54:54 +01:00
#endif
);
DoFocusEvents(keybd, pWin, parent, focusEventMode);
focus->win = parent;
focus->revert = RevertToNone;
break;
case RevertToPointerRoot:
DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode);
focus->win = PointerRootWin;
focus->traceGood = 0;
break;
}
}
}
2003-11-14 16:54:54 +01:00
if (IsPointerDevice(keybd))
{
if (keybd->valuator->motionHintWindow == pWin)
keybd->valuator->motionHintWindow = NullWindow;
}
}
2003-11-14 16:54:54 +01:00
if (freeResources)
{
if (pWin->dontPropagate)
DontPropagateRefCnts[pWin->dontPropagate]--;
while ( (oc = wOtherClients(pWin)) )
FreeResource(oc->resource, RT_NONE);
while ( (passive = wPassiveGrabs(pWin)) )
FreeResource(passive->resource, RT_NONE);
}
#ifdef XINPUT
DeleteWindowFromAnyExtEvents(pWin, freeResources);
#endif
}
/**
2007-04-13 05:38:44 +02:00
* Call this whenever some window at or below pWin has changed geometry. If
* there is a grab on the window, the cursor will be re-confined into the
* window.
*/
_X_EXPORT void
CheckCursorConfinement(WindowPtr pWin)
2003-11-14 16:54:54 +01:00
{
GrabPtr grab;
2003-11-14 16:54:54 +01:00
WindowPtr confineTo;
DeviceIntPtr pDev;
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return;
#endif
for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
2003-11-14 16:54:54 +01:00
{
if (DevHasCursor(pDev))
{
grab = pDev->deviceGrab.grab;
if (grab && (confineTo = grab->confineTo))
{
if (!BorderSizeNotEmpty(pDev, confineTo))
(*inputInfo.pointer->deviceGrab.DeactivateGrab)(pDev);
else if ((pWin == confineTo) || IsParent(pWin, confineTo))
ConfineCursorToWindow(pDev, confineTo, TRUE, TRUE);
}
}
2003-11-14 16:54:54 +01:00
}
}
Mask
EventMaskForClient(WindowPtr pWin, ClientPtr client)
2003-11-14 16:54:54 +01:00
{
OtherClientsPtr other;
2003-11-14 16:54:54 +01:00
if (wClient (pWin) == client)
return pWin->eventMask;
for (other = wOtherClients(pWin); other; other = other->next)
{
if (SameClient(other, client))
return other->mask;
}
return 0;
}
2007-04-13 05:38:44 +02:00
/**
* Server-side protocol handling for RecolorCursor request.
*/
2003-11-14 16:54:54 +01:00
int
ProcRecolorCursor(ClientPtr client)
2003-11-14 16:54:54 +01:00
{
CursorPtr pCursor;
int nscr;
ScreenPtr pscr;
2003-11-14 17:49:22 +01:00
Bool displayed;
SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
2003-11-14 16:54:54 +01:00
REQUEST(xRecolorCursorReq);
REQUEST_SIZE_MATCH(xRecolorCursorReq);
pCursor = (CursorPtr)SecurityLookupIDByType(client, stuff->cursor,
RT_CURSOR, DixWriteAccess);
2003-11-14 16:54:54 +01:00
if ( !pCursor)
{
client->errorValue = stuff->cursor;
return (BadCursor);
}
pCursor->foreRed = stuff->foreRed;
pCursor->foreGreen = stuff->foreGreen;
pCursor->foreBlue = stuff->foreBlue;
pCursor->backRed = stuff->backRed;
pCursor->backGreen = stuff->backGreen;
pCursor->backBlue = stuff->backBlue;
for (nscr = 0; nscr < screenInfo.numScreens; nscr++)
{
pscr = screenInfo.screens[nscr];
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension)
displayed = (pscr == pSprite->screen);
2003-11-14 17:49:22 +01:00
else
#endif
displayed = (pscr == pSprite->hotPhys.pScreen);
( *pscr->RecolorCursor)(PickPointer(client), pscr, pCursor,
(pCursor == pSprite->current) && displayed);
2003-11-14 16:54:54 +01:00
}
return (Success);
}
2007-04-13 05:38:44 +02:00
/**
* Write the given events to a client, swapping the byte order if necessary.
* To swap the byte ordering, a callback is called that has to be set up for
* the given event type.
*
* In the case of DeviceMotionNotify trailed by DeviceValuators, the events
* can be more than one. Usually it's just one event.
*
* Do not modify the event structure passed in. See comment below.
*
* @param pClient Client to send events to.
* @param count Number of events.
* @param events The event list.
*/
_X_EXPORT void
WriteEventsToClient(ClientPtr pClient, int count, xEvent *events)
2003-11-14 16:54:54 +01:00
{
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
xEvent eventCopy;
#endif
xEvent *eventTo, *eventFrom;
int i,
eventlength = sizeof(xEvent);
2003-11-14 16:54:54 +01:00
#ifdef XKB
if ((!noXkbExtension)&&(!XkbFilterEvents(pClient, count, events)))
return;
#endif
2003-11-14 17:49:22 +01:00
#ifdef PANORAMIX
if(!noPanoramiXExtension &&
(panoramiXdataPtr[0].x || panoramiXdataPtr[0].y))
{
switch(events->u.u.type) {
case MotionNotify:
case ButtonPress:
case ButtonRelease:
case KeyPress:
case KeyRelease:
case EnterNotify:
case LeaveNotify:
/*
When multiple clients want the same event DeliverEventsToWindow
passes the same event structure multiple times so we can't
modify the one passed to us
*/
count = 1; /* should always be 1 */
memcpy(&eventCopy, events, sizeof(xEvent));
eventCopy.u.keyButtonPointer.rootX += panoramiXdataPtr[0].x;
eventCopy.u.keyButtonPointer.rootY += panoramiXdataPtr[0].y;
if(eventCopy.u.keyButtonPointer.event ==
eventCopy.u.keyButtonPointer.root)
{
eventCopy.u.keyButtonPointer.eventX += panoramiXdataPtr[0].x;
eventCopy.u.keyButtonPointer.eventY += panoramiXdataPtr[0].y;
}
events = &eventCopy;
break;
default: break;
}
}
#endif
2003-11-14 16:54:54 +01:00
if (EventCallback)
{
EventInfoRec eventinfo;
eventinfo.client = pClient;
eventinfo.events = events;
eventinfo.count = count;
CallCallbacks(&EventCallback, (pointer)&eventinfo);
}
#ifdef XSERVER_DTRACE
if (XSERVER_SEND_EVENT_ENABLED()) {
for (i = 0; i < count; i++)
{
XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]);
}
}
#endif
/* Just a safety check to make sure we only have one GenericEvent, it just
* makes things easier for me right now. (whot) */
for (i = 1; i < count; i++)
{
if (events[i].u.u.type == GenericEvent)
{
ErrorF("TryClientEvents: Only one GenericEvent at a time.");
return;
}
}
if (events->u.u.type == GenericEvent)
{
eventlength += ((xGenericEvent*)events)->length * 4;
if (eventlength > swapEventLen)
{
swapEventLen = eventlength;
swapEvent = Xrealloc(swapEvent, swapEventLen);
if (!swapEvent)
{
FatalError("WriteEventsToClient: Out of memory.\n");
return;
}
}
}
2003-11-14 16:54:54 +01:00
if(pClient->swapped)
{
for(i = 0; i < count; i++)
{
eventFrom = &events[i];
eventTo = swapEvent;
2003-11-14 16:54:54 +01:00
/* Remember to strip off the leading bit of type in case
this event was sent with "SendEvent." */
(*EventSwapVector[eventFrom->u.u.type & 0177])
(eventFrom, eventTo);
(void)WriteToClient(pClient, eventlength, (char *)&eventTo);
2003-11-14 16:54:54 +01:00
}
}
else
{
/* only one GenericEvent, remember? that means either count is 1 and
* eventlength is arbitrary or eventlength is 32 and count doesn't
* matter. And we're all set. Woohoo. */
(void)WriteToClient(pClient, count * eventlength, (char *) events);
2003-11-14 16:54:54 +01:00
}
}
/*
* Set the client pointer for the given client. Second parameter setter could
* be used in the future to determine access rights. Unused for now.
2007-05-30 10:14:31 +02:00
*
* A client can have exactly one ClientPointer. Each time a
* request/reply/event is processed and the choice of devices is ambiguous
* (e.g. QueryPointer request), the server will pick the ClientPointer (see
* PickPointer()).
* If a keyboard is needed, the first keyboard paired with the CP is used.
*/
_X_EXPORT Bool
SetClientPointer(ClientPtr client, ClientPtr setter, DeviceIntPtr device)
{
client->clientPtr = device;
return TRUE;
}
/* PickPointer will pick an appropriate pointer for the given client.
*
* If a client pointer is set, it will pick the client pointer, otherwise the
* first available pointer in the list. If no physical device is attached, it
* will pick the core pointer, but will not store it on the client.
*/
_X_EXPORT DeviceIntPtr
PickPointer(ClientPtr client)
{
if (!client->clientPtr)
{
/* look if there is a real device attached */
DeviceIntPtr it = inputInfo.devices;
while (it)
{
if (it != inputInfo.pointer && it->spriteInfo->spriteOwner)
{
client->clientPtr = it;
break;
}
it = it->next;
}
if (!it)
{
ErrorF("Picking VCP\n");
return inputInfo.pointer;
}
}
return client->clientPtr;
}
/* PickKeyboard will pick an appropriate keyboard for the given client by
* searching the list of devices for the keyboard device that is paired with
* the client's pointer.
* If no pointer is paired with the keyboard, the virtual core keyboard is
* returned.
*/
_X_EXPORT DeviceIntPtr
PickKeyboard(ClientPtr client)
{
DeviceIntPtr ptr = PickPointer(client);
DeviceIntPtr kbd = inputInfo.devices;
while(kbd)
{
if (ptr != kbd &&
IsKeyboardDevice(kbd) &&
ptr->spriteInfo->sprite == kbd->spriteInfo->sprite)
return kbd;
kbd = kbd->next;
}
return (kbd) ? kbd : inputInfo.keyboard;
}
/* A client that has one or more core grabs does not get core events from
* devices it does not have a grab on. Legacy applications behave bad
* otherwise because they are not used to it and the events interfere.
* Only applies for core events.
*
* Return true if a core event from the device would interfere and should not
* be delivered.
*/
Bool
IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event)
{
DeviceIntPtr it = inputInfo.devices;
if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client))
return FALSE;
switch(event->u.u.type)
{
case KeyPress:
case KeyRelease:
case ButtonPress:
case ButtonRelease:
case MotionNotify:
case EnterNotify:
case LeaveNotify:
break;
default:
return FALSE;
}
while(it)
{
if (it != dev)
{
if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client)
&& !it->deviceGrab.fromPassiveGrab)
{
return TRUE;
}
}
it = it->next;
}
return FALSE;
}
/**
* Set the filters for a extension.
* The filters array needs to contain the Masks that are applicable for each
* event type for the given extension.
* e.g. if generic event type 2 should be let through for windows with
* MyExampleMask set, make sure that filters[2] == MyExampleMask.
*/
_X_EXPORT void
SetGenericFilter(int extension, Mask* filters)
{
generic_filters[extension & 0x7f] = filters;
}
/**
* Grab a device for XI events and XGE events.
* grabmode is used to ungrab a device.
*/
_X_EXPORT int
ExtGrabDevice(ClientPtr client,
DeviceIntPtr dev,
int device_mode,
WindowPtr grabWindow,
WindowPtr confineTo,
TimeStamp ctime,
Bool ownerEvents,
CursorPtr cursor,
Mask xi_mask,
GenericMaskPtr ge_masks)
{
GrabInfoPtr grabinfo;
GrabRec newGrab;
UpdateCurrentTime();
grabinfo = &dev->deviceGrab;
if (grabinfo->grab && !SameClient(grabinfo->grab, client))
return AlreadyGrabbed;
if (!grabWindow->realized)
return GrabNotViewable;
if ((CompareTimeStamps(ctime, currentTime) == LATER) ||
(CompareTimeStamps(ctime, grabinfo->grabTime) == EARLIER))
return GrabInvalidTime;
if (grabinfo->sync.frozen && grabinfo->sync.other &&
!SameClient(grabinfo->sync.other, client))
return GrabFrozen;
memset(&newGrab, 0, sizeof(GrabRec));
newGrab.window = grabWindow;
newGrab.resource = client->clientAsMask;
newGrab.ownerEvents = ownerEvents;
newGrab.device = dev;
newGrab.cursor = cursor;
newGrab.confineTo = confineTo;
newGrab.eventMask = xi_mask;
newGrab.genericMasks = NULL;
newGrab.next = NULL;
if (ge_masks)
{
newGrab.genericMasks = xcalloc(1, sizeof(GenericMaskRec));
*newGrab.genericMasks = *ge_masks;
newGrab.genericMasks->next = NULL;
}
if (IsPointerDevice(dev))
{
newGrab.keyboardMode = GrabModeAsync;
newGrab.pointerMode = device_mode;
} else
{
newGrab.keyboardMode = device_mode;
newGrab.pointerMode = GrabModeAsync;
}
(*grabinfo->ActivateGrab)(dev, &newGrab, ctime, FALSE);
return GrabSuccess;
}
_X_EXPORT int
ExtUngrabDevice(ClientPtr client, DeviceIntPtr dev)
{
GrabInfoPtr grabinfo = &dev->deviceGrab;
if (grabinfo->grab && SameClient(grabinfo->grab, client))
(*grabinfo->DeactivateGrab)(dev);
return GrabSuccess;
}