xref: /OK3568_Linux_fs/external/xserver/dix/events.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /************************************************************
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun Copyright 1987, 1998  The Open Group
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun Permission to use, copy, modify, distribute, and sell this software and its
6*4882a593Smuzhiyun documentation for any purpose is hereby granted without fee, provided that
7*4882a593Smuzhiyun the above copyright notice appear in all copies and that both that
8*4882a593Smuzhiyun copyright notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation.
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun all copies or substantial portions of the Software.
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17*4882a593Smuzhiyun OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18*4882a593Smuzhiyun AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19*4882a593Smuzhiyun CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun Except as contained in this notice, the name of The Open Group shall not be
22*4882a593Smuzhiyun used in advertising or otherwise to promote the sale, use or other dealings
23*4882a593Smuzhiyun in this Software without prior written authorization from The Open Group.
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun                         All Rights Reserved
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun Permission to use, copy, modify, and distribute this software and its
30*4882a593Smuzhiyun documentation for any purpose and without fee is hereby granted,
31*4882a593Smuzhiyun provided that the above copyright notice appear in all copies and that
32*4882a593Smuzhiyun both that copyright notice and this permission notice appear in
33*4882a593Smuzhiyun supporting documentation, and that the name of Digital not be
34*4882a593Smuzhiyun used in advertising or publicity pertaining to distribution of the
35*4882a593Smuzhiyun software without specific, written prior permission.
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38*4882a593Smuzhiyun ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39*4882a593Smuzhiyun DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40*4882a593Smuzhiyun ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41*4882a593Smuzhiyun WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42*4882a593Smuzhiyun ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43*4882a593Smuzhiyun SOFTWARE.
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun ********************************************************/
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /* The panoramix components contained the following notice */
48*4882a593Smuzhiyun /*****************************************************************
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun Permission is hereby granted, free of charge, to any person obtaining a copy
53*4882a593Smuzhiyun of this software and associated documentation files (the "Software"), to deal
54*4882a593Smuzhiyun in the Software without restriction, including without limitation the rights
55*4882a593Smuzhiyun to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
56*4882a593Smuzhiyun copies of the Software.
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun The above copyright notice and this permission notice shall be included in
59*4882a593Smuzhiyun all copies or substantial portions of the Software.
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62*4882a593Smuzhiyun IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63*4882a593Smuzhiyun FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
64*4882a593Smuzhiyun DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
65*4882a593Smuzhiyun BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
66*4882a593Smuzhiyun WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
67*4882a593Smuzhiyun IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun Except as contained in this notice, the name of Digital Equipment Corporation
70*4882a593Smuzhiyun shall not be used in advertising or otherwise to promote the sale, use or other
71*4882a593Smuzhiyun dealings in this Software without prior written authorization from Digital
72*4882a593Smuzhiyun Equipment Corporation.
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun ******************************************************************/
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /*
77*4882a593Smuzhiyun  * Copyright (c) 2003-2005, Oracle and/or its affiliates. All rights reserved.
78*4882a593Smuzhiyun  *
79*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
80*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
81*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
82*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
83*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
84*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
85*4882a593Smuzhiyun  *
86*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the next
87*4882a593Smuzhiyun  * paragraph) shall be included in all copies or substantial portions of the
88*4882a593Smuzhiyun  * Software.
89*4882a593Smuzhiyun  *
90*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
91*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
92*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
93*4882a593Smuzhiyun  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
94*4882a593Smuzhiyun  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
95*4882a593Smuzhiyun  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
96*4882a593Smuzhiyun  * DEALINGS IN THE SOFTWARE.
97*4882a593Smuzhiyun  */
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /** @file events.c
100*4882a593Smuzhiyun  * This file handles event delivery and a big part of the server-side protocol
101*4882a593Smuzhiyun  * handling (the parts for input devices).
102*4882a593Smuzhiyun  */
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
105*4882a593Smuzhiyun #include <dix-config.h>
106*4882a593Smuzhiyun #endif
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun #include <X11/X.h>
109*4882a593Smuzhiyun #include "misc.h"
110*4882a593Smuzhiyun #include "resource.h"
111*4882a593Smuzhiyun #include <X11/Xproto.h>
112*4882a593Smuzhiyun #include "windowstr.h"
113*4882a593Smuzhiyun #include "inputstr.h"
114*4882a593Smuzhiyun #include "inpututils.h"
115*4882a593Smuzhiyun #include "scrnintstr.h"
116*4882a593Smuzhiyun #include "cursorstr.h"
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun #include "dixstruct.h"
119*4882a593Smuzhiyun #ifdef PANORAMIX
120*4882a593Smuzhiyun #include "panoramiX.h"
121*4882a593Smuzhiyun #include "panoramiXsrv.h"
122*4882a593Smuzhiyun #endif
123*4882a593Smuzhiyun #include "globals.h"
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun #include <X11/extensions/XKBproto.h>
126*4882a593Smuzhiyun #include "xkbsrv.h"
127*4882a593Smuzhiyun #include "xace.h"
128*4882a593Smuzhiyun #include "probes.h"
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun #include <X11/extensions/XIproto.h>
131*4882a593Smuzhiyun #include <X11/extensions/XI2proto.h>
132*4882a593Smuzhiyun #include <X11/extensions/XI.h>
133*4882a593Smuzhiyun #include <X11/extensions/XI2.h>
134*4882a593Smuzhiyun #include "exglobals.h"
135*4882a593Smuzhiyun #include "exevents.h"
136*4882a593Smuzhiyun #include "extnsionst.h"
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun #include "dixevents.h"
139*4882a593Smuzhiyun #include "dixgrabs.h"
140*4882a593Smuzhiyun #include "dispatch.h"
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun #include <X11/extensions/ge.h>
143*4882a593Smuzhiyun #include "geext.h"
144*4882a593Smuzhiyun #include "geint.h"
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun #include "eventstr.h"
147*4882a593Smuzhiyun #include "enterleave.h"
148*4882a593Smuzhiyun #include "eventconvert.h"
149*4882a593Smuzhiyun #include "mi.h"
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun /* Extension events type numbering starts at EXTENSION_EVENT_BASE.  */
152*4882a593Smuzhiyun #define NoSuchEvent 0x80000000  /* so doesn't match NoEventMask */
153*4882a593Smuzhiyun #define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask )
154*4882a593Smuzhiyun #define AllButtonsMask ( \
155*4882a593Smuzhiyun 	Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )
156*4882a593Smuzhiyun #define MotionMask ( \
157*4882a593Smuzhiyun 	PointerMotionMask | Button1MotionMask | \
158*4882a593Smuzhiyun 	Button2MotionMask | Button3MotionMask | Button4MotionMask | \
159*4882a593Smuzhiyun 	Button5MotionMask | ButtonMotionMask )
160*4882a593Smuzhiyun #define PropagateMask ( \
161*4882a593Smuzhiyun 	KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \
162*4882a593Smuzhiyun 	MotionMask )
163*4882a593Smuzhiyun #define PointerGrabMask ( \
164*4882a593Smuzhiyun 	ButtonPressMask | ButtonReleaseMask | \
165*4882a593Smuzhiyun 	EnterWindowMask | LeaveWindowMask | \
166*4882a593Smuzhiyun 	PointerMotionHintMask | KeymapStateMask | \
167*4882a593Smuzhiyun 	MotionMask )
168*4882a593Smuzhiyun #define AllModifiersMask ( \
169*4882a593Smuzhiyun 	ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \
170*4882a593Smuzhiyun 	Mod3Mask | Mod4Mask | Mod5Mask )
171*4882a593Smuzhiyun #define LastEventMask OwnerGrabButtonMask
172*4882a593Smuzhiyun #define AllEventMasks (LastEventMask|(LastEventMask-1))
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun /* @return the core event type or 0 if the event is not a core event */
175*4882a593Smuzhiyun static inline int
core_get_type(const xEvent * event)176*4882a593Smuzhiyun core_get_type(const xEvent *event)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun     int type = event->u.u.type;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun     return ((type & EXTENSION_EVENT_BASE) || type == GenericEvent) ? 0 : type;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun /* @return the XI2 event type or 0 if the event is not a XI2 event */
184*4882a593Smuzhiyun static inline int
xi2_get_type(const xEvent * event)185*4882a593Smuzhiyun xi2_get_type(const xEvent *event)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun     const xGenericEvent *e = (const xGenericEvent *) event;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun     return (e->type != GenericEvent ||
190*4882a593Smuzhiyun             e->extension != IReqCode) ? 0 : e->evtype;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun /**
194*4882a593Smuzhiyun  * Used to indicate a implicit passive grab created by a ButtonPress event.
195*4882a593Smuzhiyun  * See DeliverEventsToWindow().
196*4882a593Smuzhiyun  */
197*4882a593Smuzhiyun #define ImplicitGrabMask (1 << 7)
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun #define WID(w) ((w) ? ((w)->drawable.id) : 0)
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun #define XE_KBPTR (xE->u.keyButtonPointer)
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun CallbackListPtr EventCallback;
204*4882a593Smuzhiyun CallbackListPtr DeviceEventCallback;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun #define DNPMCOUNT 8
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun Mask DontPropagateMasks[DNPMCOUNT];
209*4882a593Smuzhiyun static int DontPropagateRefCnts[DNPMCOUNT];
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun static void CheckVirtualMotion(DeviceIntPtr pDev, QdEventPtr qe,
212*4882a593Smuzhiyun                                WindowPtr pWin);
213*4882a593Smuzhiyun static void CheckPhysLimits(DeviceIntPtr pDev, CursorPtr cursor,
214*4882a593Smuzhiyun                             Bool generateEvents, Bool confineToScreen,
215*4882a593Smuzhiyun                             ScreenPtr pScreen);
216*4882a593Smuzhiyun static Bool IsWrongPointerBarrierClient(ClientPtr client,
217*4882a593Smuzhiyun                                         DeviceIntPtr dev,
218*4882a593Smuzhiyun                                         xEvent *event);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun /** Key repeat hack. Do not use but in TryClientEvents */
221*4882a593Smuzhiyun extern BOOL EventIsKeyRepeat(xEvent *event);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun /**
224*4882a593Smuzhiyun  * Main input device struct.
225*4882a593Smuzhiyun  *     inputInfo.pointer
226*4882a593Smuzhiyun  *     is the core pointer. Referred to as "virtual core pointer", "VCP",
227*4882a593Smuzhiyun  *     "core pointer" or inputInfo.pointer. The VCP is the first master
228*4882a593Smuzhiyun  *     pointer device and cannot be deleted.
229*4882a593Smuzhiyun  *
230*4882a593Smuzhiyun  *     inputInfo.keyboard
231*4882a593Smuzhiyun  *     is the core keyboard ("virtual core keyboard", "VCK", "core keyboard").
232*4882a593Smuzhiyun  *     See inputInfo.pointer.
233*4882a593Smuzhiyun  *
234*4882a593Smuzhiyun  *     inputInfo.devices
235*4882a593Smuzhiyun  *     linked list containing all devices including VCP and VCK.
236*4882a593Smuzhiyun  *
237*4882a593Smuzhiyun  *     inputInfo.off_devices
238*4882a593Smuzhiyun  *     Devices that have not been initialized and are thus turned off.
239*4882a593Smuzhiyun  *
240*4882a593Smuzhiyun  *     inputInfo.numDevices
241*4882a593Smuzhiyun  *     Total number of devices.
242*4882a593Smuzhiyun  *
243*4882a593Smuzhiyun  *     inputInfo.all_devices
244*4882a593Smuzhiyun  *     Virtual device used for XIAllDevices passive grabs. This device is
245*4882a593Smuzhiyun  *     not part of the inputInfo.devices list and mostly unset except for
246*4882a593Smuzhiyun  *     the deviceid. It exists because passivegrabs need a valid device
247*4882a593Smuzhiyun  *     reference.
248*4882a593Smuzhiyun  *
249*4882a593Smuzhiyun  *     inputInfo.all_master_devices
250*4882a593Smuzhiyun  *     Virtual device used for XIAllMasterDevices passive grabs. This device
251*4882a593Smuzhiyun  *     is not part of the inputInfo.devices list and mostly unset except for
252*4882a593Smuzhiyun  *     the deviceid. It exists because passivegrabs need a valid device
253*4882a593Smuzhiyun  *     reference.
254*4882a593Smuzhiyun  */
255*4882a593Smuzhiyun InputInfo inputInfo;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun EventSyncInfoRec syncEvents;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun static struct DeviceEventTime {
260*4882a593Smuzhiyun     Bool reset;
261*4882a593Smuzhiyun     TimeStamp time;
262*4882a593Smuzhiyun } lastDeviceEventTime[MAXDEVICES];
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun /**
265*4882a593Smuzhiyun  * The root window the given device is currently on.
266*4882a593Smuzhiyun  */
267*4882a593Smuzhiyun #define RootWindow(sprite) sprite->spriteTrace[0]
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun static xEvent *swapEvent = NULL;
270*4882a593Smuzhiyun static int swapEventLen = 0;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun void
NotImplemented(xEvent * from,xEvent * to)273*4882a593Smuzhiyun NotImplemented(xEvent *from, xEvent *to)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun     FatalError("Not implemented");
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun /**
279*4882a593Smuzhiyun  * Convert the given event type from an XI event to a core event.
280*4882a593Smuzhiyun  * @param[in] The XI 1.x event type.
281*4882a593Smuzhiyun  * @return The matching core event type or 0 if there is none.
282*4882a593Smuzhiyun  */
283*4882a593Smuzhiyun int
XItoCoreType(int xitype)284*4882a593Smuzhiyun XItoCoreType(int xitype)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun     int coretype = 0;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun     if (xitype == DeviceMotionNotify)
289*4882a593Smuzhiyun         coretype = MotionNotify;
290*4882a593Smuzhiyun     else if (xitype == DeviceButtonPress)
291*4882a593Smuzhiyun         coretype = ButtonPress;
292*4882a593Smuzhiyun     else if (xitype == DeviceButtonRelease)
293*4882a593Smuzhiyun         coretype = ButtonRelease;
294*4882a593Smuzhiyun     else if (xitype == DeviceKeyPress)
295*4882a593Smuzhiyun         coretype = KeyPress;
296*4882a593Smuzhiyun     else if (xitype == DeviceKeyRelease)
297*4882a593Smuzhiyun         coretype = KeyRelease;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun     return coretype;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun /**
303*4882a593Smuzhiyun  * @return true if the device owns a cursor, false if device shares a cursor
304*4882a593Smuzhiyun  * sprite with another device.
305*4882a593Smuzhiyun  */
306*4882a593Smuzhiyun Bool
DevHasCursor(DeviceIntPtr pDev)307*4882a593Smuzhiyun DevHasCursor(DeviceIntPtr pDev)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun     return pDev->spriteInfo->spriteOwner;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun /*
313*4882a593Smuzhiyun  * @return true if a device is a pointer, check is the same as used by XI to
314*4882a593Smuzhiyun  * fill the 'use' field.
315*4882a593Smuzhiyun  */
316*4882a593Smuzhiyun Bool
IsPointerDevice(DeviceIntPtr dev)317*4882a593Smuzhiyun IsPointerDevice(DeviceIntPtr dev)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun     return (dev->type == MASTER_POINTER) ||
320*4882a593Smuzhiyun         (dev->valuator && dev->button) || (dev->valuator && !dev->key);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun /*
324*4882a593Smuzhiyun  * @return true if a device is a keyboard, check is the same as used by XI to
325*4882a593Smuzhiyun  * fill the 'use' field.
326*4882a593Smuzhiyun  *
327*4882a593Smuzhiyun  * Some pointer devices have keys as well (e.g. multimedia keys). Try to not
328*4882a593Smuzhiyun  * count them as keyboard devices.
329*4882a593Smuzhiyun  */
330*4882a593Smuzhiyun Bool
IsKeyboardDevice(DeviceIntPtr dev)331*4882a593Smuzhiyun IsKeyboardDevice(DeviceIntPtr dev)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun     return (dev->type == MASTER_KEYBOARD) ||
334*4882a593Smuzhiyun         ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev));
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun Bool
IsMaster(DeviceIntPtr dev)338*4882a593Smuzhiyun IsMaster(DeviceIntPtr dev)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun     return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun Bool
IsFloating(DeviceIntPtr dev)344*4882a593Smuzhiyun IsFloating(DeviceIntPtr dev)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun     return !IsMaster(dev) && GetMaster(dev, MASTER_KEYBOARD) == NULL;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun /**
350*4882a593Smuzhiyun  * Max event opcode.
351*4882a593Smuzhiyun  */
352*4882a593Smuzhiyun extern int lastEvent;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun #define CantBeFiltered NoEventMask
355*4882a593Smuzhiyun /**
356*4882a593Smuzhiyun  * Event masks for each event type.
357*4882a593Smuzhiyun  *
358*4882a593Smuzhiyun  * One set of filters for each device, initialized by memcpy of
359*4882a593Smuzhiyun  * default_filter in InitEvents.
360*4882a593Smuzhiyun  *
361*4882a593Smuzhiyun  * Filters are used whether a given event may be delivered to a client,
362*4882a593Smuzhiyun  * usually in the form of if (window-event-mask & filter); then deliver event.
363*4882a593Smuzhiyun  *
364*4882a593Smuzhiyun  * One notable filter is for PointerMotion/DevicePointerMotion events. Each
365*4882a593Smuzhiyun  * time a button is pressed, the filter is modified to also contain the
366*4882a593Smuzhiyun  * matching ButtonXMotion mask.
367*4882a593Smuzhiyun  */
368*4882a593Smuzhiyun Mask event_filters[MAXDEVICES][MAXEVENTS];
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun static const Mask default_filter[MAXEVENTS] = {
371*4882a593Smuzhiyun     NoSuchEvent,                /* 0 */
372*4882a593Smuzhiyun     NoSuchEvent,                /* 1 */
373*4882a593Smuzhiyun     KeyPressMask,               /* KeyPress */
374*4882a593Smuzhiyun     KeyReleaseMask,             /* KeyRelease */
375*4882a593Smuzhiyun     ButtonPressMask,            /* ButtonPress */
376*4882a593Smuzhiyun     ButtonReleaseMask,          /* ButtonRelease */
377*4882a593Smuzhiyun     PointerMotionMask,          /* MotionNotify (initial state) */
378*4882a593Smuzhiyun     EnterWindowMask,            /* EnterNotify */
379*4882a593Smuzhiyun     LeaveWindowMask,            /* LeaveNotify */
380*4882a593Smuzhiyun     FocusChangeMask,            /* FocusIn */
381*4882a593Smuzhiyun     FocusChangeMask,            /* FocusOut */
382*4882a593Smuzhiyun     KeymapStateMask,            /* KeymapNotify */
383*4882a593Smuzhiyun     ExposureMask,               /* Expose */
384*4882a593Smuzhiyun     CantBeFiltered,             /* GraphicsExpose */
385*4882a593Smuzhiyun     CantBeFiltered,             /* NoExpose */
386*4882a593Smuzhiyun     VisibilityChangeMask,       /* VisibilityNotify */
387*4882a593Smuzhiyun     SubstructureNotifyMask,     /* CreateNotify */
388*4882a593Smuzhiyun     StructureAndSubMask,        /* DestroyNotify */
389*4882a593Smuzhiyun     StructureAndSubMask,        /* UnmapNotify */
390*4882a593Smuzhiyun     StructureAndSubMask,        /* MapNotify */
391*4882a593Smuzhiyun     SubstructureRedirectMask,   /* MapRequest */
392*4882a593Smuzhiyun     StructureAndSubMask,        /* ReparentNotify */
393*4882a593Smuzhiyun     StructureAndSubMask,        /* ConfigureNotify */
394*4882a593Smuzhiyun     SubstructureRedirectMask,   /* ConfigureRequest */
395*4882a593Smuzhiyun     StructureAndSubMask,        /* GravityNotify */
396*4882a593Smuzhiyun     ResizeRedirectMask,         /* ResizeRequest */
397*4882a593Smuzhiyun     StructureAndSubMask,        /* CirculateNotify */
398*4882a593Smuzhiyun     SubstructureRedirectMask,   /* CirculateRequest */
399*4882a593Smuzhiyun     PropertyChangeMask,         /* PropertyNotify */
400*4882a593Smuzhiyun     CantBeFiltered,             /* SelectionClear */
401*4882a593Smuzhiyun     CantBeFiltered,             /* SelectionRequest */
402*4882a593Smuzhiyun     CantBeFiltered,             /* SelectionNotify */
403*4882a593Smuzhiyun     ColormapChangeMask,         /* ColormapNotify */
404*4882a593Smuzhiyun     CantBeFiltered,             /* ClientMessage */
405*4882a593Smuzhiyun     CantBeFiltered              /* MappingNotify */
406*4882a593Smuzhiyun };
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun /**
409*4882a593Smuzhiyun  * For the given event, return the matching event filter. This filter may then
410*4882a593Smuzhiyun  * be AND'ed with the selected event mask.
411*4882a593Smuzhiyun  *
412*4882a593Smuzhiyun  * For XI2 events, the returned filter is simply the byte containing the event
413*4882a593Smuzhiyun  * mask we're interested in. E.g. for a mask of (1 << 13), this would be
414*4882a593Smuzhiyun  * byte[1].
415*4882a593Smuzhiyun  *
416*4882a593Smuzhiyun  * @param[in] dev The device the event belongs to, may be NULL.
417*4882a593Smuzhiyun  * @param[in] event The event to get the filter for. Only the type of the
418*4882a593Smuzhiyun  *                  event matters, or the extension + evtype for GenericEvents.
419*4882a593Smuzhiyun  * @return The filter mask for the given event.
420*4882a593Smuzhiyun  *
421*4882a593Smuzhiyun  * @see GetEventMask
422*4882a593Smuzhiyun  */
423*4882a593Smuzhiyun Mask
GetEventFilter(DeviceIntPtr dev,xEvent * event)424*4882a593Smuzhiyun GetEventFilter(DeviceIntPtr dev, xEvent *event)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun     int evtype = 0;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun     if (event->u.u.type != GenericEvent)
429*4882a593Smuzhiyun         return event_get_filter_from_type(dev, event->u.u.type);
430*4882a593Smuzhiyun     else if ((evtype = xi2_get_type(event)))
431*4882a593Smuzhiyun         return event_get_filter_from_xi2type(evtype);
432*4882a593Smuzhiyun     ErrorF("[dix] Unknown event type %d. No filter\n", event->u.u.type);
433*4882a593Smuzhiyun     return 0;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun /**
437*4882a593Smuzhiyun  * Return the single byte of the device's XI2 mask that contains the mask
438*4882a593Smuzhiyun  * for the event_type.
439*4882a593Smuzhiyun  */
440*4882a593Smuzhiyun int
GetXI2MaskByte(XI2Mask * mask,DeviceIntPtr dev,int event_type)441*4882a593Smuzhiyun GetXI2MaskByte(XI2Mask *mask, DeviceIntPtr dev, int event_type)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun     /* we just return the matching filter because that's the only use
444*4882a593Smuzhiyun      * for this mask anyway.
445*4882a593Smuzhiyun      */
446*4882a593Smuzhiyun     if (xi2mask_isset(mask, dev, event_type))
447*4882a593Smuzhiyun         return event_get_filter_from_xi2type(event_type);
448*4882a593Smuzhiyun     else
449*4882a593Smuzhiyun         return 0;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun /**
453*4882a593Smuzhiyun  * @return TRUE if the mask is set for this event from this device on the
454*4882a593Smuzhiyun  * window, or FALSE otherwise.
455*4882a593Smuzhiyun  */
456*4882a593Smuzhiyun Bool
WindowXI2MaskIsset(DeviceIntPtr dev,WindowPtr win,xEvent * ev)457*4882a593Smuzhiyun WindowXI2MaskIsset(DeviceIntPtr dev, WindowPtr win, xEvent *ev)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun     OtherInputMasks *inputMasks = wOtherInputMasks(win);
460*4882a593Smuzhiyun     int evtype;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun     if (!inputMasks || xi2_get_type(ev) == 0)
463*4882a593Smuzhiyun         return 0;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun     evtype = ((xGenericEvent *) ev)->evtype;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun     return xi2mask_isset(inputMasks->xi2mask, dev, evtype);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun Mask
GetEventMask(DeviceIntPtr dev,xEvent * event,InputClients * other)471*4882a593Smuzhiyun GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients * other)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun     int evtype;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun     /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */
476*4882a593Smuzhiyun     if ((evtype = xi2_get_type(event))) {
477*4882a593Smuzhiyun         return GetXI2MaskByte(other->xi2mask, dev, evtype);
478*4882a593Smuzhiyun     }
479*4882a593Smuzhiyun     else if (core_get_type(event) != 0)
480*4882a593Smuzhiyun         return other->mask[XIAllDevices];
481*4882a593Smuzhiyun     else
482*4882a593Smuzhiyun         return other->mask[dev->id];
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun static CARD8 criticalEvents[32] = {
486*4882a593Smuzhiyun     0x7c, 0x30, 0x40            /* key, button, expose, and configure events */
487*4882a593Smuzhiyun };
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun static void
SyntheticMotion(DeviceIntPtr dev,int x,int y)490*4882a593Smuzhiyun SyntheticMotion(DeviceIntPtr dev, int x, int y)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun     int screenno = 0;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun #ifdef PANORAMIX
495*4882a593Smuzhiyun     if (!noPanoramiXExtension)
496*4882a593Smuzhiyun         screenno = dev->spriteInfo->sprite->screen->myNum;
497*4882a593Smuzhiyun #endif
498*4882a593Smuzhiyun     PostSyntheticMotion(dev, x, y, screenno,
499*4882a593Smuzhiyun                         (syncEvents.playingEvents) ? syncEvents.time.
500*4882a593Smuzhiyun                         milliseconds : currentTime.milliseconds);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun #ifdef PANORAMIX
505*4882a593Smuzhiyun static void PostNewCursor(DeviceIntPtr pDev);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun static Bool
XineramaSetCursorPosition(DeviceIntPtr pDev,int x,int y,Bool generateEvent)508*4882a593Smuzhiyun XineramaSetCursorPosition(DeviceIntPtr pDev, int x, int y, Bool generateEvent)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun     ScreenPtr pScreen;
511*4882a593Smuzhiyun     int i;
512*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun     /* x,y are in Screen 0 coordinates.  We need to decide what Screen
515*4882a593Smuzhiyun        to send the message too and what the coordinates relative to
516*4882a593Smuzhiyun        that screen are. */
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun     pScreen = pSprite->screen;
519*4882a593Smuzhiyun     x += screenInfo.screens[0]->x;
520*4882a593Smuzhiyun     y += screenInfo.screens[0]->y;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun     if (!point_on_screen(pScreen, x, y)) {
523*4882a593Smuzhiyun         FOR_NSCREENS(i) {
524*4882a593Smuzhiyun             if (i == pScreen->myNum)
525*4882a593Smuzhiyun                 continue;
526*4882a593Smuzhiyun             if (point_on_screen(screenInfo.screens[i], x, y)) {
527*4882a593Smuzhiyun                 pScreen = screenInfo.screens[i];
528*4882a593Smuzhiyun                 break;
529*4882a593Smuzhiyun             }
530*4882a593Smuzhiyun         }
531*4882a593Smuzhiyun     }
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun     pSprite->screen = pScreen;
534*4882a593Smuzhiyun     pSprite->hotPhys.x = x - screenInfo.screens[0]->x;
535*4882a593Smuzhiyun     pSprite->hotPhys.y = y - screenInfo.screens[0]->y;
536*4882a593Smuzhiyun     x -= pScreen->x;
537*4882a593Smuzhiyun     y -= pScreen->y;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun     return (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent);
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun static void
XineramaConstrainCursor(DeviceIntPtr pDev)543*4882a593Smuzhiyun XineramaConstrainCursor(DeviceIntPtr pDev)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
546*4882a593Smuzhiyun     ScreenPtr pScreen;
547*4882a593Smuzhiyun     BoxRec newBox;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun     pScreen = pSprite->screen;
550*4882a593Smuzhiyun     newBox = pSprite->physLimits;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun     /* Translate the constraining box to the screen
553*4882a593Smuzhiyun        the sprite is actually on */
554*4882a593Smuzhiyun     newBox.x1 += screenInfo.screens[0]->x - pScreen->x;
555*4882a593Smuzhiyun     newBox.x2 += screenInfo.screens[0]->x - pScreen->x;
556*4882a593Smuzhiyun     newBox.y1 += screenInfo.screens[0]->y - pScreen->y;
557*4882a593Smuzhiyun     newBox.y2 += screenInfo.screens[0]->y - pScreen->y;
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun     (*pScreen->ConstrainCursor) (pDev, pScreen, &newBox);
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun static Bool
XineramaSetWindowPntrs(DeviceIntPtr pDev,WindowPtr pWin)563*4882a593Smuzhiyun XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun     if (pWin == screenInfo.screens[0]->root) {
568*4882a593Smuzhiyun         int i;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun         FOR_NSCREENS(i)
571*4882a593Smuzhiyun             pSprite->windows[i] = screenInfo.screens[i]->root;
572*4882a593Smuzhiyun     }
573*4882a593Smuzhiyun     else {
574*4882a593Smuzhiyun         PanoramiXRes *win;
575*4882a593Smuzhiyun         int rc, i;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun         rc = dixLookupResourceByType((void **) &win, pWin->drawable.id,
578*4882a593Smuzhiyun                                      XRT_WINDOW, serverClient, DixReadAccess);
579*4882a593Smuzhiyun         if (rc != Success)
580*4882a593Smuzhiyun             return FALSE;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun         FOR_NSCREENS(i) {
583*4882a593Smuzhiyun             rc = dixLookupWindow(pSprite->windows + i, win->info[i].id,
584*4882a593Smuzhiyun                                  serverClient, DixReadAccess);
585*4882a593Smuzhiyun             if (rc != Success)  /* window is being unmapped */
586*4882a593Smuzhiyun                 return FALSE;
587*4882a593Smuzhiyun         }
588*4882a593Smuzhiyun     }
589*4882a593Smuzhiyun     return TRUE;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun static void
XineramaConfineCursorToWindow(DeviceIntPtr pDev,WindowPtr pWin,Bool generateEvents)593*4882a593Smuzhiyun XineramaConfineCursorToWindow(DeviceIntPtr pDev,
594*4882a593Smuzhiyun                               WindowPtr pWin, Bool generateEvents)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun     int x, y, off_x, off_y, i;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun     assert(!noPanoramiXExtension);
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun     if (!XineramaSetWindowPntrs(pDev, pWin))
603*4882a593Smuzhiyun         return;
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun     i = PanoramiXNumScreens - 1;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun     RegionCopy(&pSprite->Reg1, &pSprite->windows[i]->borderSize);
608*4882a593Smuzhiyun     off_x = screenInfo.screens[i]->x;
609*4882a593Smuzhiyun     off_y = screenInfo.screens[i]->y;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun     while (i--) {
612*4882a593Smuzhiyun         x = off_x - screenInfo.screens[i]->x;
613*4882a593Smuzhiyun         y = off_y - screenInfo.screens[i]->y;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun         if (x || y)
616*4882a593Smuzhiyun             RegionTranslate(&pSprite->Reg1, x, y);
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun         RegionUnion(&pSprite->Reg1, &pSprite->Reg1,
619*4882a593Smuzhiyun                     &pSprite->windows[i]->borderSize);
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun         off_x = screenInfo.screens[i]->x;
622*4882a593Smuzhiyun         off_y = screenInfo.screens[i]->y;
623*4882a593Smuzhiyun     }
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun     pSprite->hotLimits = *RegionExtents(&pSprite->Reg1);
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun     if (RegionNumRects(&pSprite->Reg1) > 1)
628*4882a593Smuzhiyun         pSprite->hotShape = &pSprite->Reg1;
629*4882a593Smuzhiyun     else
630*4882a593Smuzhiyun         pSprite->hotShape = NullRegion;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun     pSprite->confined = FALSE;
633*4882a593Smuzhiyun     pSprite->confineWin =
634*4882a593Smuzhiyun         (pWin == screenInfo.screens[0]->root) ? NullWindow : pWin;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun     CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL);
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun #endif                          /* PANORAMIX */
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun /**
642*4882a593Smuzhiyun  * Modifies the filter for the given protocol event type to the given masks.
643*4882a593Smuzhiyun  *
644*4882a593Smuzhiyun  * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent().
645*4882a593Smuzhiyun  * The latter initialises masks for the matching XI events, it's a once-off
646*4882a593Smuzhiyun  * setting.
647*4882a593Smuzhiyun  * UDS however changes the mask for MotionNotify and DeviceMotionNotify each
648*4882a593Smuzhiyun  * time a button is pressed to include the matching ButtonXMotion mask in the
649*4882a593Smuzhiyun  * filter.
650*4882a593Smuzhiyun  *
651*4882a593Smuzhiyun  * @param[in] deviceid The device to modify the filter for.
652*4882a593Smuzhiyun  * @param[in] mask The new filter mask.
653*4882a593Smuzhiyun  * @param[in] event Protocol event type.
654*4882a593Smuzhiyun  */
655*4882a593Smuzhiyun void
SetMaskForEvent(int deviceid,Mask mask,int event)656*4882a593Smuzhiyun SetMaskForEvent(int deviceid, Mask mask, int event)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun     if (deviceid < 0 || deviceid >= MAXDEVICES)
659*4882a593Smuzhiyun         FatalError("SetMaskForEvent: bogus device id");
660*4882a593Smuzhiyun     event_filters[deviceid][event] = mask;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun void
SetCriticalEvent(int event)664*4882a593Smuzhiyun SetCriticalEvent(int event)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun     if (event >= MAXEVENTS)
667*4882a593Smuzhiyun         FatalError("SetCriticalEvent: bogus event number");
668*4882a593Smuzhiyun     criticalEvents[event >> 3] |= 1 << (event & 7);
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun void
ConfineToShape(DeviceIntPtr pDev,RegionPtr shape,int * px,int * py)672*4882a593Smuzhiyun ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun     BoxRec box;
675*4882a593Smuzhiyun     int x = *px, y = *py;
676*4882a593Smuzhiyun     int incx = 1, incy = 1;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun     if (RegionContainsPoint(shape, x, y, &box))
679*4882a593Smuzhiyun         return;
680*4882a593Smuzhiyun     box = *RegionExtents(shape);
681*4882a593Smuzhiyun     /* this is rather crude */
682*4882a593Smuzhiyun     do {
683*4882a593Smuzhiyun         x += incx;
684*4882a593Smuzhiyun         if (x >= box.x2) {
685*4882a593Smuzhiyun             incx = -1;
686*4882a593Smuzhiyun             x = *px - 1;
687*4882a593Smuzhiyun         }
688*4882a593Smuzhiyun         else if (x < box.x1) {
689*4882a593Smuzhiyun             incx = 1;
690*4882a593Smuzhiyun             x = *px;
691*4882a593Smuzhiyun             y += incy;
692*4882a593Smuzhiyun             if (y >= box.y2) {
693*4882a593Smuzhiyun                 incy = -1;
694*4882a593Smuzhiyun                 y = *py - 1;
695*4882a593Smuzhiyun             }
696*4882a593Smuzhiyun             else if (y < box.y1)
697*4882a593Smuzhiyun                 return;         /* should never get here! */
698*4882a593Smuzhiyun         }
699*4882a593Smuzhiyun     } while (!RegionContainsPoint(shape, x, y, &box));
700*4882a593Smuzhiyun     *px = x;
701*4882a593Smuzhiyun     *py = y;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun static void
CheckPhysLimits(DeviceIntPtr pDev,CursorPtr cursor,Bool generateEvents,Bool confineToScreen,ScreenPtr pScreen)705*4882a593Smuzhiyun CheckPhysLimits(DeviceIntPtr pDev, CursorPtr cursor, Bool generateEvents,
706*4882a593Smuzhiyun                 Bool confineToScreen, /* unused if PanoramiX on */
707*4882a593Smuzhiyun                 ScreenPtr pScreen)    /* unused if PanoramiX on */
708*4882a593Smuzhiyun {
709*4882a593Smuzhiyun     HotSpot new;
710*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun     if (!cursor)
713*4882a593Smuzhiyun         return;
714*4882a593Smuzhiyun     new = pSprite->hotPhys;
715*4882a593Smuzhiyun #ifdef PANORAMIX
716*4882a593Smuzhiyun     if (!noPanoramiXExtension)
717*4882a593Smuzhiyun         /* I don't care what the DDX has to say about it */
718*4882a593Smuzhiyun         pSprite->physLimits = pSprite->hotLimits;
719*4882a593Smuzhiyun     else
720*4882a593Smuzhiyun #endif
721*4882a593Smuzhiyun     {
722*4882a593Smuzhiyun         if (pScreen)
723*4882a593Smuzhiyun             new.pScreen = pScreen;
724*4882a593Smuzhiyun         else
725*4882a593Smuzhiyun             pScreen = new.pScreen;
726*4882a593Smuzhiyun         (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits,
727*4882a593Smuzhiyun                                   &pSprite->physLimits);
728*4882a593Smuzhiyun         pSprite->confined = confineToScreen;
729*4882a593Smuzhiyun         (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits);
730*4882a593Smuzhiyun     }
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun     /* constrain the pointer to those limits */
733*4882a593Smuzhiyun     if (new.x < pSprite->physLimits.x1)
734*4882a593Smuzhiyun         new.x = pSprite->physLimits.x1;
735*4882a593Smuzhiyun     else if (new.x >= pSprite->physLimits.x2)
736*4882a593Smuzhiyun         new.x = pSprite->physLimits.x2 - 1;
737*4882a593Smuzhiyun     if (new.y < pSprite->physLimits.y1)
738*4882a593Smuzhiyun         new.y = pSprite->physLimits.y1;
739*4882a593Smuzhiyun     else if (new.y >= pSprite->physLimits.y2)
740*4882a593Smuzhiyun         new.y = pSprite->physLimits.y2 - 1;
741*4882a593Smuzhiyun     if (pSprite->hotShape)
742*4882a593Smuzhiyun         ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y);
743*4882a593Smuzhiyun     if ((
744*4882a593Smuzhiyun #ifdef PANORAMIX
745*4882a593Smuzhiyun             noPanoramiXExtension &&
746*4882a593Smuzhiyun #endif
747*4882a593Smuzhiyun             (pScreen != pSprite->hotPhys.pScreen)) ||
748*4882a593Smuzhiyun         (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) {
749*4882a593Smuzhiyun #ifdef PANORAMIX
750*4882a593Smuzhiyun         if (!noPanoramiXExtension)
751*4882a593Smuzhiyun             XineramaSetCursorPosition(pDev, new.x, new.y, generateEvents);
752*4882a593Smuzhiyun         else
753*4882a593Smuzhiyun #endif
754*4882a593Smuzhiyun         {
755*4882a593Smuzhiyun             if (pScreen != pSprite->hotPhys.pScreen)
756*4882a593Smuzhiyun                 pSprite->hotPhys = new;
757*4882a593Smuzhiyun             (*pScreen->SetCursorPosition)
758*4882a593Smuzhiyun                 (pDev, pScreen, new.x, new.y, generateEvents);
759*4882a593Smuzhiyun         }
760*4882a593Smuzhiyun         if (!generateEvents)
761*4882a593Smuzhiyun             SyntheticMotion(pDev, new.x, new.y);
762*4882a593Smuzhiyun     }
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun #ifdef PANORAMIX
765*4882a593Smuzhiyun     /* Tell DDX what the limits are */
766*4882a593Smuzhiyun     if (!noPanoramiXExtension)
767*4882a593Smuzhiyun         XineramaConstrainCursor(pDev);
768*4882a593Smuzhiyun #endif
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun static void
CheckVirtualMotion(DeviceIntPtr pDev,QdEventPtr qe,WindowPtr pWin)772*4882a593Smuzhiyun CheckVirtualMotion(DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin)
773*4882a593Smuzhiyun {
774*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
775*4882a593Smuzhiyun     RegionPtr reg = NULL;
776*4882a593Smuzhiyun     DeviceEvent *ev = NULL;
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun     if (qe) {
779*4882a593Smuzhiyun         ev = &qe->event->device_event;
780*4882a593Smuzhiyun         switch (ev->type) {
781*4882a593Smuzhiyun         case ET_Motion:
782*4882a593Smuzhiyun         case ET_ButtonPress:
783*4882a593Smuzhiyun         case ET_ButtonRelease:
784*4882a593Smuzhiyun         case ET_KeyPress:
785*4882a593Smuzhiyun         case ET_KeyRelease:
786*4882a593Smuzhiyun         case ET_ProximityIn:
787*4882a593Smuzhiyun         case ET_ProximityOut:
788*4882a593Smuzhiyun             pSprite->hot.pScreen = qe->pScreen;
789*4882a593Smuzhiyun             pSprite->hot.x = ev->root_x;
790*4882a593Smuzhiyun             pSprite->hot.y = ev->root_y;
791*4882a593Smuzhiyun             pWin =
792*4882a593Smuzhiyun                 pDev->deviceGrab.grab ? pDev->deviceGrab.grab->
793*4882a593Smuzhiyun                 confineTo : NullWindow;
794*4882a593Smuzhiyun             break;
795*4882a593Smuzhiyun         default:
796*4882a593Smuzhiyun             break;
797*4882a593Smuzhiyun         }
798*4882a593Smuzhiyun     }
799*4882a593Smuzhiyun     if (pWin) {
800*4882a593Smuzhiyun         BoxRec lims;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun #ifdef PANORAMIX
803*4882a593Smuzhiyun         if (!noPanoramiXExtension) {
804*4882a593Smuzhiyun             int x, y, off_x, off_y, i;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun             if (!XineramaSetWindowPntrs(pDev, pWin))
807*4882a593Smuzhiyun                 return;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun             i = PanoramiXNumScreens - 1;
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun             RegionCopy(&pSprite->Reg2, &pSprite->windows[i]->borderSize);
812*4882a593Smuzhiyun             off_x = screenInfo.screens[i]->x;
813*4882a593Smuzhiyun             off_y = screenInfo.screens[i]->y;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun             while (i--) {
816*4882a593Smuzhiyun                 x = off_x - screenInfo.screens[i]->x;
817*4882a593Smuzhiyun                 y = off_y - screenInfo.screens[i]->y;
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun                 if (x || y)
820*4882a593Smuzhiyun                     RegionTranslate(&pSprite->Reg2, x, y);
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun                 RegionUnion(&pSprite->Reg2, &pSprite->Reg2,
823*4882a593Smuzhiyun                             &pSprite->windows[i]->borderSize);
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun                 off_x = screenInfo.screens[i]->x;
826*4882a593Smuzhiyun                 off_y = screenInfo.screens[i]->y;
827*4882a593Smuzhiyun             }
828*4882a593Smuzhiyun         }
829*4882a593Smuzhiyun         else
830*4882a593Smuzhiyun #endif
831*4882a593Smuzhiyun         {
832*4882a593Smuzhiyun             if (pSprite->hot.pScreen != pWin->drawable.pScreen) {
833*4882a593Smuzhiyun                 pSprite->hot.pScreen = pWin->drawable.pScreen;
834*4882a593Smuzhiyun                 pSprite->hot.x = pSprite->hot.y = 0;
835*4882a593Smuzhiyun             }
836*4882a593Smuzhiyun         }
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun         lims = *RegionExtents(&pWin->borderSize);
839*4882a593Smuzhiyun         if (pSprite->hot.x < lims.x1)
840*4882a593Smuzhiyun             pSprite->hot.x = lims.x1;
841*4882a593Smuzhiyun         else if (pSprite->hot.x >= lims.x2)
842*4882a593Smuzhiyun             pSprite->hot.x = lims.x2 - 1;
843*4882a593Smuzhiyun         if (pSprite->hot.y < lims.y1)
844*4882a593Smuzhiyun             pSprite->hot.y = lims.y1;
845*4882a593Smuzhiyun         else if (pSprite->hot.y >= lims.y2)
846*4882a593Smuzhiyun             pSprite->hot.y = lims.y2 - 1;
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun #ifdef PANORAMIX
849*4882a593Smuzhiyun         if (!noPanoramiXExtension) {
850*4882a593Smuzhiyun             if (RegionNumRects(&pSprite->Reg2) > 1)
851*4882a593Smuzhiyun                 reg = &pSprite->Reg2;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun         }
854*4882a593Smuzhiyun         else
855*4882a593Smuzhiyun #endif
856*4882a593Smuzhiyun         {
857*4882a593Smuzhiyun             if (wBoundingShape(pWin))
858*4882a593Smuzhiyun                 reg = &pWin->borderSize;
859*4882a593Smuzhiyun         }
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun         if (reg)
862*4882a593Smuzhiyun             ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y);
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun         if (qe && ev) {
865*4882a593Smuzhiyun             qe->pScreen = pSprite->hot.pScreen;
866*4882a593Smuzhiyun             ev->root_x = pSprite->hot.x;
867*4882a593Smuzhiyun             ev->root_y = pSprite->hot.y;
868*4882a593Smuzhiyun         }
869*4882a593Smuzhiyun     }
870*4882a593Smuzhiyun #ifdef PANORAMIX
871*4882a593Smuzhiyun     if (noPanoramiXExtension)   /* No typo. Only set the root win if disabled */
872*4882a593Smuzhiyun #endif
873*4882a593Smuzhiyun         RootWindow(pDev->spriteInfo->sprite) = pSprite->hot.pScreen->root;
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun static void
ConfineCursorToWindow(DeviceIntPtr pDev,WindowPtr pWin,Bool generateEvents,Bool confineToScreen)877*4882a593Smuzhiyun ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents,
878*4882a593Smuzhiyun                       Bool confineToScreen)
879*4882a593Smuzhiyun {
880*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun     if (syncEvents.playingEvents) {
883*4882a593Smuzhiyun         CheckVirtualMotion(pDev, (QdEventPtr) NULL, pWin);
884*4882a593Smuzhiyun         SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y);
885*4882a593Smuzhiyun     }
886*4882a593Smuzhiyun     else {
887*4882a593Smuzhiyun         ScreenPtr pScreen = pWin->drawable.pScreen;
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun #ifdef PANORAMIX
890*4882a593Smuzhiyun         if (!noPanoramiXExtension) {
891*4882a593Smuzhiyun             XineramaConfineCursorToWindow(pDev, pWin, generateEvents);
892*4882a593Smuzhiyun             return;
893*4882a593Smuzhiyun         }
894*4882a593Smuzhiyun #endif
895*4882a593Smuzhiyun         pSprite->hotLimits = *RegionExtents(&pWin->borderSize);
896*4882a593Smuzhiyun         pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize
897*4882a593Smuzhiyun             : NullRegion;
898*4882a593Smuzhiyun         CheckPhysLimits(pDev, pSprite->current, generateEvents,
899*4882a593Smuzhiyun                         confineToScreen, pWin->drawable.pScreen);
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun         if (*pScreen->CursorConfinedTo)
902*4882a593Smuzhiyun             (*pScreen->CursorConfinedTo) (pDev, pScreen, pWin);
903*4882a593Smuzhiyun     }
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun Bool
PointerConfinedToScreen(DeviceIntPtr pDev)907*4882a593Smuzhiyun PointerConfinedToScreen(DeviceIntPtr pDev)
908*4882a593Smuzhiyun {
909*4882a593Smuzhiyun     return pDev->spriteInfo->sprite->confined;
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun /**
913*4882a593Smuzhiyun  * Update the sprite cursor to the given cursor.
914*4882a593Smuzhiyun  *
915*4882a593Smuzhiyun  * ChangeToCursor() will display the new cursor and free the old cursor (if
916*4882a593Smuzhiyun  * applicable). If the provided cursor is already the updated cursor, nothing
917*4882a593Smuzhiyun  * happens.
918*4882a593Smuzhiyun  */
919*4882a593Smuzhiyun static void
ChangeToCursor(DeviceIntPtr pDev,CursorPtr cursor)920*4882a593Smuzhiyun ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor)
921*4882a593Smuzhiyun {
922*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
923*4882a593Smuzhiyun     ScreenPtr pScreen;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun     if (cursor != pSprite->current) {
926*4882a593Smuzhiyun         if ((pSprite->current->bits->xhot != cursor->bits->xhot) ||
927*4882a593Smuzhiyun             (pSprite->current->bits->yhot != cursor->bits->yhot))
928*4882a593Smuzhiyun             CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined,
929*4882a593Smuzhiyun                             (ScreenPtr) NULL);
930*4882a593Smuzhiyun #ifdef PANORAMIX
931*4882a593Smuzhiyun         /* XXX: is this really necessary?? (whot) */
932*4882a593Smuzhiyun         if (!noPanoramiXExtension)
933*4882a593Smuzhiyun             pScreen = pSprite->screen;
934*4882a593Smuzhiyun         else
935*4882a593Smuzhiyun #endif
936*4882a593Smuzhiyun             pScreen = pSprite->hotPhys.pScreen;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun         (*pScreen->DisplayCursor) (pDev, pScreen, cursor);
939*4882a593Smuzhiyun         FreeCursor(pSprite->current, (Cursor) 0);
940*4882a593Smuzhiyun         pSprite->current = RefCursor(cursor);
941*4882a593Smuzhiyun     }
942*4882a593Smuzhiyun }
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun /**
945*4882a593Smuzhiyun  * @returns true if b is a descendent of a
946*4882a593Smuzhiyun  */
947*4882a593Smuzhiyun Bool
IsParent(WindowPtr a,WindowPtr b)948*4882a593Smuzhiyun IsParent(WindowPtr a, WindowPtr b)
949*4882a593Smuzhiyun {
950*4882a593Smuzhiyun     for (b = b->parent; b; b = b->parent)
951*4882a593Smuzhiyun         if (b == a)
952*4882a593Smuzhiyun             return TRUE;
953*4882a593Smuzhiyun     return FALSE;
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun /**
957*4882a593Smuzhiyun  * Update the cursor displayed on the screen.
958*4882a593Smuzhiyun  *
959*4882a593Smuzhiyun  * Called whenever a cursor may have changed shape or position.
960*4882a593Smuzhiyun  */
961*4882a593Smuzhiyun static void
PostNewCursor(DeviceIntPtr pDev)962*4882a593Smuzhiyun PostNewCursor(DeviceIntPtr pDev)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun     WindowPtr win;
965*4882a593Smuzhiyun     GrabPtr grab = pDev->deviceGrab.grab;
966*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
967*4882a593Smuzhiyun     CursorPtr pCursor;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun     if (syncEvents.playingEvents)
970*4882a593Smuzhiyun         return;
971*4882a593Smuzhiyun     if (grab) {
972*4882a593Smuzhiyun         if (grab->cursor) {
973*4882a593Smuzhiyun             ChangeToCursor(pDev, grab->cursor);
974*4882a593Smuzhiyun             return;
975*4882a593Smuzhiyun         }
976*4882a593Smuzhiyun         if (IsParent(grab->window, pSprite->win))
977*4882a593Smuzhiyun             win = pSprite->win;
978*4882a593Smuzhiyun         else
979*4882a593Smuzhiyun             win = grab->window;
980*4882a593Smuzhiyun     }
981*4882a593Smuzhiyun     else
982*4882a593Smuzhiyun         win = pSprite->win;
983*4882a593Smuzhiyun     for (; win; win = win->parent) {
984*4882a593Smuzhiyun         if (win->optional) {
985*4882a593Smuzhiyun             pCursor = WindowGetDeviceCursor(win, pDev);
986*4882a593Smuzhiyun             if (!pCursor && win->optional->cursor != NullCursor)
987*4882a593Smuzhiyun                 pCursor = win->optional->cursor;
988*4882a593Smuzhiyun             if (pCursor) {
989*4882a593Smuzhiyun                 ChangeToCursor(pDev, pCursor);
990*4882a593Smuzhiyun                 return;
991*4882a593Smuzhiyun             }
992*4882a593Smuzhiyun         }
993*4882a593Smuzhiyun     }
994*4882a593Smuzhiyun }
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun /**
997*4882a593Smuzhiyun  * @param dev device which you want to know its current root window
998*4882a593Smuzhiyun  * @return root window where dev's sprite is located
999*4882a593Smuzhiyun  */
1000*4882a593Smuzhiyun WindowPtr
GetCurrentRootWindow(DeviceIntPtr dev)1001*4882a593Smuzhiyun GetCurrentRootWindow(DeviceIntPtr dev)
1002*4882a593Smuzhiyun {
1003*4882a593Smuzhiyun     return RootWindow(dev->spriteInfo->sprite);
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun /**
1007*4882a593Smuzhiyun  * @return window underneath the cursor sprite.
1008*4882a593Smuzhiyun  */
1009*4882a593Smuzhiyun WindowPtr
GetSpriteWindow(DeviceIntPtr pDev)1010*4882a593Smuzhiyun GetSpriteWindow(DeviceIntPtr pDev)
1011*4882a593Smuzhiyun {
1012*4882a593Smuzhiyun     return pDev->spriteInfo->sprite->win;
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun /**
1016*4882a593Smuzhiyun  * @return current sprite cursor.
1017*4882a593Smuzhiyun  */
1018*4882a593Smuzhiyun CursorPtr
GetSpriteCursor(DeviceIntPtr pDev)1019*4882a593Smuzhiyun GetSpriteCursor(DeviceIntPtr pDev)
1020*4882a593Smuzhiyun {
1021*4882a593Smuzhiyun     return pDev->spriteInfo->sprite->current;
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun /**
1025*4882a593Smuzhiyun  * Set x/y current sprite position in screen coordinates.
1026*4882a593Smuzhiyun  */
1027*4882a593Smuzhiyun void
GetSpritePosition(DeviceIntPtr pDev,int * px,int * py)1028*4882a593Smuzhiyun GetSpritePosition(DeviceIntPtr pDev, int *px, int *py)
1029*4882a593Smuzhiyun {
1030*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun     *px = pSprite->hotPhys.x;
1033*4882a593Smuzhiyun     *py = pSprite->hotPhys.y;
1034*4882a593Smuzhiyun }
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun #ifdef PANORAMIX
1037*4882a593Smuzhiyun int
XineramaGetCursorScreen(DeviceIntPtr pDev)1038*4882a593Smuzhiyun XineramaGetCursorScreen(DeviceIntPtr pDev)
1039*4882a593Smuzhiyun {
1040*4882a593Smuzhiyun     if (!noPanoramiXExtension) {
1041*4882a593Smuzhiyun         return pDev->spriteInfo->sprite->screen->myNum;
1042*4882a593Smuzhiyun     }
1043*4882a593Smuzhiyun     else {
1044*4882a593Smuzhiyun         return 0;
1045*4882a593Smuzhiyun     }
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun #endif                          /* PANORAMIX */
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun #define TIMESLOP (5 * 60 * 1000)        /* 5 minutes */
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun static void
MonthChangedOrBadTime(CARD32 * ms)1052*4882a593Smuzhiyun MonthChangedOrBadTime(CARD32 *ms)
1053*4882a593Smuzhiyun {
1054*4882a593Smuzhiyun     /* If the ddx/OS is careless about not processing timestamped events from
1055*4882a593Smuzhiyun      * different sources in sorted order, then it's possible for time to go
1056*4882a593Smuzhiyun      * backwards when it should not.  Here we ensure a decent time.
1057*4882a593Smuzhiyun      */
1058*4882a593Smuzhiyun     if ((currentTime.milliseconds - *ms) > TIMESLOP)
1059*4882a593Smuzhiyun         currentTime.months++;
1060*4882a593Smuzhiyun     else
1061*4882a593Smuzhiyun         *ms = currentTime.milliseconds;
1062*4882a593Smuzhiyun }
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun void
NoticeTime(const DeviceIntPtr dev,TimeStamp time)1065*4882a593Smuzhiyun NoticeTime(const DeviceIntPtr dev, TimeStamp time)
1066*4882a593Smuzhiyun {
1067*4882a593Smuzhiyun     currentTime = time;
1068*4882a593Smuzhiyun     lastDeviceEventTime[XIAllDevices].time = currentTime;
1069*4882a593Smuzhiyun     lastDeviceEventTime[dev->id].time = currentTime;
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun     LastEventTimeToggleResetFlag(dev->id, TRUE);
1072*4882a593Smuzhiyun     LastEventTimeToggleResetFlag(XIAllDevices, TRUE);
1073*4882a593Smuzhiyun }
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun static void
NoticeTimeMillis(const DeviceIntPtr dev,CARD32 * ms)1076*4882a593Smuzhiyun NoticeTimeMillis(const DeviceIntPtr dev, CARD32 *ms)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun     TimeStamp time;
1079*4882a593Smuzhiyun     if (*ms < currentTime.milliseconds)
1080*4882a593Smuzhiyun         MonthChangedOrBadTime(ms);
1081*4882a593Smuzhiyun     time.months = currentTime.months;
1082*4882a593Smuzhiyun     time.milliseconds = *ms;
1083*4882a593Smuzhiyun     NoticeTime(dev, time);
1084*4882a593Smuzhiyun }
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun void
NoticeEventTime(InternalEvent * ev,DeviceIntPtr dev)1087*4882a593Smuzhiyun NoticeEventTime(InternalEvent *ev, DeviceIntPtr dev)
1088*4882a593Smuzhiyun {
1089*4882a593Smuzhiyun     if (!syncEvents.playingEvents)
1090*4882a593Smuzhiyun         NoticeTimeMillis(dev, &ev->any.time);
1091*4882a593Smuzhiyun }
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun TimeStamp
LastEventTime(int deviceid)1094*4882a593Smuzhiyun LastEventTime(int deviceid)
1095*4882a593Smuzhiyun {
1096*4882a593Smuzhiyun     return lastDeviceEventTime[deviceid].time;
1097*4882a593Smuzhiyun }
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun Bool
LastEventTimeWasReset(int deviceid)1100*4882a593Smuzhiyun LastEventTimeWasReset(int deviceid)
1101*4882a593Smuzhiyun {
1102*4882a593Smuzhiyun     return lastDeviceEventTime[deviceid].reset;
1103*4882a593Smuzhiyun }
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun void
LastEventTimeToggleResetFlag(int deviceid,Bool state)1106*4882a593Smuzhiyun LastEventTimeToggleResetFlag(int deviceid, Bool state)
1107*4882a593Smuzhiyun {
1108*4882a593Smuzhiyun     lastDeviceEventTime[deviceid].reset = state;
1109*4882a593Smuzhiyun }
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun void
LastEventTimeToggleResetAll(Bool state)1112*4882a593Smuzhiyun LastEventTimeToggleResetAll(Bool state)
1113*4882a593Smuzhiyun {
1114*4882a593Smuzhiyun     DeviceIntPtr dev;
1115*4882a593Smuzhiyun     nt_list_for_each_entry(dev, inputInfo.devices, next) {
1116*4882a593Smuzhiyun         LastEventTimeToggleResetFlag(dev->id, FALSE);
1117*4882a593Smuzhiyun     }
1118*4882a593Smuzhiyun     LastEventTimeToggleResetFlag(XIAllDevices, FALSE);
1119*4882a593Smuzhiyun     LastEventTimeToggleResetFlag(XIAllMasterDevices, FALSE);
1120*4882a593Smuzhiyun }
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun /**************************************************************************
1123*4882a593Smuzhiyun  *            The following procedures deal with synchronous events       *
1124*4882a593Smuzhiyun  **************************************************************************/
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun /**
1127*4882a593Smuzhiyun  * EnqueueEvent is a device's processInputProc if a device is frozen.
1128*4882a593Smuzhiyun  * Instead of delivering the events to the client, the event is tacked onto a
1129*4882a593Smuzhiyun  * linked list for later delivery.
1130*4882a593Smuzhiyun  */
1131*4882a593Smuzhiyun void
EnqueueEvent(InternalEvent * ev,DeviceIntPtr device)1132*4882a593Smuzhiyun EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
1133*4882a593Smuzhiyun {
1134*4882a593Smuzhiyun     QdEventPtr tail = NULL;
1135*4882a593Smuzhiyun     QdEventPtr qe;
1136*4882a593Smuzhiyun     SpritePtr pSprite = device->spriteInfo->sprite;
1137*4882a593Smuzhiyun     int eventlen;
1138*4882a593Smuzhiyun     DeviceEvent *event = &ev->device_event;
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun     if (!xorg_list_is_empty(&syncEvents.pending))
1141*4882a593Smuzhiyun         tail = xorg_list_last_entry(&syncEvents.pending, QdEventRec, next);
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun     NoticeTimeMillis(device, &ev->any.time);
1144*4882a593Smuzhiyun 
1145*4882a593Smuzhiyun     /* Fix for key repeating bug. */
1146*4882a593Smuzhiyun     if (device->key != NULL && device->key->xkbInfo != NULL &&
1147*4882a593Smuzhiyun         event->type == ET_KeyRelease)
1148*4882a593Smuzhiyun         AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key);
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun     if (DeviceEventCallback) {
1151*4882a593Smuzhiyun         DeviceEventInfoRec eventinfo;
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun         /*  The RECORD spec says that the root window field of motion events
1154*4882a593Smuzhiyun          *  must be valid.  At this point, it hasn't been filled in yet, so
1155*4882a593Smuzhiyun          *  we do it here.  The long expression below is necessary to get
1156*4882a593Smuzhiyun          *  the current root window; the apparently reasonable alternative
1157*4882a593Smuzhiyun          *  GetCurrentRootWindow()->drawable.id doesn't give you the right
1158*4882a593Smuzhiyun          *  answer on the first motion event after a screen change because
1159*4882a593Smuzhiyun          *  the data that GetCurrentRootWindow relies on hasn't been
1160*4882a593Smuzhiyun          *  updated yet.
1161*4882a593Smuzhiyun          */
1162*4882a593Smuzhiyun         if (ev->any.type == ET_Motion)
1163*4882a593Smuzhiyun             ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id;
1164*4882a593Smuzhiyun 
1165*4882a593Smuzhiyun         eventinfo.event = ev;
1166*4882a593Smuzhiyun         eventinfo.device = device;
1167*4882a593Smuzhiyun         CallCallbacks(&DeviceEventCallback, (void *) &eventinfo);
1168*4882a593Smuzhiyun     }
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun     if (event->type == ET_Motion) {
1171*4882a593Smuzhiyun #ifdef PANORAMIX
1172*4882a593Smuzhiyun         if (!noPanoramiXExtension) {
1173*4882a593Smuzhiyun             event->root_x += pSprite->screen->x - screenInfo.screens[0]->x;
1174*4882a593Smuzhiyun             event->root_y += pSprite->screen->y - screenInfo.screens[0]->y;
1175*4882a593Smuzhiyun         }
1176*4882a593Smuzhiyun #endif
1177*4882a593Smuzhiyun         pSprite->hotPhys.x = event->root_x;
1178*4882a593Smuzhiyun         pSprite->hotPhys.y = event->root_y;
1179*4882a593Smuzhiyun         /* do motion compression, but not if from different devices */
1180*4882a593Smuzhiyun         if (tail &&
1181*4882a593Smuzhiyun             (tail->event->any.type == ET_Motion) &&
1182*4882a593Smuzhiyun             (tail->device == device) &&
1183*4882a593Smuzhiyun             (tail->pScreen == pSprite->hotPhys.pScreen)) {
1184*4882a593Smuzhiyun             DeviceEvent *tailev = &tail->event->device_event;
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun             tailev->root_x = pSprite->hotPhys.x;
1187*4882a593Smuzhiyun             tailev->root_y = pSprite->hotPhys.y;
1188*4882a593Smuzhiyun             tailev->time = event->time;
1189*4882a593Smuzhiyun             tail->months = currentTime.months;
1190*4882a593Smuzhiyun             return;
1191*4882a593Smuzhiyun         }
1192*4882a593Smuzhiyun     }
1193*4882a593Smuzhiyun 
1194*4882a593Smuzhiyun     eventlen = event->length;
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun     qe = malloc(sizeof(QdEventRec) + eventlen);
1197*4882a593Smuzhiyun     if (!qe)
1198*4882a593Smuzhiyun         return;
1199*4882a593Smuzhiyun     xorg_list_init(&qe->next);
1200*4882a593Smuzhiyun     qe->device = device;
1201*4882a593Smuzhiyun     qe->pScreen = pSprite->hotPhys.pScreen;
1202*4882a593Smuzhiyun     qe->months = currentTime.months;
1203*4882a593Smuzhiyun     qe->event = (InternalEvent *) (qe + 1);
1204*4882a593Smuzhiyun     memcpy(qe->event, event, eventlen);
1205*4882a593Smuzhiyun     xorg_list_append(&qe->next, &syncEvents.pending);
1206*4882a593Smuzhiyun }
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun /**
1209*4882a593Smuzhiyun  * Run through the list of events queued up in syncEvents.
1210*4882a593Smuzhiyun  * For each event do:
1211*4882a593Smuzhiyun  * If the device for this event is not frozen anymore, take it and process it
1212*4882a593Smuzhiyun  * as usually.
1213*4882a593Smuzhiyun  * After that, check if there's any devices in the list that are not frozen.
1214*4882a593Smuzhiyun  * If there is none, we're done. If there is at least one device that is not
1215*4882a593Smuzhiyun  * frozen, then re-run from the beginning of the event queue.
1216*4882a593Smuzhiyun  */
1217*4882a593Smuzhiyun void
PlayReleasedEvents(void)1218*4882a593Smuzhiyun PlayReleasedEvents(void)
1219*4882a593Smuzhiyun {
1220*4882a593Smuzhiyun     QdEventPtr tmp;
1221*4882a593Smuzhiyun     QdEventPtr qe;
1222*4882a593Smuzhiyun     DeviceIntPtr dev;
1223*4882a593Smuzhiyun     DeviceIntPtr pDev;
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun  restart:
1226*4882a593Smuzhiyun     xorg_list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next) {
1227*4882a593Smuzhiyun         if (!qe->device->deviceGrab.sync.frozen) {
1228*4882a593Smuzhiyun             xorg_list_del(&qe->next);
1229*4882a593Smuzhiyun             pDev = qe->device;
1230*4882a593Smuzhiyun             if (qe->event->any.type == ET_Motion)
1231*4882a593Smuzhiyun                 CheckVirtualMotion(pDev, qe, NullWindow);
1232*4882a593Smuzhiyun             syncEvents.time.months = qe->months;
1233*4882a593Smuzhiyun             syncEvents.time.milliseconds = qe->event->any.time;
1234*4882a593Smuzhiyun #ifdef PANORAMIX
1235*4882a593Smuzhiyun             /* Translate back to the sprite screen since processInputProc
1236*4882a593Smuzhiyun                will translate from sprite screen to screen 0 upon reentry
1237*4882a593Smuzhiyun                to the DIX layer */
1238*4882a593Smuzhiyun             if (!noPanoramiXExtension) {
1239*4882a593Smuzhiyun                 DeviceEvent *ev = &qe->event->device_event;
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun                 switch (ev->type) {
1242*4882a593Smuzhiyun                 case ET_Motion:
1243*4882a593Smuzhiyun                 case ET_ButtonPress:
1244*4882a593Smuzhiyun                 case ET_ButtonRelease:
1245*4882a593Smuzhiyun                 case ET_KeyPress:
1246*4882a593Smuzhiyun                 case ET_KeyRelease:
1247*4882a593Smuzhiyun                 case ET_ProximityIn:
1248*4882a593Smuzhiyun                 case ET_ProximityOut:
1249*4882a593Smuzhiyun                 case ET_TouchBegin:
1250*4882a593Smuzhiyun                 case ET_TouchUpdate:
1251*4882a593Smuzhiyun                 case ET_TouchEnd:
1252*4882a593Smuzhiyun                     ev->root_x += screenInfo.screens[0]->x -
1253*4882a593Smuzhiyun                         pDev->spriteInfo->sprite->screen->x;
1254*4882a593Smuzhiyun                     ev->root_y += screenInfo.screens[0]->y -
1255*4882a593Smuzhiyun                         pDev->spriteInfo->sprite->screen->y;
1256*4882a593Smuzhiyun                     break;
1257*4882a593Smuzhiyun                 default:
1258*4882a593Smuzhiyun                     break;
1259*4882a593Smuzhiyun                 }
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun             }
1262*4882a593Smuzhiyun #endif
1263*4882a593Smuzhiyun             (*qe->device->public.processInputProc) (qe->event, qe->device);
1264*4882a593Smuzhiyun             free(qe);
1265*4882a593Smuzhiyun             for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen;
1266*4882a593Smuzhiyun                  dev = dev->next);
1267*4882a593Smuzhiyun             if (!dev)
1268*4882a593Smuzhiyun                 break;
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun             /* Playing the event may have unfrozen another device. */
1271*4882a593Smuzhiyun             /* So to play it safe, restart at the head of the queue */
1272*4882a593Smuzhiyun             goto restart;
1273*4882a593Smuzhiyun         }
1274*4882a593Smuzhiyun     }
1275*4882a593Smuzhiyun }
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun /**
1278*4882a593Smuzhiyun  * Freeze or thaw the given devices. The device's processing proc is
1279*4882a593Smuzhiyun  * switched to either the real processing proc (in case of thawing) or an
1280*4882a593Smuzhiyun  * enqueuing processing proc (usually EnqueueEvent()).
1281*4882a593Smuzhiyun  *
1282*4882a593Smuzhiyun  * @param dev The device to freeze/thaw
1283*4882a593Smuzhiyun  * @param frozen True to freeze or false to thaw.
1284*4882a593Smuzhiyun  */
1285*4882a593Smuzhiyun static void
FreezeThaw(DeviceIntPtr dev,Bool frozen)1286*4882a593Smuzhiyun FreezeThaw(DeviceIntPtr dev, Bool frozen)
1287*4882a593Smuzhiyun {
1288*4882a593Smuzhiyun     dev->deviceGrab.sync.frozen = frozen;
1289*4882a593Smuzhiyun     if (frozen)
1290*4882a593Smuzhiyun         dev->public.processInputProc = dev->public.enqueueInputProc;
1291*4882a593Smuzhiyun     else
1292*4882a593Smuzhiyun         dev->public.processInputProc = dev->public.realInputProc;
1293*4882a593Smuzhiyun }
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun /**
1296*4882a593Smuzhiyun  * Unfreeze devices and replay all events to the respective clients.
1297*4882a593Smuzhiyun  *
1298*4882a593Smuzhiyun  * ComputeFreezes takes the first event in the device's frozen event queue. It
1299*4882a593Smuzhiyun  * runs up the sprite tree (spriteTrace) and searches for the window to replay
1300*4882a593Smuzhiyun  * the events from. If it is found, it checks for passive grabs one down from
1301*4882a593Smuzhiyun  * the window or delivers the events.
1302*4882a593Smuzhiyun  */
1303*4882a593Smuzhiyun static void
ComputeFreezes(void)1304*4882a593Smuzhiyun ComputeFreezes(void)
1305*4882a593Smuzhiyun {
1306*4882a593Smuzhiyun     DeviceIntPtr replayDev = syncEvents.replayDev;
1307*4882a593Smuzhiyun     WindowPtr w;
1308*4882a593Smuzhiyun     GrabPtr grab;
1309*4882a593Smuzhiyun     DeviceIntPtr dev;
1310*4882a593Smuzhiyun 
1311*4882a593Smuzhiyun     for (dev = inputInfo.devices; dev; dev = dev->next)
1312*4882a593Smuzhiyun         FreezeThaw(dev, dev->deviceGrab.sync.other ||
1313*4882a593Smuzhiyun                    (dev->deviceGrab.sync.state >= FROZEN));
1314*4882a593Smuzhiyun     if (syncEvents.playingEvents ||
1315*4882a593Smuzhiyun         (!replayDev && xorg_list_is_empty(&syncEvents.pending)))
1316*4882a593Smuzhiyun         return;
1317*4882a593Smuzhiyun     syncEvents.playingEvents = TRUE;
1318*4882a593Smuzhiyun     if (replayDev) {
1319*4882a593Smuzhiyun         DeviceEvent *event = replayDev->deviceGrab.sync.event;
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun         syncEvents.replayDev = (DeviceIntPtr) NULL;
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun         w = XYToWindow(replayDev->spriteInfo->sprite,
1324*4882a593Smuzhiyun                        event->root_x, event->root_y);
1325*4882a593Smuzhiyun         if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin)) {
1326*4882a593Smuzhiyun             if (IsTouchEvent((InternalEvent *) event)) {
1327*4882a593Smuzhiyun                 TouchPointInfoPtr ti =
1328*4882a593Smuzhiyun                     TouchFindByClientID(replayDev, event->touchid);
1329*4882a593Smuzhiyun                 BUG_WARN(!ti);
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun                 TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
1332*4882a593Smuzhiyun             }
1333*4882a593Smuzhiyun             else if (replayDev->focus &&
1334*4882a593Smuzhiyun                      !IsPointerEvent((InternalEvent *) event))
1335*4882a593Smuzhiyun                 DeliverFocusedEvent(replayDev, (InternalEvent *) event, w);
1336*4882a593Smuzhiyun             else
1337*4882a593Smuzhiyun                 DeliverDeviceEvents(w, (InternalEvent *) event, NullGrab,
1338*4882a593Smuzhiyun                                     NullWindow, replayDev);
1339*4882a593Smuzhiyun         }
1340*4882a593Smuzhiyun     }
1341*4882a593Smuzhiyun     for (dev = inputInfo.devices; dev; dev = dev->next) {
1342*4882a593Smuzhiyun         if (!dev->deviceGrab.sync.frozen) {
1343*4882a593Smuzhiyun             PlayReleasedEvents();
1344*4882a593Smuzhiyun             break;
1345*4882a593Smuzhiyun         }
1346*4882a593Smuzhiyun     }
1347*4882a593Smuzhiyun     syncEvents.playingEvents = FALSE;
1348*4882a593Smuzhiyun     for (dev = inputInfo.devices; dev; dev = dev->next) {
1349*4882a593Smuzhiyun         if (DevHasCursor(dev)) {
1350*4882a593Smuzhiyun             /* the following may have been skipped during replay,
1351*4882a593Smuzhiyun                so do it now */
1352*4882a593Smuzhiyun             if ((grab = dev->deviceGrab.grab) && grab->confineTo) {
1353*4882a593Smuzhiyun                 if (grab->confineTo->drawable.pScreen !=
1354*4882a593Smuzhiyun                     dev->spriteInfo->sprite->hotPhys.pScreen)
1355*4882a593Smuzhiyun                     dev->spriteInfo->sprite->hotPhys.x =
1356*4882a593Smuzhiyun                         dev->spriteInfo->sprite->hotPhys.y = 0;
1357*4882a593Smuzhiyun                 ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE);
1358*4882a593Smuzhiyun             }
1359*4882a593Smuzhiyun             else
1360*4882a593Smuzhiyun                 ConfineCursorToWindow(dev,
1361*4882a593Smuzhiyun                                       dev->spriteInfo->sprite->hotPhys.pScreen->
1362*4882a593Smuzhiyun                                       root, TRUE, FALSE);
1363*4882a593Smuzhiyun             PostNewCursor(dev);
1364*4882a593Smuzhiyun         }
1365*4882a593Smuzhiyun     }
1366*4882a593Smuzhiyun }
1367*4882a593Smuzhiyun 
1368*4882a593Smuzhiyun #ifdef RANDR
1369*4882a593Smuzhiyun void
ScreenRestructured(ScreenPtr pScreen)1370*4882a593Smuzhiyun ScreenRestructured(ScreenPtr pScreen)
1371*4882a593Smuzhiyun {
1372*4882a593Smuzhiyun     GrabPtr grab;
1373*4882a593Smuzhiyun     DeviceIntPtr pDev;
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
1376*4882a593Smuzhiyun         if (!IsFloating(pDev) && !DevHasCursor(pDev))
1377*4882a593Smuzhiyun             continue;
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun         /* GrabDevice doesn't have a confineTo field, so we don't need to
1380*4882a593Smuzhiyun          * worry about it. */
1381*4882a593Smuzhiyun         if ((grab = pDev->deviceGrab.grab) && grab->confineTo) {
1382*4882a593Smuzhiyun             if (grab->confineTo->drawable.pScreen
1383*4882a593Smuzhiyun                 != pDev->spriteInfo->sprite->hotPhys.pScreen)
1384*4882a593Smuzhiyun                 pDev->spriteInfo->sprite->hotPhys.x =
1385*4882a593Smuzhiyun                     pDev->spriteInfo->sprite->hotPhys.y = 0;
1386*4882a593Smuzhiyun             ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE);
1387*4882a593Smuzhiyun         }
1388*4882a593Smuzhiyun         else
1389*4882a593Smuzhiyun             ConfineCursorToWindow(pDev,
1390*4882a593Smuzhiyun                                   pDev->spriteInfo->sprite->hotPhys.pScreen->
1391*4882a593Smuzhiyun                                   root, TRUE, FALSE);
1392*4882a593Smuzhiyun     }
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun #endif
1395*4882a593Smuzhiyun 
1396*4882a593Smuzhiyun static void
CheckGrabForSyncs(DeviceIntPtr thisDev,Bool thisMode,Bool otherMode)1397*4882a593Smuzhiyun CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode)
1398*4882a593Smuzhiyun {
1399*4882a593Smuzhiyun     GrabPtr grab = thisDev->deviceGrab.grab;
1400*4882a593Smuzhiyun     DeviceIntPtr dev;
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun     if (thisMode == GrabModeSync)
1403*4882a593Smuzhiyun         thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT;
1404*4882a593Smuzhiyun     else {                      /* free both if same client owns both */
1405*4882a593Smuzhiyun         thisDev->deviceGrab.sync.state = THAWED;
1406*4882a593Smuzhiyun         if (thisDev->deviceGrab.sync.other &&
1407*4882a593Smuzhiyun             (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) ==
1408*4882a593Smuzhiyun              CLIENT_BITS(grab->resource)))
1409*4882a593Smuzhiyun             thisDev->deviceGrab.sync.other = NullGrab;
1410*4882a593Smuzhiyun     }
1411*4882a593Smuzhiyun 
1412*4882a593Smuzhiyun     if (IsMaster(thisDev)) {
1413*4882a593Smuzhiyun         dev = GetPairedDevice(thisDev);
1414*4882a593Smuzhiyun         if (otherMode == GrabModeSync)
1415*4882a593Smuzhiyun             dev->deviceGrab.sync.other = grab;
1416*4882a593Smuzhiyun         else {                  /* free both if same client owns both */
1417*4882a593Smuzhiyun             if (dev->deviceGrab.sync.other &&
1418*4882a593Smuzhiyun                 (CLIENT_BITS(dev->deviceGrab.sync.other->resource) ==
1419*4882a593Smuzhiyun                  CLIENT_BITS(grab->resource)))
1420*4882a593Smuzhiyun                 dev->deviceGrab.sync.other = NullGrab;
1421*4882a593Smuzhiyun         }
1422*4882a593Smuzhiyun     }
1423*4882a593Smuzhiyun     ComputeFreezes();
1424*4882a593Smuzhiyun }
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun /**
1427*4882a593Smuzhiyun  * Save the device's master device id. This needs to be done
1428*4882a593Smuzhiyun  * if a client directly grabs a slave device that is attached to a master. For
1429*4882a593Smuzhiyun  * the duration of the grab, the device is detached, ungrabbing re-attaches it
1430*4882a593Smuzhiyun  * though.
1431*4882a593Smuzhiyun  *
1432*4882a593Smuzhiyun  * We store the ID of the master device only in case the master disappears
1433*4882a593Smuzhiyun  * while the device has a grab.
1434*4882a593Smuzhiyun  */
1435*4882a593Smuzhiyun static void
DetachFromMaster(DeviceIntPtr dev)1436*4882a593Smuzhiyun DetachFromMaster(DeviceIntPtr dev)
1437*4882a593Smuzhiyun {
1438*4882a593Smuzhiyun     if (IsFloating(dev))
1439*4882a593Smuzhiyun         return;
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun     dev->saved_master_id = GetMaster(dev, MASTER_ATTACHED)->id;
1442*4882a593Smuzhiyun 
1443*4882a593Smuzhiyun     AttachDevice(NULL, dev, NULL);
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun static void
ReattachToOldMaster(DeviceIntPtr dev)1447*4882a593Smuzhiyun ReattachToOldMaster(DeviceIntPtr dev)
1448*4882a593Smuzhiyun {
1449*4882a593Smuzhiyun     DeviceIntPtr master = NULL;
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun     if (IsMaster(dev))
1452*4882a593Smuzhiyun         return;
1453*4882a593Smuzhiyun 
1454*4882a593Smuzhiyun     dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess);
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun     if (master) {
1457*4882a593Smuzhiyun         AttachDevice(serverClient, dev, master);
1458*4882a593Smuzhiyun         dev->saved_master_id = 0;
1459*4882a593Smuzhiyun     }
1460*4882a593Smuzhiyun }
1461*4882a593Smuzhiyun 
1462*4882a593Smuzhiyun /**
1463*4882a593Smuzhiyun  * Update touch records when an explicit grab is activated. Any touches owned by
1464*4882a593Smuzhiyun  * the grabbing client are updated so the listener state reflects the new grab.
1465*4882a593Smuzhiyun  */
1466*4882a593Smuzhiyun static void
UpdateTouchesForGrab(DeviceIntPtr mouse)1467*4882a593Smuzhiyun UpdateTouchesForGrab(DeviceIntPtr mouse)
1468*4882a593Smuzhiyun {
1469*4882a593Smuzhiyun     int i;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun     if (!mouse->touch || mouse->deviceGrab.fromPassiveGrab)
1472*4882a593Smuzhiyun         return;
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun     for (i = 0; i < mouse->touch->num_touches; i++) {
1475*4882a593Smuzhiyun         TouchPointInfoPtr ti = mouse->touch->touches + i;
1476*4882a593Smuzhiyun         TouchListener *listener = &ti->listeners[0];
1477*4882a593Smuzhiyun         GrabPtr grab = mouse->deviceGrab.grab;
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun         if (ti->active &&
1480*4882a593Smuzhiyun             CLIENT_BITS(listener->listener) == grab->resource) {
1481*4882a593Smuzhiyun             listener->listener = grab->resource;
1482*4882a593Smuzhiyun             listener->level = grab->grabtype;
1483*4882a593Smuzhiyun             listener->state = LISTENER_IS_OWNER;
1484*4882a593Smuzhiyun             listener->window = grab->window;
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun             if (grab->grabtype == CORE || grab->grabtype == XI ||
1487*4882a593Smuzhiyun                 !xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin))
1488*4882a593Smuzhiyun                 listener->type = LISTENER_POINTER_GRAB;
1489*4882a593Smuzhiyun             else
1490*4882a593Smuzhiyun                 listener->type = LISTENER_GRAB;
1491*4882a593Smuzhiyun             if (listener->grab)
1492*4882a593Smuzhiyun                 FreeGrab(listener->grab);
1493*4882a593Smuzhiyun             listener->grab = AllocGrab(grab);
1494*4882a593Smuzhiyun         }
1495*4882a593Smuzhiyun     }
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun /**
1499*4882a593Smuzhiyun  * Activate a pointer grab on the given device. A pointer grab will cause all
1500*4882a593Smuzhiyun  * core pointer events of this device to be delivered to the grabbing client only.
1501*4882a593Smuzhiyun  * No other device will send core events to the grab client while the grab is
1502*4882a593Smuzhiyun  * on, but core events will be sent to other clients.
1503*4882a593Smuzhiyun  * Can cause the cursor to change if a grab cursor is set.
1504*4882a593Smuzhiyun  *
1505*4882a593Smuzhiyun  * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab
1506*4882a593Smuzhiyun  * is an implicit grab caused by a ButtonPress event.
1507*4882a593Smuzhiyun  *
1508*4882a593Smuzhiyun  * @param mouse The device to grab.
1509*4882a593Smuzhiyun  * @param grab The grab structure, needs to be setup.
1510*4882a593Smuzhiyun  * @param autoGrab True if the grab was caused by a button down event and not
1511*4882a593Smuzhiyun  * explicitely by a client.
1512*4882a593Smuzhiyun  */
1513*4882a593Smuzhiyun void
ActivatePointerGrab(DeviceIntPtr mouse,GrabPtr grab,TimeStamp time,Bool autoGrab)1514*4882a593Smuzhiyun ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
1515*4882a593Smuzhiyun                     TimeStamp time, Bool autoGrab)
1516*4882a593Smuzhiyun {
1517*4882a593Smuzhiyun     GrabInfoPtr grabinfo = &mouse->deviceGrab;
1518*4882a593Smuzhiyun     GrabPtr oldgrab = grabinfo->grab;
1519*4882a593Smuzhiyun     WindowPtr oldWin = (grabinfo->grab) ?
1520*4882a593Smuzhiyun         grabinfo->grab->window : mouse->spriteInfo->sprite->win;
1521*4882a593Smuzhiyun     Bool isPassive = autoGrab & ~ImplicitGrabMask;
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun     /* slave devices need to float for the duration of the grab. */
1524*4882a593Smuzhiyun     if (grab->grabtype == XI2 &&
1525*4882a593Smuzhiyun         !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse))
1526*4882a593Smuzhiyun         DetachFromMaster(mouse);
1527*4882a593Smuzhiyun 
1528*4882a593Smuzhiyun     if (grab->confineTo) {
1529*4882a593Smuzhiyun         if (grab->confineTo->drawable.pScreen
1530*4882a593Smuzhiyun             != mouse->spriteInfo->sprite->hotPhys.pScreen)
1531*4882a593Smuzhiyun             mouse->spriteInfo->sprite->hotPhys.x =
1532*4882a593Smuzhiyun                 mouse->spriteInfo->sprite->hotPhys.y = 0;
1533*4882a593Smuzhiyun         ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE);
1534*4882a593Smuzhiyun     }
1535*4882a593Smuzhiyun     if (! (grabinfo->grab && oldWin == grabinfo->grab->window
1536*4882a593Smuzhiyun 			  && oldWin == grab->window))
1537*4882a593Smuzhiyun         DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab);
1538*4882a593Smuzhiyun     mouse->valuator->motionHintWindow = NullWindow;
1539*4882a593Smuzhiyun     if (syncEvents.playingEvents)
1540*4882a593Smuzhiyun         grabinfo->grabTime = syncEvents.time;
1541*4882a593Smuzhiyun     else
1542*4882a593Smuzhiyun         grabinfo->grabTime = time;
1543*4882a593Smuzhiyun     grabinfo->grab = AllocGrab(grab);
1544*4882a593Smuzhiyun     grabinfo->fromPassiveGrab = isPassive;
1545*4882a593Smuzhiyun     grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
1546*4882a593Smuzhiyun     PostNewCursor(mouse);
1547*4882a593Smuzhiyun     UpdateTouchesForGrab(mouse);
1548*4882a593Smuzhiyun     CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
1549*4882a593Smuzhiyun                       (Bool) grab->keyboardMode);
1550*4882a593Smuzhiyun     if (oldgrab)
1551*4882a593Smuzhiyun         FreeGrab(oldgrab);
1552*4882a593Smuzhiyun }
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun /**
1555*4882a593Smuzhiyun  * Delete grab on given device, update the sprite.
1556*4882a593Smuzhiyun  *
1557*4882a593Smuzhiyun  * Extension devices are set up for ActivateKeyboardGrab().
1558*4882a593Smuzhiyun  */
1559*4882a593Smuzhiyun void
DeactivatePointerGrab(DeviceIntPtr mouse)1560*4882a593Smuzhiyun DeactivatePointerGrab(DeviceIntPtr mouse)
1561*4882a593Smuzhiyun {
1562*4882a593Smuzhiyun     GrabPtr grab = mouse->deviceGrab.grab;
1563*4882a593Smuzhiyun     DeviceIntPtr dev;
1564*4882a593Smuzhiyun     Bool wasPassive = mouse->deviceGrab.fromPassiveGrab;
1565*4882a593Smuzhiyun     Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
1566*4882a593Smuzhiyun                         mouse->deviceGrab.implicitGrab);
1567*4882a593Smuzhiyun     XID grab_resource = grab->resource;
1568*4882a593Smuzhiyun     int i;
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun     /* If an explicit grab was deactivated, we must remove it from the head of
1571*4882a593Smuzhiyun      * all the touches' listener lists. */
1572*4882a593Smuzhiyun     for (i = 0; !wasPassive && mouse->touch && i < mouse->touch->num_touches; i++) {
1573*4882a593Smuzhiyun         TouchPointInfoPtr ti = mouse->touch->touches + i;
1574*4882a593Smuzhiyun         if (ti->active && TouchResourceIsOwner(ti, grab_resource)) {
1575*4882a593Smuzhiyun             int mode = XIRejectTouch;
1576*4882a593Smuzhiyun             /* Rejecting will generate a TouchEnd, but we must not
1577*4882a593Smuzhiyun                emulate a ButtonRelease here. So pretend the listener
1578*4882a593Smuzhiyun                already has the end event */
1579*4882a593Smuzhiyun             if (grab->grabtype == CORE || grab->grabtype == XI ||
1580*4882a593Smuzhiyun                     !xi2mask_isset(mouse->deviceGrab.grab->xi2mask, mouse, XI_TouchBegin)) {
1581*4882a593Smuzhiyun                 mode = XIAcceptTouch;
1582*4882a593Smuzhiyun                 /* NOTE: we set the state here, but
1583*4882a593Smuzhiyun                  * ProcessTouchOwnershipEvent() will still call
1584*4882a593Smuzhiyun                  * TouchEmitTouchEnd for this listener. The other half of
1585*4882a593Smuzhiyun                  * this hack is in DeliverTouchEndEvent */
1586*4882a593Smuzhiyun                 ti->listeners[0].state = LISTENER_HAS_END;
1587*4882a593Smuzhiyun             }
1588*4882a593Smuzhiyun             TouchListenerAcceptReject(mouse, ti, 0, mode);
1589*4882a593Smuzhiyun         }
1590*4882a593Smuzhiyun     }
1591*4882a593Smuzhiyun 
1592*4882a593Smuzhiyun     TouchRemovePointerGrab(mouse);
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun     mouse->valuator->motionHintWindow = NullWindow;
1595*4882a593Smuzhiyun     mouse->deviceGrab.grab = NullGrab;
1596*4882a593Smuzhiyun     mouse->deviceGrab.sync.state = NOT_GRABBED;
1597*4882a593Smuzhiyun     mouse->deviceGrab.fromPassiveGrab = FALSE;
1598*4882a593Smuzhiyun 
1599*4882a593Smuzhiyun     for (dev = inputInfo.devices; dev; dev = dev->next) {
1600*4882a593Smuzhiyun         if (dev->deviceGrab.sync.other == grab)
1601*4882a593Smuzhiyun             dev->deviceGrab.sync.other = NullGrab;
1602*4882a593Smuzhiyun     }
1603*4882a593Smuzhiyun     DoEnterLeaveEvents(mouse, mouse->id, grab->window,
1604*4882a593Smuzhiyun                        mouse->spriteInfo->sprite->win, NotifyUngrab);
1605*4882a593Smuzhiyun     if (grab->confineTo)
1606*4882a593Smuzhiyun         ConfineCursorToWindow(mouse, GetCurrentRootWindow(mouse), FALSE, FALSE);
1607*4882a593Smuzhiyun     PostNewCursor(mouse);
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun     if (!wasImplicit && grab->grabtype == XI2)
1610*4882a593Smuzhiyun         ReattachToOldMaster(mouse);
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun     ComputeFreezes();
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun     FreeGrab(grab);
1615*4882a593Smuzhiyun }
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun /**
1618*4882a593Smuzhiyun  * Activate a keyboard grab on the given device.
1619*4882a593Smuzhiyun  *
1620*4882a593Smuzhiyun  * Extension devices have ActivateKeyboardGrab() set as their grabbing proc.
1621*4882a593Smuzhiyun  */
1622*4882a593Smuzhiyun void
ActivateKeyboardGrab(DeviceIntPtr keybd,GrabPtr grab,TimeStamp time,Bool passive)1623*4882a593Smuzhiyun ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time,
1624*4882a593Smuzhiyun                      Bool passive)
1625*4882a593Smuzhiyun {
1626*4882a593Smuzhiyun     GrabInfoPtr grabinfo = &keybd->deviceGrab;
1627*4882a593Smuzhiyun     GrabPtr oldgrab = grabinfo->grab;
1628*4882a593Smuzhiyun     WindowPtr oldWin;
1629*4882a593Smuzhiyun 
1630*4882a593Smuzhiyun     /* slave devices need to float for the duration of the grab. */
1631*4882a593Smuzhiyun     if (grab->grabtype == XI2 && keybd->enabled &&
1632*4882a593Smuzhiyun         !(passive & ImplicitGrabMask) && !IsMaster(keybd))
1633*4882a593Smuzhiyun         DetachFromMaster(keybd);
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun     if (!keybd->enabled)
1636*4882a593Smuzhiyun         oldWin = NULL;
1637*4882a593Smuzhiyun     else if (grabinfo->grab)
1638*4882a593Smuzhiyun         oldWin = grabinfo->grab->window;
1639*4882a593Smuzhiyun     else if (keybd->focus)
1640*4882a593Smuzhiyun         oldWin = keybd->focus->win;
1641*4882a593Smuzhiyun     else
1642*4882a593Smuzhiyun         oldWin = keybd->spriteInfo->sprite->win;
1643*4882a593Smuzhiyun     if (oldWin == FollowKeyboardWin)
1644*4882a593Smuzhiyun         oldWin = keybd->focus->win;
1645*4882a593Smuzhiyun     if (keybd->valuator)
1646*4882a593Smuzhiyun         keybd->valuator->motionHintWindow = NullWindow;
1647*4882a593Smuzhiyun     if (oldWin &&
1648*4882a593Smuzhiyun 	! (grabinfo->grab && oldWin == grabinfo->grab->window
1649*4882a593Smuzhiyun 			  && oldWin == grab->window))
1650*4882a593Smuzhiyun         DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab);
1651*4882a593Smuzhiyun     if (syncEvents.playingEvents)
1652*4882a593Smuzhiyun         grabinfo->grabTime = syncEvents.time;
1653*4882a593Smuzhiyun     else
1654*4882a593Smuzhiyun         grabinfo->grabTime = time;
1655*4882a593Smuzhiyun     grabinfo->grab = AllocGrab(grab);
1656*4882a593Smuzhiyun     grabinfo->fromPassiveGrab = passive;
1657*4882a593Smuzhiyun     grabinfo->implicitGrab = passive & ImplicitGrabMask;
1658*4882a593Smuzhiyun     CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode,
1659*4882a593Smuzhiyun                       (Bool) grab->pointerMode);
1660*4882a593Smuzhiyun     if (oldgrab)
1661*4882a593Smuzhiyun         FreeGrab(oldgrab);
1662*4882a593Smuzhiyun }
1663*4882a593Smuzhiyun 
1664*4882a593Smuzhiyun /**
1665*4882a593Smuzhiyun  * Delete keyboard grab for the given device.
1666*4882a593Smuzhiyun  */
1667*4882a593Smuzhiyun void
DeactivateKeyboardGrab(DeviceIntPtr keybd)1668*4882a593Smuzhiyun DeactivateKeyboardGrab(DeviceIntPtr keybd)
1669*4882a593Smuzhiyun {
1670*4882a593Smuzhiyun     GrabPtr grab = keybd->deviceGrab.grab;
1671*4882a593Smuzhiyun     DeviceIntPtr dev;
1672*4882a593Smuzhiyun     WindowPtr focusWin;
1673*4882a593Smuzhiyun     Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab &&
1674*4882a593Smuzhiyun                         keybd->deviceGrab.implicitGrab);
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun     if (keybd->valuator)
1677*4882a593Smuzhiyun         keybd->valuator->motionHintWindow = NullWindow;
1678*4882a593Smuzhiyun     keybd->deviceGrab.grab = NullGrab;
1679*4882a593Smuzhiyun     keybd->deviceGrab.sync.state = NOT_GRABBED;
1680*4882a593Smuzhiyun     keybd->deviceGrab.fromPassiveGrab = FALSE;
1681*4882a593Smuzhiyun 
1682*4882a593Smuzhiyun     for (dev = inputInfo.devices; dev; dev = dev->next) {
1683*4882a593Smuzhiyun         if (dev->deviceGrab.sync.other == grab)
1684*4882a593Smuzhiyun             dev->deviceGrab.sync.other = NullGrab;
1685*4882a593Smuzhiyun     }
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun     if (keybd->focus)
1688*4882a593Smuzhiyun         focusWin = keybd->focus->win;
1689*4882a593Smuzhiyun     else if (keybd->spriteInfo->sprite)
1690*4882a593Smuzhiyun         focusWin = keybd->spriteInfo->sprite->win;
1691*4882a593Smuzhiyun     else
1692*4882a593Smuzhiyun         focusWin = NullWindow;
1693*4882a593Smuzhiyun 
1694*4882a593Smuzhiyun     if (focusWin == FollowKeyboardWin)
1695*4882a593Smuzhiyun         focusWin = inputInfo.keyboard->focus->win;
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun     DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab);
1698*4882a593Smuzhiyun 
1699*4882a593Smuzhiyun     if (!wasImplicit && grab->grabtype == XI2)
1700*4882a593Smuzhiyun         ReattachToOldMaster(keybd);
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun     ComputeFreezes();
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun     FreeGrab(grab);
1705*4882a593Smuzhiyun }
1706*4882a593Smuzhiyun 
1707*4882a593Smuzhiyun void
AllowSome(ClientPtr client,TimeStamp time,DeviceIntPtr thisDev,int newState)1708*4882a593Smuzhiyun AllowSome(ClientPtr client, TimeStamp time, DeviceIntPtr thisDev, int newState)
1709*4882a593Smuzhiyun {
1710*4882a593Smuzhiyun     Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced;
1711*4882a593Smuzhiyun     TimeStamp grabTime;
1712*4882a593Smuzhiyun     DeviceIntPtr dev;
1713*4882a593Smuzhiyun     GrabInfoPtr devgrabinfo, grabinfo = &thisDev->deviceGrab;
1714*4882a593Smuzhiyun 
1715*4882a593Smuzhiyun     thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client);
1716*4882a593Smuzhiyun     thisSynced = FALSE;
1717*4882a593Smuzhiyun     otherGrabbed = FALSE;
1718*4882a593Smuzhiyun     othersFrozen = FALSE;
1719*4882a593Smuzhiyun     grabTime = grabinfo->grabTime;
1720*4882a593Smuzhiyun     for (dev = inputInfo.devices; dev; dev = dev->next) {
1721*4882a593Smuzhiyun         devgrabinfo = &dev->deviceGrab;
1722*4882a593Smuzhiyun 
1723*4882a593Smuzhiyun         if (dev == thisDev)
1724*4882a593Smuzhiyun             continue;
1725*4882a593Smuzhiyun         if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client)) {
1726*4882a593Smuzhiyun             if (!(thisGrabbed || otherGrabbed) ||
1727*4882a593Smuzhiyun                 (CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER))
1728*4882a593Smuzhiyun                 grabTime = devgrabinfo->grabTime;
1729*4882a593Smuzhiyun             otherGrabbed = TRUE;
1730*4882a593Smuzhiyun             if (grabinfo->sync.other == devgrabinfo->grab)
1731*4882a593Smuzhiyun                 thisSynced = TRUE;
1732*4882a593Smuzhiyun             if (devgrabinfo->sync.state >= FROZEN)
1733*4882a593Smuzhiyun                 othersFrozen = TRUE;
1734*4882a593Smuzhiyun         }
1735*4882a593Smuzhiyun     }
1736*4882a593Smuzhiyun     if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced))
1737*4882a593Smuzhiyun         return;
1738*4882a593Smuzhiyun     if ((CompareTimeStamps(time, currentTime) == LATER) ||
1739*4882a593Smuzhiyun         (CompareTimeStamps(time, grabTime) == EARLIER))
1740*4882a593Smuzhiyun         return;
1741*4882a593Smuzhiyun     switch (newState) {
1742*4882a593Smuzhiyun     case THAWED:               /* Async */
1743*4882a593Smuzhiyun         if (thisGrabbed)
1744*4882a593Smuzhiyun             grabinfo->sync.state = THAWED;
1745*4882a593Smuzhiyun         if (thisSynced)
1746*4882a593Smuzhiyun             grabinfo->sync.other = NullGrab;
1747*4882a593Smuzhiyun         ComputeFreezes();
1748*4882a593Smuzhiyun         break;
1749*4882a593Smuzhiyun     case FREEZE_NEXT_EVENT:    /* Sync */
1750*4882a593Smuzhiyun         if (thisGrabbed) {
1751*4882a593Smuzhiyun             grabinfo->sync.state = FREEZE_NEXT_EVENT;
1752*4882a593Smuzhiyun             if (thisSynced)
1753*4882a593Smuzhiyun                 grabinfo->sync.other = NullGrab;
1754*4882a593Smuzhiyun             ComputeFreezes();
1755*4882a593Smuzhiyun         }
1756*4882a593Smuzhiyun         break;
1757*4882a593Smuzhiyun     case THAWED_BOTH:          /* AsyncBoth */
1758*4882a593Smuzhiyun         if (othersFrozen) {
1759*4882a593Smuzhiyun             for (dev = inputInfo.devices; dev; dev = dev->next) {
1760*4882a593Smuzhiyun                 devgrabinfo = &dev->deviceGrab;
1761*4882a593Smuzhiyun                 if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client))
1762*4882a593Smuzhiyun                     devgrabinfo->sync.state = THAWED;
1763*4882a593Smuzhiyun                 if (devgrabinfo->sync.other &&
1764*4882a593Smuzhiyun                     SameClient(devgrabinfo->sync.other, client))
1765*4882a593Smuzhiyun                     devgrabinfo->sync.other = NullGrab;
1766*4882a593Smuzhiyun             }
1767*4882a593Smuzhiyun             ComputeFreezes();
1768*4882a593Smuzhiyun         }
1769*4882a593Smuzhiyun         break;
1770*4882a593Smuzhiyun     case FREEZE_BOTH_NEXT_EVENT:       /* SyncBoth */
1771*4882a593Smuzhiyun         if (othersFrozen) {
1772*4882a593Smuzhiyun             for (dev = inputInfo.devices; dev; dev = dev->next) {
1773*4882a593Smuzhiyun                 devgrabinfo = &dev->deviceGrab;
1774*4882a593Smuzhiyun                 if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client))
1775*4882a593Smuzhiyun                     devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT;
1776*4882a593Smuzhiyun                 if (devgrabinfo->sync.other
1777*4882a593Smuzhiyun                     && SameClient(devgrabinfo->sync.other, client))
1778*4882a593Smuzhiyun                     devgrabinfo->sync.other = NullGrab;
1779*4882a593Smuzhiyun             }
1780*4882a593Smuzhiyun             ComputeFreezes();
1781*4882a593Smuzhiyun         }
1782*4882a593Smuzhiyun         break;
1783*4882a593Smuzhiyun     case NOT_GRABBED:          /* Replay */
1784*4882a593Smuzhiyun         if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT) {
1785*4882a593Smuzhiyun             if (thisSynced)
1786*4882a593Smuzhiyun                 grabinfo->sync.other = NullGrab;
1787*4882a593Smuzhiyun             syncEvents.replayDev = thisDev;
1788*4882a593Smuzhiyun             syncEvents.replayWin = grabinfo->grab->window;
1789*4882a593Smuzhiyun             (*grabinfo->DeactivateGrab) (thisDev);
1790*4882a593Smuzhiyun             syncEvents.replayDev = (DeviceIntPtr) NULL;
1791*4882a593Smuzhiyun         }
1792*4882a593Smuzhiyun         break;
1793*4882a593Smuzhiyun     case THAW_OTHERS:          /* AsyncOthers */
1794*4882a593Smuzhiyun         if (othersFrozen) {
1795*4882a593Smuzhiyun             for (dev = inputInfo.devices; dev; dev = dev->next) {
1796*4882a593Smuzhiyun                 if (dev == thisDev)
1797*4882a593Smuzhiyun                     continue;
1798*4882a593Smuzhiyun                 devgrabinfo = &dev->deviceGrab;
1799*4882a593Smuzhiyun                 if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client))
1800*4882a593Smuzhiyun                     devgrabinfo->sync.state = THAWED;
1801*4882a593Smuzhiyun                 if (devgrabinfo->sync.other
1802*4882a593Smuzhiyun                     && SameClient(devgrabinfo->sync.other, client))
1803*4882a593Smuzhiyun                     devgrabinfo->sync.other = NullGrab;
1804*4882a593Smuzhiyun             }
1805*4882a593Smuzhiyun             ComputeFreezes();
1806*4882a593Smuzhiyun         }
1807*4882a593Smuzhiyun         break;
1808*4882a593Smuzhiyun     }
1809*4882a593Smuzhiyun 
1810*4882a593Smuzhiyun     /* We've unfrozen the grab. If the grab was a touch grab, we're now the
1811*4882a593Smuzhiyun      * owner and expected to accept/reject it. Reject == ReplayPointer which
1812*4882a593Smuzhiyun      * we've handled in ComputeFreezes() (during DeactivateGrab) above,
1813*4882a593Smuzhiyun      * anything else is accept.
1814*4882a593Smuzhiyun      */
1815*4882a593Smuzhiyun     if (newState != NOT_GRABBED /* Replay */ &&
1816*4882a593Smuzhiyun         IsTouchEvent((InternalEvent*)grabinfo->sync.event)) {
1817*4882a593Smuzhiyun         TouchAcceptAndEnd(thisDev, grabinfo->sync.event->touchid);
1818*4882a593Smuzhiyun     }
1819*4882a593Smuzhiyun }
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun /**
1822*4882a593Smuzhiyun  * Server-side protocol handling for AllowEvents request.
1823*4882a593Smuzhiyun  *
1824*4882a593Smuzhiyun  * Release some events from a frozen device.
1825*4882a593Smuzhiyun  */
1826*4882a593Smuzhiyun int
ProcAllowEvents(ClientPtr client)1827*4882a593Smuzhiyun ProcAllowEvents(ClientPtr client)
1828*4882a593Smuzhiyun {
1829*4882a593Smuzhiyun     TimeStamp time;
1830*4882a593Smuzhiyun     DeviceIntPtr mouse = NULL;
1831*4882a593Smuzhiyun     DeviceIntPtr keybd = NULL;
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun     REQUEST(xAllowEventsReq);
1834*4882a593Smuzhiyun 
1835*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xAllowEventsReq);
1836*4882a593Smuzhiyun     UpdateCurrentTime();
1837*4882a593Smuzhiyun     time = ClientTimeToServerTime(stuff->time);
1838*4882a593Smuzhiyun 
1839*4882a593Smuzhiyun     mouse = PickPointer(client);
1840*4882a593Smuzhiyun     keybd = PickKeyboard(client);
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun     switch (stuff->mode) {
1843*4882a593Smuzhiyun     case ReplayPointer:
1844*4882a593Smuzhiyun         AllowSome(client, time, mouse, NOT_GRABBED);
1845*4882a593Smuzhiyun         break;
1846*4882a593Smuzhiyun     case SyncPointer:
1847*4882a593Smuzhiyun         AllowSome(client, time, mouse, FREEZE_NEXT_EVENT);
1848*4882a593Smuzhiyun         break;
1849*4882a593Smuzhiyun     case AsyncPointer:
1850*4882a593Smuzhiyun         AllowSome(client, time, mouse, THAWED);
1851*4882a593Smuzhiyun         break;
1852*4882a593Smuzhiyun     case ReplayKeyboard:
1853*4882a593Smuzhiyun         AllowSome(client, time, keybd, NOT_GRABBED);
1854*4882a593Smuzhiyun         break;
1855*4882a593Smuzhiyun     case SyncKeyboard:
1856*4882a593Smuzhiyun         AllowSome(client, time, keybd, FREEZE_NEXT_EVENT);
1857*4882a593Smuzhiyun         break;
1858*4882a593Smuzhiyun     case AsyncKeyboard:
1859*4882a593Smuzhiyun         AllowSome(client, time, keybd, THAWED);
1860*4882a593Smuzhiyun         break;
1861*4882a593Smuzhiyun     case SyncBoth:
1862*4882a593Smuzhiyun         AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT);
1863*4882a593Smuzhiyun         break;
1864*4882a593Smuzhiyun     case AsyncBoth:
1865*4882a593Smuzhiyun         AllowSome(client, time, keybd, THAWED_BOTH);
1866*4882a593Smuzhiyun         break;
1867*4882a593Smuzhiyun     default:
1868*4882a593Smuzhiyun         client->errorValue = stuff->mode;
1869*4882a593Smuzhiyun         return BadValue;
1870*4882a593Smuzhiyun     }
1871*4882a593Smuzhiyun     return Success;
1872*4882a593Smuzhiyun }
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun /**
1875*4882a593Smuzhiyun  * Deactivate grabs from any device that has been grabbed by the client.
1876*4882a593Smuzhiyun  */
1877*4882a593Smuzhiyun void
ReleaseActiveGrabs(ClientPtr client)1878*4882a593Smuzhiyun ReleaseActiveGrabs(ClientPtr client)
1879*4882a593Smuzhiyun {
1880*4882a593Smuzhiyun     DeviceIntPtr dev;
1881*4882a593Smuzhiyun     Bool done;
1882*4882a593Smuzhiyun 
1883*4882a593Smuzhiyun     /* XXX CloseDownClient should remove passive grabs before
1884*4882a593Smuzhiyun      * releasing active grabs.
1885*4882a593Smuzhiyun      */
1886*4882a593Smuzhiyun     do {
1887*4882a593Smuzhiyun         done = TRUE;
1888*4882a593Smuzhiyun         for (dev = inputInfo.devices; dev; dev = dev->next) {
1889*4882a593Smuzhiyun             if (dev->deviceGrab.grab &&
1890*4882a593Smuzhiyun                 SameClient(dev->deviceGrab.grab, client)) {
1891*4882a593Smuzhiyun                 (*dev->deviceGrab.DeactivateGrab) (dev);
1892*4882a593Smuzhiyun                 done = FALSE;
1893*4882a593Smuzhiyun             }
1894*4882a593Smuzhiyun         }
1895*4882a593Smuzhiyun     } while (!done);
1896*4882a593Smuzhiyun }
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun /**************************************************************************
1899*4882a593Smuzhiyun  *            The following procedures deal with delivering events        *
1900*4882a593Smuzhiyun  **************************************************************************/
1901*4882a593Smuzhiyun 
1902*4882a593Smuzhiyun /**
1903*4882a593Smuzhiyun  * Deliver the given events to the given client.
1904*4882a593Smuzhiyun  *
1905*4882a593Smuzhiyun  * More than one event may be delivered at a time. This is the case with
1906*4882a593Smuzhiyun  * DeviceMotionNotifies which may be followed by DeviceValuator events.
1907*4882a593Smuzhiyun  *
1908*4882a593Smuzhiyun  * TryClientEvents() is the last station before actually writing the events to
1909*4882a593Smuzhiyun  * the socket. Anything that is not filtered here, will get delivered to the
1910*4882a593Smuzhiyun  * client.
1911*4882a593Smuzhiyun  * An event is only delivered if
1912*4882a593Smuzhiyun  *   - mask and filter match up.
1913*4882a593Smuzhiyun  *   - no other client has a grab on the device that caused the event.
1914*4882a593Smuzhiyun  *
1915*4882a593Smuzhiyun  *
1916*4882a593Smuzhiyun  * @param client The target client to deliver to.
1917*4882a593Smuzhiyun  * @param dev The device the event came from. May be NULL.
1918*4882a593Smuzhiyun  * @param pEvents The events to be delivered.
1919*4882a593Smuzhiyun  * @param count Number of elements in pEvents.
1920*4882a593Smuzhiyun  * @param mask Event mask as set by the window.
1921*4882a593Smuzhiyun  * @param filter Mask based on event type.
1922*4882a593Smuzhiyun  * @param grab Possible grab on the device that caused the event.
1923*4882a593Smuzhiyun  *
1924*4882a593Smuzhiyun  * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the
1925*4882a593Smuzhiyun  * client.
1926*4882a593Smuzhiyun  */
1927*4882a593Smuzhiyun int
TryClientEvents(ClientPtr client,DeviceIntPtr dev,xEvent * pEvents,int count,Mask mask,Mask filter,GrabPtr grab)1928*4882a593Smuzhiyun TryClientEvents(ClientPtr client, DeviceIntPtr dev, xEvent *pEvents,
1929*4882a593Smuzhiyun                 int count, Mask mask, Mask filter, GrabPtr grab)
1930*4882a593Smuzhiyun {
1931*4882a593Smuzhiyun     int type;
1932*4882a593Smuzhiyun 
1933*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
1934*4882a593Smuzhiyun     ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s",
1935*4882a593Smuzhiyun            pEvents->u.u.type, pEvents->u.u.detail, mask,
1936*4882a593Smuzhiyun            client ? client->index : -1,
1937*4882a593Smuzhiyun            (client && client->clientGone) ? " (gone)" : "");
1938*4882a593Smuzhiyun #endif
1939*4882a593Smuzhiyun 
1940*4882a593Smuzhiyun     if (!client || client == serverClient || client->clientGone) {
1941*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
1942*4882a593Smuzhiyun         ErrorF(" not delivered to fake/dead client\n");
1943*4882a593Smuzhiyun #endif
1944*4882a593Smuzhiyun         return 0;
1945*4882a593Smuzhiyun     }
1946*4882a593Smuzhiyun 
1947*4882a593Smuzhiyun     if (filter != CantBeFiltered && !(mask & filter)) {
1948*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
1949*4882a593Smuzhiyun         ErrorF(" filtered\n");
1950*4882a593Smuzhiyun #endif
1951*4882a593Smuzhiyun         return 0;
1952*4882a593Smuzhiyun     }
1953*4882a593Smuzhiyun 
1954*4882a593Smuzhiyun     if (grab && !SameClient(grab, client)) {
1955*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
1956*4882a593Smuzhiyun         ErrorF(" not delivered due to grab\n");
1957*4882a593Smuzhiyun #endif
1958*4882a593Smuzhiyun         return -1;              /* don't send, but notify caller */
1959*4882a593Smuzhiyun     }
1960*4882a593Smuzhiyun 
1961*4882a593Smuzhiyun     type = pEvents->u.u.type;
1962*4882a593Smuzhiyun     if (type == MotionNotify) {
1963*4882a593Smuzhiyun         if (mask & PointerMotionHintMask) {
1964*4882a593Smuzhiyun             if (WID(dev->valuator->motionHintWindow) ==
1965*4882a593Smuzhiyun                 pEvents->u.keyButtonPointer.event) {
1966*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
1967*4882a593Smuzhiyun                 ErrorF("[dix] \n");
1968*4882a593Smuzhiyun                 ErrorF("[dix] motionHintWindow == keyButtonPointer.event\n");
1969*4882a593Smuzhiyun #endif
1970*4882a593Smuzhiyun                 return 1;       /* don't send, but pretend we did */
1971*4882a593Smuzhiyun             }
1972*4882a593Smuzhiyun             pEvents->u.u.detail = NotifyHint;
1973*4882a593Smuzhiyun         }
1974*4882a593Smuzhiyun         else {
1975*4882a593Smuzhiyun             pEvents->u.u.detail = NotifyNormal;
1976*4882a593Smuzhiyun         }
1977*4882a593Smuzhiyun     }
1978*4882a593Smuzhiyun     else if (type == DeviceMotionNotify) {
1979*4882a593Smuzhiyun         if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer *) pEvents,
1980*4882a593Smuzhiyun                                             mask) != 0)
1981*4882a593Smuzhiyun             return 1;
1982*4882a593Smuzhiyun     }
1983*4882a593Smuzhiyun     else if (type == KeyPress) {
1984*4882a593Smuzhiyun         if (EventIsKeyRepeat(pEvents)) {
1985*4882a593Smuzhiyun             if (!_XkbWantsDetectableAutoRepeat(client)) {
1986*4882a593Smuzhiyun                 xEvent release = *pEvents;
1987*4882a593Smuzhiyun 
1988*4882a593Smuzhiyun                 release.u.u.type = KeyRelease;
1989*4882a593Smuzhiyun                 WriteEventsToClient(client, 1, &release);
1990*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
1991*4882a593Smuzhiyun                 ErrorF(" (plus fake core release for repeat)");
1992*4882a593Smuzhiyun #endif
1993*4882a593Smuzhiyun             }
1994*4882a593Smuzhiyun             else {
1995*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
1996*4882a593Smuzhiyun                 ErrorF(" (detectable autorepeat for core)");
1997*4882a593Smuzhiyun #endif
1998*4882a593Smuzhiyun             }
1999*4882a593Smuzhiyun         }
2000*4882a593Smuzhiyun 
2001*4882a593Smuzhiyun     }
2002*4882a593Smuzhiyun     else if (type == DeviceKeyPress) {
2003*4882a593Smuzhiyun         if (EventIsKeyRepeat(pEvents)) {
2004*4882a593Smuzhiyun             if (!_XkbWantsDetectableAutoRepeat(client)) {
2005*4882a593Smuzhiyun                 deviceKeyButtonPointer release =
2006*4882a593Smuzhiyun                     *(deviceKeyButtonPointer *) pEvents;
2007*4882a593Smuzhiyun                 release.type = DeviceKeyRelease;
2008*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
2009*4882a593Smuzhiyun                 ErrorF(" (plus fake xi1 release for repeat)");
2010*4882a593Smuzhiyun #endif
2011*4882a593Smuzhiyun                 WriteEventsToClient(client, 1, (xEvent *) &release);
2012*4882a593Smuzhiyun             }
2013*4882a593Smuzhiyun             else {
2014*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
2015*4882a593Smuzhiyun                 ErrorF(" (detectable autorepeat for core)");
2016*4882a593Smuzhiyun #endif
2017*4882a593Smuzhiyun             }
2018*4882a593Smuzhiyun         }
2019*4882a593Smuzhiyun     }
2020*4882a593Smuzhiyun 
2021*4882a593Smuzhiyun     if (BitIsOn(criticalEvents, type)) {
2022*4882a593Smuzhiyun         if (client->smart_priority < SMART_MAX_PRIORITY)
2023*4882a593Smuzhiyun             client->smart_priority++;
2024*4882a593Smuzhiyun         SetCriticalOutputPending();
2025*4882a593Smuzhiyun     }
2026*4882a593Smuzhiyun 
2027*4882a593Smuzhiyun     WriteEventsToClient(client, count, pEvents);
2028*4882a593Smuzhiyun #ifdef DEBUG_EVENTS
2029*4882a593Smuzhiyun     ErrorF("[dix]  delivered\n");
2030*4882a593Smuzhiyun #endif
2031*4882a593Smuzhiyun     return 1;
2032*4882a593Smuzhiyun }
2033*4882a593Smuzhiyun 
2034*4882a593Smuzhiyun static BOOL
ActivateImplicitGrab(DeviceIntPtr dev,ClientPtr client,WindowPtr win,xEvent * event,Mask deliveryMask)2035*4882a593Smuzhiyun ActivateImplicitGrab(DeviceIntPtr dev, ClientPtr client, WindowPtr win,
2036*4882a593Smuzhiyun                      xEvent *event, Mask deliveryMask)
2037*4882a593Smuzhiyun {
2038*4882a593Smuzhiyun     GrabPtr tempGrab;
2039*4882a593Smuzhiyun     OtherInputMasks *inputMasks;
2040*4882a593Smuzhiyun     CARD8 type = event->u.u.type;
2041*4882a593Smuzhiyun     enum InputLevel grabtype;
2042*4882a593Smuzhiyun 
2043*4882a593Smuzhiyun     if (type == ButtonPress)
2044*4882a593Smuzhiyun         grabtype = CORE;
2045*4882a593Smuzhiyun     else if (type == DeviceButtonPress)
2046*4882a593Smuzhiyun         grabtype = XI;
2047*4882a593Smuzhiyun     else if ((type = xi2_get_type(event)) == XI_ButtonPress)
2048*4882a593Smuzhiyun         grabtype = XI2;
2049*4882a593Smuzhiyun     else
2050*4882a593Smuzhiyun         return FALSE;
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun     tempGrab = AllocGrab(NULL);
2053*4882a593Smuzhiyun     if (!tempGrab)
2054*4882a593Smuzhiyun         return FALSE;
2055*4882a593Smuzhiyun     tempGrab->next = NULL;
2056*4882a593Smuzhiyun     tempGrab->device = dev;
2057*4882a593Smuzhiyun     tempGrab->resource = client->clientAsMask;
2058*4882a593Smuzhiyun     tempGrab->window = win;
2059*4882a593Smuzhiyun     tempGrab->ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE;
2060*4882a593Smuzhiyun     tempGrab->eventMask = deliveryMask;
2061*4882a593Smuzhiyun     tempGrab->keyboardMode = GrabModeAsync;
2062*4882a593Smuzhiyun     tempGrab->pointerMode = GrabModeAsync;
2063*4882a593Smuzhiyun     tempGrab->confineTo = NullWindow;
2064*4882a593Smuzhiyun     tempGrab->cursor = NullCursor;
2065*4882a593Smuzhiyun     tempGrab->type = type;
2066*4882a593Smuzhiyun     tempGrab->grabtype = grabtype;
2067*4882a593Smuzhiyun 
2068*4882a593Smuzhiyun     /* get the XI and XI2 device mask */
2069*4882a593Smuzhiyun     inputMasks = wOtherInputMasks(win);
2070*4882a593Smuzhiyun     tempGrab->deviceMask = (inputMasks) ? inputMasks->inputEvents[dev->id] : 0;
2071*4882a593Smuzhiyun 
2072*4882a593Smuzhiyun     if (inputMasks)
2073*4882a593Smuzhiyun         xi2mask_merge(tempGrab->xi2mask, inputMasks->xi2mask);
2074*4882a593Smuzhiyun 
2075*4882a593Smuzhiyun     (*dev->deviceGrab.ActivateGrab) (dev, tempGrab,
2076*4882a593Smuzhiyun                                      currentTime, TRUE | ImplicitGrabMask);
2077*4882a593Smuzhiyun     FreeGrab(tempGrab);
2078*4882a593Smuzhiyun     return TRUE;
2079*4882a593Smuzhiyun }
2080*4882a593Smuzhiyun 
2081*4882a593Smuzhiyun /**
2082*4882a593Smuzhiyun  * Attempt event delivery to the client owning the window.
2083*4882a593Smuzhiyun  */
2084*4882a593Smuzhiyun static enum EventDeliveryState
DeliverToWindowOwner(DeviceIntPtr dev,WindowPtr win,xEvent * events,int count,Mask filter,GrabPtr grab)2085*4882a593Smuzhiyun DeliverToWindowOwner(DeviceIntPtr dev, WindowPtr win,
2086*4882a593Smuzhiyun                      xEvent *events, int count, Mask filter, GrabPtr grab)
2087*4882a593Smuzhiyun {
2088*4882a593Smuzhiyun     /* if nobody ever wants to see this event, skip some work */
2089*4882a593Smuzhiyun     if (filter != CantBeFiltered &&
2090*4882a593Smuzhiyun         !((wOtherEventMasks(win) | win->eventMask) & filter))
2091*4882a593Smuzhiyun         return EVENT_SKIP;
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun     if (IsInterferingGrab(wClient(win), dev, events))
2094*4882a593Smuzhiyun         return EVENT_SKIP;
2095*4882a593Smuzhiyun 
2096*4882a593Smuzhiyun     if (!XaceHook(XACE_RECEIVE_ACCESS, wClient(win), win, events, count)) {
2097*4882a593Smuzhiyun         int attempt = TryClientEvents(wClient(win), dev, events,
2098*4882a593Smuzhiyun                                       count, win->eventMask,
2099*4882a593Smuzhiyun                                       filter, grab);
2100*4882a593Smuzhiyun 
2101*4882a593Smuzhiyun         if (attempt > 0)
2102*4882a593Smuzhiyun             return EVENT_DELIVERED;
2103*4882a593Smuzhiyun         if (attempt < 0)
2104*4882a593Smuzhiyun             return EVENT_REJECTED;
2105*4882a593Smuzhiyun     }
2106*4882a593Smuzhiyun 
2107*4882a593Smuzhiyun     return EVENT_NOT_DELIVERED;
2108*4882a593Smuzhiyun }
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun /**
2111*4882a593Smuzhiyun  * Get the list of clients that should be tried for event delivery on the
2112*4882a593Smuzhiyun  * given window.
2113*4882a593Smuzhiyun  *
2114*4882a593Smuzhiyun  * @return 1 if the client list should be traversed, zero if the event
2115*4882a593Smuzhiyun  * should be skipped.
2116*4882a593Smuzhiyun  */
2117*4882a593Smuzhiyun static Bool
GetClientsForDelivery(DeviceIntPtr dev,WindowPtr win,xEvent * events,Mask filter,InputClients ** iclients)2118*4882a593Smuzhiyun GetClientsForDelivery(DeviceIntPtr dev, WindowPtr win,
2119*4882a593Smuzhiyun                       xEvent *events, Mask filter, InputClients ** iclients)
2120*4882a593Smuzhiyun {
2121*4882a593Smuzhiyun     int rc = 0;
2122*4882a593Smuzhiyun 
2123*4882a593Smuzhiyun     if (core_get_type(events) != 0)
2124*4882a593Smuzhiyun         *iclients = (InputClients *) wOtherClients(win);
2125*4882a593Smuzhiyun     else if (xi2_get_type(events) != 0) {
2126*4882a593Smuzhiyun         OtherInputMasks *inputMasks = wOtherInputMasks(win);
2127*4882a593Smuzhiyun 
2128*4882a593Smuzhiyun         /* Has any client selected for the event? */
2129*4882a593Smuzhiyun         if (!WindowXI2MaskIsset(dev, win, events))
2130*4882a593Smuzhiyun             goto out;
2131*4882a593Smuzhiyun         *iclients = inputMasks->inputClients;
2132*4882a593Smuzhiyun     }
2133*4882a593Smuzhiyun     else {
2134*4882a593Smuzhiyun         OtherInputMasks *inputMasks = wOtherInputMasks(win);
2135*4882a593Smuzhiyun 
2136*4882a593Smuzhiyun         /* Has any client selected for the event? */
2137*4882a593Smuzhiyun         if (!inputMasks || !(inputMasks->inputEvents[dev->id] & filter))
2138*4882a593Smuzhiyun             goto out;
2139*4882a593Smuzhiyun 
2140*4882a593Smuzhiyun         *iclients = inputMasks->inputClients;
2141*4882a593Smuzhiyun     }
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun     rc = 1;
2144*4882a593Smuzhiyun  out:
2145*4882a593Smuzhiyun     return rc;
2146*4882a593Smuzhiyun }
2147*4882a593Smuzhiyun 
2148*4882a593Smuzhiyun /**
2149*4882a593Smuzhiyun  * Try delivery on each client in inputclients, provided the event mask
2150*4882a593Smuzhiyun  * accepts it and there is no interfering core grab..
2151*4882a593Smuzhiyun  */
2152*4882a593Smuzhiyun static enum EventDeliveryState
DeliverEventToInputClients(DeviceIntPtr dev,InputClients * inputclients,WindowPtr win,xEvent * events,int count,Mask filter,GrabPtr grab,ClientPtr * client_return,Mask * mask_return)2153*4882a593Smuzhiyun DeliverEventToInputClients(DeviceIntPtr dev, InputClients * inputclients,
2154*4882a593Smuzhiyun                            WindowPtr win, xEvent *events,
2155*4882a593Smuzhiyun                            int count, Mask filter, GrabPtr grab,
2156*4882a593Smuzhiyun                            ClientPtr *client_return, Mask *mask_return)
2157*4882a593Smuzhiyun {
2158*4882a593Smuzhiyun     int attempt;
2159*4882a593Smuzhiyun     enum EventDeliveryState rc = EVENT_NOT_DELIVERED;
2160*4882a593Smuzhiyun     Bool have_device_button_grab_class_client = FALSE;
2161*4882a593Smuzhiyun 
2162*4882a593Smuzhiyun     for (; inputclients; inputclients = inputclients->next) {
2163*4882a593Smuzhiyun         Mask mask;
2164*4882a593Smuzhiyun         ClientPtr client = rClient(inputclients);
2165*4882a593Smuzhiyun 
2166*4882a593Smuzhiyun         if (IsInterferingGrab(client, dev, events))
2167*4882a593Smuzhiyun             continue;
2168*4882a593Smuzhiyun 
2169*4882a593Smuzhiyun         if (IsWrongPointerBarrierClient(client, dev, events))
2170*4882a593Smuzhiyun             continue;
2171*4882a593Smuzhiyun 
2172*4882a593Smuzhiyun         mask = GetEventMask(dev, events, inputclients);
2173*4882a593Smuzhiyun 
2174*4882a593Smuzhiyun         if (XaceHook(XACE_RECEIVE_ACCESS, client, win, events, count))
2175*4882a593Smuzhiyun             /* do nothing */ ;
2176*4882a593Smuzhiyun         else if ((attempt = TryClientEvents(client, dev,
2177*4882a593Smuzhiyun                                             events, count,
2178*4882a593Smuzhiyun                                             mask, filter, grab))) {
2179*4882a593Smuzhiyun             if (attempt > 0) {
2180*4882a593Smuzhiyun                 /*
2181*4882a593Smuzhiyun                  * The order of clients is arbitrary therefore if one
2182*4882a593Smuzhiyun                  * client belongs to DeviceButtonGrabClass make sure to
2183*4882a593Smuzhiyun                  * catch it.
2184*4882a593Smuzhiyun                  */
2185*4882a593Smuzhiyun                 if (!have_device_button_grab_class_client) {
2186*4882a593Smuzhiyun                     rc = EVENT_DELIVERED;
2187*4882a593Smuzhiyun                     *client_return = client;
2188*4882a593Smuzhiyun                     *mask_return = mask;
2189*4882a593Smuzhiyun                     /* Success overrides non-success, so if we've been
2190*4882a593Smuzhiyun                      * successful on one client, return that */
2191*4882a593Smuzhiyun                     if (mask & DeviceButtonGrabMask)
2192*4882a593Smuzhiyun                         have_device_button_grab_class_client = TRUE;
2193*4882a593Smuzhiyun                 }
2194*4882a593Smuzhiyun             } else if (rc == EVENT_NOT_DELIVERED)
2195*4882a593Smuzhiyun                 rc = EVENT_REJECTED;
2196*4882a593Smuzhiyun         }
2197*4882a593Smuzhiyun     }
2198*4882a593Smuzhiyun 
2199*4882a593Smuzhiyun     return rc;
2200*4882a593Smuzhiyun }
2201*4882a593Smuzhiyun 
2202*4882a593Smuzhiyun /**
2203*4882a593Smuzhiyun  * Deliver events to clients registered on the window.
2204*4882a593Smuzhiyun  *
2205*4882a593Smuzhiyun  * @param client_return On successful delivery, set to the recipient.
2206*4882a593Smuzhiyun  * @param mask_return On successful delivery, set to the recipient's event
2207*4882a593Smuzhiyun  * mask for this event.
2208*4882a593Smuzhiyun  */
2209*4882a593Smuzhiyun static enum EventDeliveryState
DeliverEventToWindowMask(DeviceIntPtr dev,WindowPtr win,xEvent * events,int count,Mask filter,GrabPtr grab,ClientPtr * client_return,Mask * mask_return)2210*4882a593Smuzhiyun DeliverEventToWindowMask(DeviceIntPtr dev, WindowPtr win, xEvent *events,
2211*4882a593Smuzhiyun                          int count, Mask filter, GrabPtr grab,
2212*4882a593Smuzhiyun                          ClientPtr *client_return, Mask *mask_return)
2213*4882a593Smuzhiyun {
2214*4882a593Smuzhiyun     InputClients *iclients;
2215*4882a593Smuzhiyun 
2216*4882a593Smuzhiyun     if (!GetClientsForDelivery(dev, win, events, filter, &iclients))
2217*4882a593Smuzhiyun         return EVENT_SKIP;
2218*4882a593Smuzhiyun 
2219*4882a593Smuzhiyun     return DeliverEventToInputClients(dev, iclients, win, events, count, filter,
2220*4882a593Smuzhiyun                                       grab, client_return, mask_return);
2221*4882a593Smuzhiyun 
2222*4882a593Smuzhiyun }
2223*4882a593Smuzhiyun 
2224*4882a593Smuzhiyun /**
2225*4882a593Smuzhiyun  * Deliver events to a window. At this point, we do not yet know if the event
2226*4882a593Smuzhiyun  * actually needs to be delivered. May activate a grab if the event is a
2227*4882a593Smuzhiyun  * button press.
2228*4882a593Smuzhiyun  *
2229*4882a593Smuzhiyun  * Core events are always delivered to the window owner. If the filter is
2230*4882a593Smuzhiyun  * something other than CantBeFiltered, the event is also delivered to other
2231*4882a593Smuzhiyun  * clients with the matching mask on the window.
2232*4882a593Smuzhiyun  *
2233*4882a593Smuzhiyun  * More than one event may be delivered at a time. This is the case with
2234*4882a593Smuzhiyun  * DeviceMotionNotifies which may be followed by DeviceValuator events.
2235*4882a593Smuzhiyun  *
2236*4882a593Smuzhiyun  * @param pWin The window that would get the event.
2237*4882a593Smuzhiyun  * @param pEvents The events to be delivered.
2238*4882a593Smuzhiyun  * @param count Number of elements in pEvents.
2239*4882a593Smuzhiyun  * @param filter Mask based on event type.
2240*4882a593Smuzhiyun  * @param grab Possible grab on the device that caused the event.
2241*4882a593Smuzhiyun  *
2242*4882a593Smuzhiyun  * @return a positive number if at least one successful delivery has been
2243*4882a593Smuzhiyun  * made, 0 if no events were delivered, or a negative number if the event
2244*4882a593Smuzhiyun  * has not been delivered _and_ rejected by at least one client.
2245*4882a593Smuzhiyun  */
2246*4882a593Smuzhiyun int
DeliverEventsToWindow(DeviceIntPtr pDev,WindowPtr pWin,xEvent * pEvents,int count,Mask filter,GrabPtr grab)2247*4882a593Smuzhiyun DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
2248*4882a593Smuzhiyun                       *pEvents, int count, Mask filter, GrabPtr grab)
2249*4882a593Smuzhiyun {
2250*4882a593Smuzhiyun     int deliveries = 0, nondeliveries = 0;
2251*4882a593Smuzhiyun     ClientPtr client = NullClient;
2252*4882a593Smuzhiyun     Mask deliveryMask = 0;      /* If a grab occurs due to a button press, then
2253*4882a593Smuzhiyun                                    this mask is the mask of the grab. */
2254*4882a593Smuzhiyun     int type = pEvents->u.u.type;
2255*4882a593Smuzhiyun 
2256*4882a593Smuzhiyun     /* Deliver to window owner */
2257*4882a593Smuzhiyun     if ((filter == CantBeFiltered) || core_get_type(pEvents) != 0) {
2258*4882a593Smuzhiyun         enum EventDeliveryState rc;
2259*4882a593Smuzhiyun 
2260*4882a593Smuzhiyun         rc = DeliverToWindowOwner(pDev, pWin, pEvents, count, filter, grab);
2261*4882a593Smuzhiyun 
2262*4882a593Smuzhiyun         switch (rc) {
2263*4882a593Smuzhiyun         case EVENT_SKIP:
2264*4882a593Smuzhiyun             return 0;
2265*4882a593Smuzhiyun         case EVENT_REJECTED:
2266*4882a593Smuzhiyun             nondeliveries--;
2267*4882a593Smuzhiyun             break;
2268*4882a593Smuzhiyun         case EVENT_DELIVERED:
2269*4882a593Smuzhiyun             /* We delivered to the owner, with our event mask */
2270*4882a593Smuzhiyun             deliveries++;
2271*4882a593Smuzhiyun             client = wClient(pWin);
2272*4882a593Smuzhiyun             deliveryMask = pWin->eventMask;
2273*4882a593Smuzhiyun             break;
2274*4882a593Smuzhiyun         case EVENT_NOT_DELIVERED:
2275*4882a593Smuzhiyun             break;
2276*4882a593Smuzhiyun         }
2277*4882a593Smuzhiyun     }
2278*4882a593Smuzhiyun 
2279*4882a593Smuzhiyun     /* CantBeFiltered means only window owner gets the event */
2280*4882a593Smuzhiyun     if (filter != CantBeFiltered) {
2281*4882a593Smuzhiyun         enum EventDeliveryState rc;
2282*4882a593Smuzhiyun 
2283*4882a593Smuzhiyun         rc = DeliverEventToWindowMask(pDev, pWin, pEvents, count, filter,
2284*4882a593Smuzhiyun                                       grab, &client, &deliveryMask);
2285*4882a593Smuzhiyun 
2286*4882a593Smuzhiyun         switch (rc) {
2287*4882a593Smuzhiyun         case EVENT_SKIP:
2288*4882a593Smuzhiyun             return 0;
2289*4882a593Smuzhiyun         case EVENT_REJECTED:
2290*4882a593Smuzhiyun             nondeliveries--;
2291*4882a593Smuzhiyun             break;
2292*4882a593Smuzhiyun         case EVENT_DELIVERED:
2293*4882a593Smuzhiyun             deliveries++;
2294*4882a593Smuzhiyun             break;
2295*4882a593Smuzhiyun         case EVENT_NOT_DELIVERED:
2296*4882a593Smuzhiyun             break;
2297*4882a593Smuzhiyun         }
2298*4882a593Smuzhiyun     }
2299*4882a593Smuzhiyun 
2300*4882a593Smuzhiyun     if (deliveries) {
2301*4882a593Smuzhiyun         /*
2302*4882a593Smuzhiyun          * Note that since core events are delivered first, an implicit grab may
2303*4882a593Smuzhiyun          * be activated on a core grab, stopping the XI events.
2304*4882a593Smuzhiyun          */
2305*4882a593Smuzhiyun         if (!grab &&
2306*4882a593Smuzhiyun             ActivateImplicitGrab(pDev, client, pWin, pEvents, deliveryMask))
2307*4882a593Smuzhiyun             /* grab activated */ ;
2308*4882a593Smuzhiyun         else if (type == MotionNotify)
2309*4882a593Smuzhiyun             pDev->valuator->motionHintWindow = pWin;
2310*4882a593Smuzhiyun         else if (type == DeviceMotionNotify || type == DeviceButtonPress)
2311*4882a593Smuzhiyun             CheckDeviceGrabAndHintWindow(pWin, type,
2312*4882a593Smuzhiyun                                          (deviceKeyButtonPointer *) pEvents,
2313*4882a593Smuzhiyun                                          grab, client, deliveryMask);
2314*4882a593Smuzhiyun         return deliveries;
2315*4882a593Smuzhiyun     }
2316*4882a593Smuzhiyun     return nondeliveries;
2317*4882a593Smuzhiyun }
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun /**
2320*4882a593Smuzhiyun  * Filter out raw events for XI 2.0 and XI 2.1 clients.
2321*4882a593Smuzhiyun  *
2322*4882a593Smuzhiyun  * If there is a grab on the device, 2.0 clients only get raw events if they
2323*4882a593Smuzhiyun  * have the grab. 2.1+ clients get raw events in all cases.
2324*4882a593Smuzhiyun  *
2325*4882a593Smuzhiyun  * @return TRUE if the event should be discarded, FALSE otherwise.
2326*4882a593Smuzhiyun  */
2327*4882a593Smuzhiyun static BOOL
FilterRawEvents(const ClientPtr client,const GrabPtr grab,WindowPtr root)2328*4882a593Smuzhiyun FilterRawEvents(const ClientPtr client, const GrabPtr grab, WindowPtr root)
2329*4882a593Smuzhiyun {
2330*4882a593Smuzhiyun     XIClientPtr client_xi_version;
2331*4882a593Smuzhiyun     int cmp;
2332*4882a593Smuzhiyun 
2333*4882a593Smuzhiyun     /* device not grabbed -> don't filter */
2334*4882a593Smuzhiyun     if (!grab)
2335*4882a593Smuzhiyun         return FALSE;
2336*4882a593Smuzhiyun 
2337*4882a593Smuzhiyun     client_xi_version =
2338*4882a593Smuzhiyun         dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
2339*4882a593Smuzhiyun 
2340*4882a593Smuzhiyun     cmp = version_compare(client_xi_version->major_version,
2341*4882a593Smuzhiyun                           client_xi_version->minor_version, 2, 0);
2342*4882a593Smuzhiyun     /* XI 2.0: if device is grabbed, skip
2343*4882a593Smuzhiyun        XI 2.1: if device is grabbed by us, skip, we've already delivered */
2344*4882a593Smuzhiyun     if (cmp == 0)
2345*4882a593Smuzhiyun         return TRUE;
2346*4882a593Smuzhiyun 
2347*4882a593Smuzhiyun     return (grab->window != root) ? FALSE : SameClient(grab, client);
2348*4882a593Smuzhiyun }
2349*4882a593Smuzhiyun 
2350*4882a593Smuzhiyun /**
2351*4882a593Smuzhiyun  * Deliver a raw event to the grab owner (if any) and to all root windows.
2352*4882a593Smuzhiyun  *
2353*4882a593Smuzhiyun  * Raw event delivery differs between XI 2.0 and XI 2.1.
2354*4882a593Smuzhiyun  * XI 2.0: events delivered to the grabbing client (if any) OR to all root
2355*4882a593Smuzhiyun  * windows
2356*4882a593Smuzhiyun  * XI 2.1: events delivered to all root windows, regardless of grabbing
2357*4882a593Smuzhiyun  * state.
2358*4882a593Smuzhiyun  */
2359*4882a593Smuzhiyun void
DeliverRawEvent(RawDeviceEvent * ev,DeviceIntPtr device)2360*4882a593Smuzhiyun DeliverRawEvent(RawDeviceEvent *ev, DeviceIntPtr device)
2361*4882a593Smuzhiyun {
2362*4882a593Smuzhiyun     GrabPtr grab = device->deviceGrab.grab;
2363*4882a593Smuzhiyun     xEvent *xi;
2364*4882a593Smuzhiyun     int i, rc;
2365*4882a593Smuzhiyun     int filter;
2366*4882a593Smuzhiyun 
2367*4882a593Smuzhiyun     rc = EventToXI2((InternalEvent *) ev, (xEvent **) &xi);
2368*4882a593Smuzhiyun     if (rc != Success) {
2369*4882a593Smuzhiyun         ErrorF("[Xi] %s: XI2 conversion failed in %s (%d)\n",
2370*4882a593Smuzhiyun                __func__, device->name, rc);
2371*4882a593Smuzhiyun         return;
2372*4882a593Smuzhiyun     }
2373*4882a593Smuzhiyun 
2374*4882a593Smuzhiyun     if (grab)
2375*4882a593Smuzhiyun         DeliverGrabbedEvent((InternalEvent *) ev, device, FALSE);
2376*4882a593Smuzhiyun 
2377*4882a593Smuzhiyun     filter = GetEventFilter(device, xi);
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun     for (i = 0; i < screenInfo.numScreens; i++) {
2380*4882a593Smuzhiyun         WindowPtr root;
2381*4882a593Smuzhiyun         InputClients *inputclients;
2382*4882a593Smuzhiyun 
2383*4882a593Smuzhiyun         root = screenInfo.screens[i]->root;
2384*4882a593Smuzhiyun         if (!GetClientsForDelivery(device, root, xi, filter, &inputclients))
2385*4882a593Smuzhiyun             continue;
2386*4882a593Smuzhiyun 
2387*4882a593Smuzhiyun         for (; inputclients; inputclients = inputclients->next) {
2388*4882a593Smuzhiyun             ClientPtr c;        /* unused */
2389*4882a593Smuzhiyun             Mask m;             /* unused */
2390*4882a593Smuzhiyun             InputClients ic = *inputclients;
2391*4882a593Smuzhiyun 
2392*4882a593Smuzhiyun             /* Because we run through the list manually, copy the actual
2393*4882a593Smuzhiyun              * list, shorten the copy to only have one client and then pass
2394*4882a593Smuzhiyun              * that down to DeliverEventToInputClients. This way we avoid
2395*4882a593Smuzhiyun              * double events on XI 2.1 clients that have a grab on the
2396*4882a593Smuzhiyun              * device.
2397*4882a593Smuzhiyun              */
2398*4882a593Smuzhiyun             ic.next = NULL;
2399*4882a593Smuzhiyun 
2400*4882a593Smuzhiyun             if (!FilterRawEvents(rClient(&ic), grab, root))
2401*4882a593Smuzhiyun                 DeliverEventToInputClients(device, &ic, root, xi, 1,
2402*4882a593Smuzhiyun                                            filter, NULL, &c, &m);
2403*4882a593Smuzhiyun         }
2404*4882a593Smuzhiyun     }
2405*4882a593Smuzhiyun 
2406*4882a593Smuzhiyun     free(xi);
2407*4882a593Smuzhiyun }
2408*4882a593Smuzhiyun 
2409*4882a593Smuzhiyun /* If the event goes to dontClient, don't send it and return 0.  if
2410*4882a593Smuzhiyun    send works,  return 1 or if send didn't work, return 2.
2411*4882a593Smuzhiyun    Only works for core events.
2412*4882a593Smuzhiyun */
2413*4882a593Smuzhiyun 
2414*4882a593Smuzhiyun #ifdef PANORAMIX
2415*4882a593Smuzhiyun static int
XineramaTryClientEventsResult(ClientPtr client,GrabPtr grab,Mask mask,Mask filter)2416*4882a593Smuzhiyun XineramaTryClientEventsResult(ClientPtr client,
2417*4882a593Smuzhiyun                               GrabPtr grab, Mask mask, Mask filter)
2418*4882a593Smuzhiyun {
2419*4882a593Smuzhiyun     if ((client) && (client != serverClient) && (!client->clientGone) &&
2420*4882a593Smuzhiyun         ((filter == CantBeFiltered) || (mask & filter))) {
2421*4882a593Smuzhiyun         if (grab && !SameClient(grab, client))
2422*4882a593Smuzhiyun             return -1;
2423*4882a593Smuzhiyun         else
2424*4882a593Smuzhiyun             return 1;
2425*4882a593Smuzhiyun     }
2426*4882a593Smuzhiyun     return 0;
2427*4882a593Smuzhiyun }
2428*4882a593Smuzhiyun #endif
2429*4882a593Smuzhiyun 
2430*4882a593Smuzhiyun /**
2431*4882a593Smuzhiyun  * Try to deliver events to the interested parties.
2432*4882a593Smuzhiyun  *
2433*4882a593Smuzhiyun  * @param pWin The window that would get the event.
2434*4882a593Smuzhiyun  * @param pEvents The events to be delivered.
2435*4882a593Smuzhiyun  * @param count Number of elements in pEvents.
2436*4882a593Smuzhiyun  * @param filter Mask based on event type.
2437*4882a593Smuzhiyun  * @param dontClient Don't deliver to the dontClient.
2438*4882a593Smuzhiyun  */
2439*4882a593Smuzhiyun int
MaybeDeliverEventsToClient(WindowPtr pWin,xEvent * pEvents,int count,Mask filter,ClientPtr dontClient)2440*4882a593Smuzhiyun MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents,
2441*4882a593Smuzhiyun                            int count, Mask filter, ClientPtr dontClient)
2442*4882a593Smuzhiyun {
2443*4882a593Smuzhiyun     OtherClients *other;
2444*4882a593Smuzhiyun 
2445*4882a593Smuzhiyun     if (pWin->eventMask & filter) {
2446*4882a593Smuzhiyun         if (wClient(pWin) == dontClient)
2447*4882a593Smuzhiyun             return 0;
2448*4882a593Smuzhiyun #ifdef PANORAMIX
2449*4882a593Smuzhiyun         if (!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
2450*4882a593Smuzhiyun             return XineramaTryClientEventsResult(wClient(pWin), NullGrab,
2451*4882a593Smuzhiyun                                                  pWin->eventMask, filter);
2452*4882a593Smuzhiyun #endif
2453*4882a593Smuzhiyun         if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count))
2454*4882a593Smuzhiyun             return 1;           /* don't send, but pretend we did */
2455*4882a593Smuzhiyun         return TryClientEvents(wClient(pWin), NULL, pEvents, count,
2456*4882a593Smuzhiyun                                pWin->eventMask, filter, NullGrab);
2457*4882a593Smuzhiyun     }
2458*4882a593Smuzhiyun     for (other = wOtherClients(pWin); other; other = other->next) {
2459*4882a593Smuzhiyun         if (other->mask & filter) {
2460*4882a593Smuzhiyun             if (SameClient(other, dontClient))
2461*4882a593Smuzhiyun                 return 0;
2462*4882a593Smuzhiyun #ifdef PANORAMIX
2463*4882a593Smuzhiyun             if (!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
2464*4882a593Smuzhiyun                 return XineramaTryClientEventsResult(rClient(other), NullGrab,
2465*4882a593Smuzhiyun                                                      other->mask, filter);
2466*4882a593Smuzhiyun #endif
2467*4882a593Smuzhiyun             if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, pEvents,
2468*4882a593Smuzhiyun                          count))
2469*4882a593Smuzhiyun                 return 1;       /* don't send, but pretend we did */
2470*4882a593Smuzhiyun             return TryClientEvents(rClient(other), NULL, pEvents, count,
2471*4882a593Smuzhiyun                                    other->mask, filter, NullGrab);
2472*4882a593Smuzhiyun         }
2473*4882a593Smuzhiyun     }
2474*4882a593Smuzhiyun     return 2;
2475*4882a593Smuzhiyun }
2476*4882a593Smuzhiyun 
2477*4882a593Smuzhiyun static Window
FindChildForEvent(SpritePtr pSprite,WindowPtr event)2478*4882a593Smuzhiyun FindChildForEvent(SpritePtr pSprite, WindowPtr event)
2479*4882a593Smuzhiyun {
2480*4882a593Smuzhiyun     WindowPtr w = DeepestSpriteWin(pSprite);
2481*4882a593Smuzhiyun     Window child = None;
2482*4882a593Smuzhiyun 
2483*4882a593Smuzhiyun     /* If the search ends up past the root should the child field be
2484*4882a593Smuzhiyun        set to none or should the value in the argument be passed
2485*4882a593Smuzhiyun        through. It probably doesn't matter since everyone calls
2486*4882a593Smuzhiyun        this function with child == None anyway. */
2487*4882a593Smuzhiyun     while (w) {
2488*4882a593Smuzhiyun         /* If the source window is same as event window, child should be
2489*4882a593Smuzhiyun            none.  Don't bother going all all the way back to the root. */
2490*4882a593Smuzhiyun 
2491*4882a593Smuzhiyun         if (w == event) {
2492*4882a593Smuzhiyun             child = None;
2493*4882a593Smuzhiyun             break;
2494*4882a593Smuzhiyun         }
2495*4882a593Smuzhiyun 
2496*4882a593Smuzhiyun         if (w->parent == event) {
2497*4882a593Smuzhiyun             child = w->drawable.id;
2498*4882a593Smuzhiyun             break;
2499*4882a593Smuzhiyun         }
2500*4882a593Smuzhiyun         w = w->parent;
2501*4882a593Smuzhiyun     }
2502*4882a593Smuzhiyun     return child;
2503*4882a593Smuzhiyun }
2504*4882a593Smuzhiyun 
2505*4882a593Smuzhiyun /**
2506*4882a593Smuzhiyun  * Adjust event fields to comply with the window properties.
2507*4882a593Smuzhiyun  *
2508*4882a593Smuzhiyun  * @param xE Event to be modified in place
2509*4882a593Smuzhiyun  * @param pWin The window to get the information from.
2510*4882a593Smuzhiyun  * @param child Child window setting for event (if applicable)
2511*4882a593Smuzhiyun  * @param calcChild If True, calculate the child window.
2512*4882a593Smuzhiyun  */
2513*4882a593Smuzhiyun void
FixUpEventFromWindow(SpritePtr pSprite,xEvent * xE,WindowPtr pWin,Window child,Bool calcChild)2514*4882a593Smuzhiyun FixUpEventFromWindow(SpritePtr pSprite,
2515*4882a593Smuzhiyun                      xEvent *xE, WindowPtr pWin, Window child, Bool calcChild)
2516*4882a593Smuzhiyun {
2517*4882a593Smuzhiyun     int evtype;
2518*4882a593Smuzhiyun 
2519*4882a593Smuzhiyun     if (calcChild)
2520*4882a593Smuzhiyun         child = FindChildForEvent(pSprite, pWin);
2521*4882a593Smuzhiyun 
2522*4882a593Smuzhiyun     if ((evtype = xi2_get_type(xE))) {
2523*4882a593Smuzhiyun         xXIDeviceEvent *event = (xXIDeviceEvent *) xE;
2524*4882a593Smuzhiyun 
2525*4882a593Smuzhiyun         switch (evtype) {
2526*4882a593Smuzhiyun         case XI_RawKeyPress:
2527*4882a593Smuzhiyun         case XI_RawKeyRelease:
2528*4882a593Smuzhiyun         case XI_RawButtonPress:
2529*4882a593Smuzhiyun         case XI_RawButtonRelease:
2530*4882a593Smuzhiyun         case XI_RawMotion:
2531*4882a593Smuzhiyun         case XI_RawTouchBegin:
2532*4882a593Smuzhiyun         case XI_RawTouchUpdate:
2533*4882a593Smuzhiyun         case XI_RawTouchEnd:
2534*4882a593Smuzhiyun         case XI_DeviceChanged:
2535*4882a593Smuzhiyun         case XI_HierarchyChanged:
2536*4882a593Smuzhiyun         case XI_PropertyEvent:
2537*4882a593Smuzhiyun         case XI_BarrierHit:
2538*4882a593Smuzhiyun         case XI_BarrierLeave:
2539*4882a593Smuzhiyun             return;
2540*4882a593Smuzhiyun         default:
2541*4882a593Smuzhiyun             break;
2542*4882a593Smuzhiyun         }
2543*4882a593Smuzhiyun 
2544*4882a593Smuzhiyun         event->root = RootWindow(pSprite)->drawable.id;
2545*4882a593Smuzhiyun         event->event = pWin->drawable.id;
2546*4882a593Smuzhiyun 
2547*4882a593Smuzhiyun         if (evtype == XI_TouchOwnership) {
2548*4882a593Smuzhiyun             event->child = child;
2549*4882a593Smuzhiyun             return;
2550*4882a593Smuzhiyun         }
2551*4882a593Smuzhiyun 
2552*4882a593Smuzhiyun         if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
2553*4882a593Smuzhiyun             event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
2554*4882a593Smuzhiyun             event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
2555*4882a593Smuzhiyun             event->child = child;
2556*4882a593Smuzhiyun         }
2557*4882a593Smuzhiyun         else {
2558*4882a593Smuzhiyun             event->event_x = 0;
2559*4882a593Smuzhiyun             event->event_y = 0;
2560*4882a593Smuzhiyun             event->child = None;
2561*4882a593Smuzhiyun         }
2562*4882a593Smuzhiyun 
2563*4882a593Smuzhiyun         if (event->evtype == XI_Enter || event->evtype == XI_Leave ||
2564*4882a593Smuzhiyun             event->evtype == XI_FocusIn || event->evtype == XI_FocusOut)
2565*4882a593Smuzhiyun             ((xXIEnterEvent *) event)->same_screen =
2566*4882a593Smuzhiyun                 (pSprite->hot.pScreen == pWin->drawable.pScreen);
2567*4882a593Smuzhiyun 
2568*4882a593Smuzhiyun     }
2569*4882a593Smuzhiyun     else {
2570*4882a593Smuzhiyun         XE_KBPTR.root = RootWindow(pSprite)->drawable.id;
2571*4882a593Smuzhiyun         XE_KBPTR.event = pWin->drawable.id;
2572*4882a593Smuzhiyun         if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
2573*4882a593Smuzhiyun             XE_KBPTR.sameScreen = xTrue;
2574*4882a593Smuzhiyun             XE_KBPTR.child = child;
2575*4882a593Smuzhiyun             XE_KBPTR.eventX = XE_KBPTR.rootX - pWin->drawable.x;
2576*4882a593Smuzhiyun             XE_KBPTR.eventY = XE_KBPTR.rootY - pWin->drawable.y;
2577*4882a593Smuzhiyun         }
2578*4882a593Smuzhiyun         else {
2579*4882a593Smuzhiyun             XE_KBPTR.sameScreen = xFalse;
2580*4882a593Smuzhiyun             XE_KBPTR.child = None;
2581*4882a593Smuzhiyun             XE_KBPTR.eventX = 0;
2582*4882a593Smuzhiyun             XE_KBPTR.eventY = 0;
2583*4882a593Smuzhiyun         }
2584*4882a593Smuzhiyun     }
2585*4882a593Smuzhiyun }
2586*4882a593Smuzhiyun 
2587*4882a593Smuzhiyun /**
2588*4882a593Smuzhiyun  * Check if a given event is deliverable at all on a given window.
2589*4882a593Smuzhiyun  *
2590*4882a593Smuzhiyun  * This function only checks if any client wants it, not for a specific
2591*4882a593Smuzhiyun  * client.
2592*4882a593Smuzhiyun  *
2593*4882a593Smuzhiyun  * @param[in] dev The device this event is being sent for.
2594*4882a593Smuzhiyun  * @param[in] evtype The event type of the event that is to be sent.
2595*4882a593Smuzhiyun  * @param[in] win The current event window.
2596*4882a593Smuzhiyun  *
2597*4882a593Smuzhiyun  * @return Bitmask of ::EVENT_XI2_MASK, ::EVENT_XI1_MASK, ::EVENT_CORE_MASK, and
2598*4882a593Smuzhiyun  *         ::EVENT_DONT_PROPAGATE_MASK.
2599*4882a593Smuzhiyun  */
2600*4882a593Smuzhiyun int
EventIsDeliverable(DeviceIntPtr dev,int evtype,WindowPtr win)2601*4882a593Smuzhiyun EventIsDeliverable(DeviceIntPtr dev, int evtype, WindowPtr win)
2602*4882a593Smuzhiyun {
2603*4882a593Smuzhiyun     int rc = 0;
2604*4882a593Smuzhiyun     int filter = 0;
2605*4882a593Smuzhiyun     int type;
2606*4882a593Smuzhiyun     OtherInputMasks *inputMasks = wOtherInputMasks(win);
2607*4882a593Smuzhiyun 
2608*4882a593Smuzhiyun     if ((type = GetXI2Type(evtype)) != 0) {
2609*4882a593Smuzhiyun         if (inputMasks && xi2mask_isset(inputMasks->xi2mask, dev, type))
2610*4882a593Smuzhiyun             rc |= EVENT_XI2_MASK;
2611*4882a593Smuzhiyun     }
2612*4882a593Smuzhiyun 
2613*4882a593Smuzhiyun     if ((type = GetXIType(evtype)) != 0) {
2614*4882a593Smuzhiyun         filter = event_get_filter_from_type(dev, type);
2615*4882a593Smuzhiyun 
2616*4882a593Smuzhiyun         /* Check for XI mask */
2617*4882a593Smuzhiyun         if (inputMasks &&
2618*4882a593Smuzhiyun             (inputMasks->deliverableEvents[dev->id] & filter) &&
2619*4882a593Smuzhiyun             (inputMasks->inputEvents[dev->id] & filter))
2620*4882a593Smuzhiyun             rc |= EVENT_XI1_MASK;
2621*4882a593Smuzhiyun 
2622*4882a593Smuzhiyun         /* Check for XI DontPropagate mask */
2623*4882a593Smuzhiyun         if (inputMasks && (inputMasks->dontPropagateMask[dev->id] & filter))
2624*4882a593Smuzhiyun             rc |= EVENT_DONT_PROPAGATE_MASK;
2625*4882a593Smuzhiyun 
2626*4882a593Smuzhiyun     }
2627*4882a593Smuzhiyun 
2628*4882a593Smuzhiyun     if ((type = GetCoreType(evtype)) != 0) {
2629*4882a593Smuzhiyun         filter = event_get_filter_from_type(dev, type);
2630*4882a593Smuzhiyun 
2631*4882a593Smuzhiyun         /* Check for core mask */
2632*4882a593Smuzhiyun         if ((win->deliverableEvents & filter) &&
2633*4882a593Smuzhiyun             ((wOtherEventMasks(win) | win->eventMask) & filter))
2634*4882a593Smuzhiyun             rc |= EVENT_CORE_MASK;
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun         /* Check for core DontPropagate mask */
2637*4882a593Smuzhiyun         if (filter & wDontPropagateMask(win))
2638*4882a593Smuzhiyun             rc |= EVENT_DONT_PROPAGATE_MASK;
2639*4882a593Smuzhiyun     }
2640*4882a593Smuzhiyun 
2641*4882a593Smuzhiyun     return rc;
2642*4882a593Smuzhiyun }
2643*4882a593Smuzhiyun 
2644*4882a593Smuzhiyun static int
DeliverEvent(DeviceIntPtr dev,xEvent * xE,int count,WindowPtr win,Window child,GrabPtr grab)2645*4882a593Smuzhiyun DeliverEvent(DeviceIntPtr dev, xEvent *xE, int count,
2646*4882a593Smuzhiyun              WindowPtr win, Window child, GrabPtr grab)
2647*4882a593Smuzhiyun {
2648*4882a593Smuzhiyun     SpritePtr pSprite = dev->spriteInfo->sprite;
2649*4882a593Smuzhiyun     Mask filter;
2650*4882a593Smuzhiyun     int deliveries = 0;
2651*4882a593Smuzhiyun 
2652*4882a593Smuzhiyun     if (XaceHook(XACE_SEND_ACCESS, NULL, dev, win, xE, count) == Success) {
2653*4882a593Smuzhiyun         filter = GetEventFilter(dev, xE);
2654*4882a593Smuzhiyun         FixUpEventFromWindow(pSprite, xE, win, child, FALSE);
2655*4882a593Smuzhiyun         deliveries = DeliverEventsToWindow(dev, win, xE, count, filter, grab);
2656*4882a593Smuzhiyun     }
2657*4882a593Smuzhiyun 
2658*4882a593Smuzhiyun     return deliveries;
2659*4882a593Smuzhiyun }
2660*4882a593Smuzhiyun 
2661*4882a593Smuzhiyun static int
DeliverOneEvent(InternalEvent * event,DeviceIntPtr dev,enum InputLevel level,WindowPtr win,Window child,GrabPtr grab)2662*4882a593Smuzhiyun DeliverOneEvent(InternalEvent *event, DeviceIntPtr dev, enum InputLevel level,
2663*4882a593Smuzhiyun                 WindowPtr win, Window child, GrabPtr grab)
2664*4882a593Smuzhiyun {
2665*4882a593Smuzhiyun     xEvent *xE = NULL;
2666*4882a593Smuzhiyun     int count = 0;
2667*4882a593Smuzhiyun     int deliveries = 0;
2668*4882a593Smuzhiyun     int rc;
2669*4882a593Smuzhiyun 
2670*4882a593Smuzhiyun     switch (level) {
2671*4882a593Smuzhiyun     case XI2:
2672*4882a593Smuzhiyun         rc = EventToXI2(event, &xE);
2673*4882a593Smuzhiyun         count = 1;
2674*4882a593Smuzhiyun         break;
2675*4882a593Smuzhiyun     case XI:
2676*4882a593Smuzhiyun         rc = EventToXI(event, &xE, &count);
2677*4882a593Smuzhiyun         break;
2678*4882a593Smuzhiyun     case CORE:
2679*4882a593Smuzhiyun         rc = EventToCore(event, &xE, &count);
2680*4882a593Smuzhiyun         break;
2681*4882a593Smuzhiyun     default:
2682*4882a593Smuzhiyun         rc = BadImplementation;
2683*4882a593Smuzhiyun         break;
2684*4882a593Smuzhiyun     }
2685*4882a593Smuzhiyun 
2686*4882a593Smuzhiyun     if (rc == Success) {
2687*4882a593Smuzhiyun         deliveries = DeliverEvent(dev, xE, count, win, child, grab);
2688*4882a593Smuzhiyun         free(xE);
2689*4882a593Smuzhiyun     }
2690*4882a593Smuzhiyun     else
2691*4882a593Smuzhiyun         BUG_WARN_MSG(rc != BadMatch,
2692*4882a593Smuzhiyun                      "%s: conversion to level %d failed with rc %d\n",
2693*4882a593Smuzhiyun                      dev->name, level, rc);
2694*4882a593Smuzhiyun     return deliveries;
2695*4882a593Smuzhiyun }
2696*4882a593Smuzhiyun 
2697*4882a593Smuzhiyun /**
2698*4882a593Smuzhiyun  * Deliver events caused by input devices.
2699*4882a593Smuzhiyun  *
2700*4882a593Smuzhiyun  * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is
2701*4882a593Smuzhiyun  * called directly from the processInputProc.
2702*4882a593Smuzhiyun  * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call
2703*4882a593Smuzhiyun  * DeliverDeviceEvents.
2704*4882a593Smuzhiyun  * For focused events, DeliverFocusedEvent is called first, and _may_ call
2705*4882a593Smuzhiyun  * DeliverDeviceEvents.
2706*4882a593Smuzhiyun  *
2707*4882a593Smuzhiyun  * @param pWin Window to deliver event to.
2708*4882a593Smuzhiyun  * @param event The events to deliver, not yet in wire format.
2709*4882a593Smuzhiyun  * @param grab Possible grab on a device.
2710*4882a593Smuzhiyun  * @param stopAt Don't recurse up to the root window.
2711*4882a593Smuzhiyun  * @param dev The device that is responsible for the event.
2712*4882a593Smuzhiyun  *
2713*4882a593Smuzhiyun  * @see DeliverGrabbedEvent
2714*4882a593Smuzhiyun  * @see DeliverFocusedEvent
2715*4882a593Smuzhiyun  */
2716*4882a593Smuzhiyun int
DeliverDeviceEvents(WindowPtr pWin,InternalEvent * event,GrabPtr grab,WindowPtr stopAt,DeviceIntPtr dev)2717*4882a593Smuzhiyun DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab,
2718*4882a593Smuzhiyun                     WindowPtr stopAt, DeviceIntPtr dev)
2719*4882a593Smuzhiyun {
2720*4882a593Smuzhiyun     Window child = None;
2721*4882a593Smuzhiyun     int deliveries = 0;
2722*4882a593Smuzhiyun     int mask;
2723*4882a593Smuzhiyun 
2724*4882a593Smuzhiyun     verify_internal_event(event);
2725*4882a593Smuzhiyun 
2726*4882a593Smuzhiyun     while (pWin) {
2727*4882a593Smuzhiyun         if ((mask = EventIsDeliverable(dev, event->any.type, pWin))) {
2728*4882a593Smuzhiyun             /* XI2 events first */
2729*4882a593Smuzhiyun             if (mask & EVENT_XI2_MASK) {
2730*4882a593Smuzhiyun                 deliveries =
2731*4882a593Smuzhiyun                     DeliverOneEvent(event, dev, XI2, pWin, child, grab);
2732*4882a593Smuzhiyun                 if (deliveries > 0)
2733*4882a593Smuzhiyun                     break;
2734*4882a593Smuzhiyun             }
2735*4882a593Smuzhiyun 
2736*4882a593Smuzhiyun             /* XI events */
2737*4882a593Smuzhiyun             if (mask & EVENT_XI1_MASK) {
2738*4882a593Smuzhiyun                 deliveries = DeliverOneEvent(event, dev, XI, pWin, child, grab);
2739*4882a593Smuzhiyun                 if (deliveries > 0)
2740*4882a593Smuzhiyun                     break;
2741*4882a593Smuzhiyun             }
2742*4882a593Smuzhiyun 
2743*4882a593Smuzhiyun             /* Core event */
2744*4882a593Smuzhiyun             if ((mask & EVENT_CORE_MASK) && IsMaster(dev) && dev->coreEvents) {
2745*4882a593Smuzhiyun                 deliveries =
2746*4882a593Smuzhiyun                     DeliverOneEvent(event, dev, CORE, pWin, child, grab);
2747*4882a593Smuzhiyun                 if (deliveries > 0)
2748*4882a593Smuzhiyun                     break;
2749*4882a593Smuzhiyun             }
2750*4882a593Smuzhiyun 
2751*4882a593Smuzhiyun         }
2752*4882a593Smuzhiyun 
2753*4882a593Smuzhiyun         if ((deliveries < 0) || (pWin == stopAt) ||
2754*4882a593Smuzhiyun             (mask & EVENT_DONT_PROPAGATE_MASK)) {
2755*4882a593Smuzhiyun             deliveries = 0;
2756*4882a593Smuzhiyun             break;
2757*4882a593Smuzhiyun         }
2758*4882a593Smuzhiyun 
2759*4882a593Smuzhiyun         child = pWin->drawable.id;
2760*4882a593Smuzhiyun         pWin = pWin->parent;
2761*4882a593Smuzhiyun     }
2762*4882a593Smuzhiyun 
2763*4882a593Smuzhiyun     return deliveries;
2764*4882a593Smuzhiyun }
2765*4882a593Smuzhiyun 
2766*4882a593Smuzhiyun /**
2767*4882a593Smuzhiyun  * Deliver event to a window and it's immediate parent. Used for most window
2768*4882a593Smuzhiyun  * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that
2769*4882a593Smuzhiyun  * propagate up the tree or extension events
2770*4882a593Smuzhiyun  *
2771*4882a593Smuzhiyun  * In case of a ReparentNotify event, the event will be delivered to the
2772*4882a593Smuzhiyun  * otherParent as well.
2773*4882a593Smuzhiyun  *
2774*4882a593Smuzhiyun  * @param pWin Window to deliver events to.
2775*4882a593Smuzhiyun  * @param xE Events to deliver.
2776*4882a593Smuzhiyun  * @param count number of events in xE.
2777*4882a593Smuzhiyun  * @param otherParent Used for ReparentNotify events.
2778*4882a593Smuzhiyun  */
2779*4882a593Smuzhiyun int
DeliverEvents(WindowPtr pWin,xEvent * xE,int count,WindowPtr otherParent)2780*4882a593Smuzhiyun DeliverEvents(WindowPtr pWin, xEvent *xE, int count, WindowPtr otherParent)
2781*4882a593Smuzhiyun {
2782*4882a593Smuzhiyun     DeviceIntRec dummy;
2783*4882a593Smuzhiyun     int deliveries;
2784*4882a593Smuzhiyun 
2785*4882a593Smuzhiyun #ifdef PANORAMIX
2786*4882a593Smuzhiyun     if (!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
2787*4882a593Smuzhiyun         return count;
2788*4882a593Smuzhiyun #endif
2789*4882a593Smuzhiyun 
2790*4882a593Smuzhiyun     if (!count)
2791*4882a593Smuzhiyun         return 0;
2792*4882a593Smuzhiyun 
2793*4882a593Smuzhiyun     dummy.id = XIAllDevices;
2794*4882a593Smuzhiyun 
2795*4882a593Smuzhiyun     switch (xE->u.u.type) {
2796*4882a593Smuzhiyun     case DestroyNotify:
2797*4882a593Smuzhiyun     case UnmapNotify:
2798*4882a593Smuzhiyun     case MapNotify:
2799*4882a593Smuzhiyun     case MapRequest:
2800*4882a593Smuzhiyun     case ReparentNotify:
2801*4882a593Smuzhiyun     case ConfigureNotify:
2802*4882a593Smuzhiyun     case ConfigureRequest:
2803*4882a593Smuzhiyun     case GravityNotify:
2804*4882a593Smuzhiyun     case CirculateNotify:
2805*4882a593Smuzhiyun     case CirculateRequest:
2806*4882a593Smuzhiyun         xE->u.destroyNotify.event = pWin->drawable.id;
2807*4882a593Smuzhiyun         break;
2808*4882a593Smuzhiyun     }
2809*4882a593Smuzhiyun 
2810*4882a593Smuzhiyun     switch (xE->u.u.type) {
2811*4882a593Smuzhiyun     case DestroyNotify:
2812*4882a593Smuzhiyun     case UnmapNotify:
2813*4882a593Smuzhiyun     case MapNotify:
2814*4882a593Smuzhiyun     case ReparentNotify:
2815*4882a593Smuzhiyun     case ConfigureNotify:
2816*4882a593Smuzhiyun     case GravityNotify:
2817*4882a593Smuzhiyun     case CirculateNotify:
2818*4882a593Smuzhiyun         break;
2819*4882a593Smuzhiyun     default:
2820*4882a593Smuzhiyun     {
2821*4882a593Smuzhiyun         Mask filter;
2822*4882a593Smuzhiyun 
2823*4882a593Smuzhiyun         filter = GetEventFilter(&dummy, xE);
2824*4882a593Smuzhiyun         return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, NullGrab);
2825*4882a593Smuzhiyun     }
2826*4882a593Smuzhiyun     }
2827*4882a593Smuzhiyun 
2828*4882a593Smuzhiyun     deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count,
2829*4882a593Smuzhiyun                                        StructureNotifyMask, NullGrab);
2830*4882a593Smuzhiyun     if (pWin->parent) {
2831*4882a593Smuzhiyun         xE->u.destroyNotify.event = pWin->parent->drawable.id;
2832*4882a593Smuzhiyun         deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count,
2833*4882a593Smuzhiyun                                             SubstructureNotifyMask, NullGrab);
2834*4882a593Smuzhiyun         if (xE->u.u.type == ReparentNotify) {
2835*4882a593Smuzhiyun             xE->u.destroyNotify.event = otherParent->drawable.id;
2836*4882a593Smuzhiyun             deliveries += DeliverEventsToWindow(&dummy,
2837*4882a593Smuzhiyun                                                 otherParent, xE, count,
2838*4882a593Smuzhiyun                                                 SubstructureNotifyMask,
2839*4882a593Smuzhiyun                                                 NullGrab);
2840*4882a593Smuzhiyun         }
2841*4882a593Smuzhiyun     }
2842*4882a593Smuzhiyun     return deliveries;
2843*4882a593Smuzhiyun }
2844*4882a593Smuzhiyun 
2845*4882a593Smuzhiyun Bool
PointInBorderSize(WindowPtr pWin,int x,int y)2846*4882a593Smuzhiyun PointInBorderSize(WindowPtr pWin, int x, int y)
2847*4882a593Smuzhiyun {
2848*4882a593Smuzhiyun     BoxRec box;
2849*4882a593Smuzhiyun 
2850*4882a593Smuzhiyun     if (RegionContainsPoint(&pWin->borderSize, x, y, &box))
2851*4882a593Smuzhiyun         return TRUE;
2852*4882a593Smuzhiyun 
2853*4882a593Smuzhiyun #ifdef PANORAMIX
2854*4882a593Smuzhiyun     if (!noPanoramiXExtension &&
2855*4882a593Smuzhiyun         XineramaSetWindowPntrs(inputInfo.pointer, pWin)) {
2856*4882a593Smuzhiyun         SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite;
2857*4882a593Smuzhiyun         int i;
2858*4882a593Smuzhiyun 
2859*4882a593Smuzhiyun         FOR_NSCREENS_FORWARD_SKIP(i) {
2860*4882a593Smuzhiyun             if (RegionContainsPoint(&pSprite->windows[i]->borderSize,
2861*4882a593Smuzhiyun                                     x + screenInfo.screens[0]->x -
2862*4882a593Smuzhiyun                                     screenInfo.screens[i]->x,
2863*4882a593Smuzhiyun                                     y + screenInfo.screens[0]->y -
2864*4882a593Smuzhiyun                                     screenInfo.screens[i]->y, &box))
2865*4882a593Smuzhiyun                 return TRUE;
2866*4882a593Smuzhiyun         }
2867*4882a593Smuzhiyun     }
2868*4882a593Smuzhiyun #endif
2869*4882a593Smuzhiyun     return FALSE;
2870*4882a593Smuzhiyun }
2871*4882a593Smuzhiyun 
2872*4882a593Smuzhiyun /**
2873*4882a593Smuzhiyun  * Traversed from the root window to the window at the position x/y. While
2874*4882a593Smuzhiyun  * traversing, it sets up the traversal history in the spriteTrace array.
2875*4882a593Smuzhiyun  * After completing, the spriteTrace history is set in the following way:
2876*4882a593Smuzhiyun  *   spriteTrace[0] ... root window
2877*4882a593Smuzhiyun  *   spriteTrace[1] ... top level window that encloses x/y
2878*4882a593Smuzhiyun  *       ...
2879*4882a593Smuzhiyun  *   spriteTrace[spriteTraceGood - 1] ... window at x/y
2880*4882a593Smuzhiyun  *
2881*4882a593Smuzhiyun  * @returns the window at the given coordinates.
2882*4882a593Smuzhiyun  */
2883*4882a593Smuzhiyun WindowPtr
XYToWindow(SpritePtr pSprite,int x,int y)2884*4882a593Smuzhiyun XYToWindow(SpritePtr pSprite, int x, int y)
2885*4882a593Smuzhiyun {
2886*4882a593Smuzhiyun     ScreenPtr pScreen = RootWindow(pSprite)->drawable.pScreen;
2887*4882a593Smuzhiyun 
2888*4882a593Smuzhiyun     return (*pScreen->XYToWindow)(pScreen, pSprite, x, y);
2889*4882a593Smuzhiyun }
2890*4882a593Smuzhiyun 
2891*4882a593Smuzhiyun /**
2892*4882a593Smuzhiyun  * Ungrab a currently FocusIn grabbed device and grab the device on the
2893*4882a593Smuzhiyun  * given window. If the win given is the NoneWin, the device is ungrabbed if
2894*4882a593Smuzhiyun  * applicable and FALSE is returned.
2895*4882a593Smuzhiyun  *
2896*4882a593Smuzhiyun  * @returns TRUE if the device has been grabbed, or FALSE otherwise.
2897*4882a593Smuzhiyun  */
2898*4882a593Smuzhiyun BOOL
ActivateFocusInGrab(DeviceIntPtr dev,WindowPtr old,WindowPtr win)2899*4882a593Smuzhiyun ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
2900*4882a593Smuzhiyun {
2901*4882a593Smuzhiyun     BOOL rc = FALSE;
2902*4882a593Smuzhiyun     DeviceEvent event;
2903*4882a593Smuzhiyun 
2904*4882a593Smuzhiyun     if (dev->deviceGrab.grab) {
2905*4882a593Smuzhiyun         if (!dev->deviceGrab.fromPassiveGrab ||
2906*4882a593Smuzhiyun             dev->deviceGrab.grab->type != XI_FocusIn ||
2907*4882a593Smuzhiyun             dev->deviceGrab.grab->window == win ||
2908*4882a593Smuzhiyun             IsParent(dev->deviceGrab.grab->window, win))
2909*4882a593Smuzhiyun             return FALSE;
2910*4882a593Smuzhiyun         DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab);
2911*4882a593Smuzhiyun         (*dev->deviceGrab.DeactivateGrab) (dev);
2912*4882a593Smuzhiyun     }
2913*4882a593Smuzhiyun 
2914*4882a593Smuzhiyun     if (win == NoneWin || win == PointerRootWin)
2915*4882a593Smuzhiyun         return FALSE;
2916*4882a593Smuzhiyun 
2917*4882a593Smuzhiyun     event = (DeviceEvent) {
2918*4882a593Smuzhiyun         .header = ET_Internal,
2919*4882a593Smuzhiyun         .type = ET_FocusIn,
2920*4882a593Smuzhiyun         .length = sizeof(DeviceEvent),
2921*4882a593Smuzhiyun         .time = GetTimeInMillis(),
2922*4882a593Smuzhiyun         .deviceid = dev->id,
2923*4882a593Smuzhiyun         .sourceid = dev->id,
2924*4882a593Smuzhiyun         .detail.button = 0
2925*4882a593Smuzhiyun     };
2926*4882a593Smuzhiyun     rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE,
2927*4882a593Smuzhiyun                                     TRUE) != NULL);
2928*4882a593Smuzhiyun     if (rc)
2929*4882a593Smuzhiyun         DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab);
2930*4882a593Smuzhiyun     return rc;
2931*4882a593Smuzhiyun }
2932*4882a593Smuzhiyun 
2933*4882a593Smuzhiyun /**
2934*4882a593Smuzhiyun  * Ungrab a currently Enter grabbed device and grab the device for the given
2935*4882a593Smuzhiyun  * window.
2936*4882a593Smuzhiyun  *
2937*4882a593Smuzhiyun  * @returns TRUE if the device has been grabbed, or FALSE otherwise.
2938*4882a593Smuzhiyun  */
2939*4882a593Smuzhiyun static BOOL
ActivateEnterGrab(DeviceIntPtr dev,WindowPtr old,WindowPtr win)2940*4882a593Smuzhiyun ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win)
2941*4882a593Smuzhiyun {
2942*4882a593Smuzhiyun     BOOL rc = FALSE;
2943*4882a593Smuzhiyun     DeviceEvent event;
2944*4882a593Smuzhiyun 
2945*4882a593Smuzhiyun     if (dev->deviceGrab.grab) {
2946*4882a593Smuzhiyun         if (!dev->deviceGrab.fromPassiveGrab ||
2947*4882a593Smuzhiyun             dev->deviceGrab.grab->type != XI_Enter ||
2948*4882a593Smuzhiyun             dev->deviceGrab.grab->window == win ||
2949*4882a593Smuzhiyun             IsParent(dev->deviceGrab.grab->window, win))
2950*4882a593Smuzhiyun             return FALSE;
2951*4882a593Smuzhiyun         DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab);
2952*4882a593Smuzhiyun         (*dev->deviceGrab.DeactivateGrab) (dev);
2953*4882a593Smuzhiyun     }
2954*4882a593Smuzhiyun 
2955*4882a593Smuzhiyun     event = (DeviceEvent) {
2956*4882a593Smuzhiyun         .header = ET_Internal,
2957*4882a593Smuzhiyun         .type = ET_Enter,
2958*4882a593Smuzhiyun         .length = sizeof(DeviceEvent),
2959*4882a593Smuzhiyun         .time = GetTimeInMillis(),
2960*4882a593Smuzhiyun         .deviceid = dev->id,
2961*4882a593Smuzhiyun         .sourceid = dev->id,
2962*4882a593Smuzhiyun         .detail.button = 0
2963*4882a593Smuzhiyun     };
2964*4882a593Smuzhiyun     rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE,
2965*4882a593Smuzhiyun                                     TRUE) != NULL);
2966*4882a593Smuzhiyun     if (rc)
2967*4882a593Smuzhiyun         DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab);
2968*4882a593Smuzhiyun     return rc;
2969*4882a593Smuzhiyun }
2970*4882a593Smuzhiyun 
2971*4882a593Smuzhiyun /**
2972*4882a593Smuzhiyun  * Update the sprite coordinates based on the event. Update the cursor
2973*4882a593Smuzhiyun  * position, then update the event with the new coordinates that may have been
2974*4882a593Smuzhiyun  * changed. If the window underneath the sprite has changed, change to new
2975*4882a593Smuzhiyun  * cursor and send enter/leave events.
2976*4882a593Smuzhiyun  *
2977*4882a593Smuzhiyun  * CheckMotion() will not do anything and return FALSE if the event is not a
2978*4882a593Smuzhiyun  * pointer event.
2979*4882a593Smuzhiyun  *
2980*4882a593Smuzhiyun  * @return TRUE if the sprite has moved or FALSE otherwise.
2981*4882a593Smuzhiyun  */
2982*4882a593Smuzhiyun Bool
CheckMotion(DeviceEvent * ev,DeviceIntPtr pDev)2983*4882a593Smuzhiyun CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev)
2984*4882a593Smuzhiyun {
2985*4882a593Smuzhiyun     WindowPtr prevSpriteWin, newSpriteWin;
2986*4882a593Smuzhiyun     SpritePtr pSprite = pDev->spriteInfo->sprite;
2987*4882a593Smuzhiyun 
2988*4882a593Smuzhiyun     verify_internal_event((InternalEvent *) ev);
2989*4882a593Smuzhiyun 
2990*4882a593Smuzhiyun     prevSpriteWin = pSprite->win;
2991*4882a593Smuzhiyun 
2992*4882a593Smuzhiyun     if (ev && !syncEvents.playingEvents) {
2993*4882a593Smuzhiyun         /* GetPointerEvents() guarantees that pointer events have the correct
2994*4882a593Smuzhiyun            rootX/Y set already. */
2995*4882a593Smuzhiyun         switch (ev->type) {
2996*4882a593Smuzhiyun         case ET_ButtonPress:
2997*4882a593Smuzhiyun         case ET_ButtonRelease:
2998*4882a593Smuzhiyun         case ET_Motion:
2999*4882a593Smuzhiyun         case ET_TouchBegin:
3000*4882a593Smuzhiyun         case ET_TouchUpdate:
3001*4882a593Smuzhiyun         case ET_TouchEnd:
3002*4882a593Smuzhiyun             break;
3003*4882a593Smuzhiyun         default:
3004*4882a593Smuzhiyun             /* all other events return FALSE */
3005*4882a593Smuzhiyun             return FALSE;
3006*4882a593Smuzhiyun         }
3007*4882a593Smuzhiyun 
3008*4882a593Smuzhiyun #ifdef PANORAMIX
3009*4882a593Smuzhiyun         if (!noPanoramiXExtension) {
3010*4882a593Smuzhiyun             /* Motion events entering DIX get translated to Screen 0
3011*4882a593Smuzhiyun                coordinates.  Replayed events have already been
3012*4882a593Smuzhiyun                translated since they've entered DIX before */
3013*4882a593Smuzhiyun             ev->root_x += pSprite->screen->x - screenInfo.screens[0]->x;
3014*4882a593Smuzhiyun             ev->root_y += pSprite->screen->y - screenInfo.screens[0]->y;
3015*4882a593Smuzhiyun         }
3016*4882a593Smuzhiyun         else
3017*4882a593Smuzhiyun #endif
3018*4882a593Smuzhiyun         {
3019*4882a593Smuzhiyun             if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) {
3020*4882a593Smuzhiyun                 pSprite->hot.pScreen = pSprite->hotPhys.pScreen;
3021*4882a593Smuzhiyun                 RootWindow(pDev->spriteInfo->sprite) =
3022*4882a593Smuzhiyun                     pSprite->hot.pScreen->root;
3023*4882a593Smuzhiyun             }
3024*4882a593Smuzhiyun         }
3025*4882a593Smuzhiyun 
3026*4882a593Smuzhiyun         pSprite->hot.x = ev->root_x;
3027*4882a593Smuzhiyun         pSprite->hot.y = ev->root_y;
3028*4882a593Smuzhiyun         if (pSprite->hot.x < pSprite->physLimits.x1)
3029*4882a593Smuzhiyun             pSprite->hot.x = pSprite->physLimits.x1;
3030*4882a593Smuzhiyun         else if (pSprite->hot.x >= pSprite->physLimits.x2)
3031*4882a593Smuzhiyun             pSprite->hot.x = pSprite->physLimits.x2 - 1;
3032*4882a593Smuzhiyun         if (pSprite->hot.y < pSprite->physLimits.y1)
3033*4882a593Smuzhiyun             pSprite->hot.y = pSprite->physLimits.y1;
3034*4882a593Smuzhiyun         else if (pSprite->hot.y >= pSprite->physLimits.y2)
3035*4882a593Smuzhiyun             pSprite->hot.y = pSprite->physLimits.y2 - 1;
3036*4882a593Smuzhiyun         if (pSprite->hotShape)
3037*4882a593Smuzhiyun             ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x,
3038*4882a593Smuzhiyun                            &pSprite->hot.y);
3039*4882a593Smuzhiyun         pSprite->hotPhys = pSprite->hot;
3040*4882a593Smuzhiyun 
3041*4882a593Smuzhiyun         if ((pSprite->hotPhys.x != ev->root_x) ||
3042*4882a593Smuzhiyun             (pSprite->hotPhys.y != ev->root_y)) {
3043*4882a593Smuzhiyun #ifdef PANORAMIX
3044*4882a593Smuzhiyun             if (!noPanoramiXExtension) {
3045*4882a593Smuzhiyun                 XineramaSetCursorPosition(pDev, pSprite->hotPhys.x,
3046*4882a593Smuzhiyun                                           pSprite->hotPhys.y, FALSE);
3047*4882a593Smuzhiyun             }
3048*4882a593Smuzhiyun             else
3049*4882a593Smuzhiyun #endif
3050*4882a593Smuzhiyun             {
3051*4882a593Smuzhiyun                 (*pSprite->hotPhys.pScreen->SetCursorPosition) (pDev,
3052*4882a593Smuzhiyun                                                                 pSprite->
3053*4882a593Smuzhiyun                                                                 hotPhys.pScreen,
3054*4882a593Smuzhiyun                                                                 pSprite->
3055*4882a593Smuzhiyun                                                                 hotPhys.x,
3056*4882a593Smuzhiyun                                                                 pSprite->
3057*4882a593Smuzhiyun                                                                 hotPhys.y,
3058*4882a593Smuzhiyun                                                                 FALSE);
3059*4882a593Smuzhiyun             }
3060*4882a593Smuzhiyun         }
3061*4882a593Smuzhiyun 
3062*4882a593Smuzhiyun         ev->root_x = pSprite->hot.x;
3063*4882a593Smuzhiyun         ev->root_y = pSprite->hot.y;
3064*4882a593Smuzhiyun     }
3065*4882a593Smuzhiyun 
3066*4882a593Smuzhiyun     newSpriteWin = XYToWindow(pSprite, pSprite->hot.x, pSprite->hot.y);
3067*4882a593Smuzhiyun 
3068*4882a593Smuzhiyun     if (newSpriteWin != prevSpriteWin) {
3069*4882a593Smuzhiyun         int sourceid;
3070*4882a593Smuzhiyun 
3071*4882a593Smuzhiyun         if (!ev) {
3072*4882a593Smuzhiyun             UpdateCurrentTimeIf();
3073*4882a593Smuzhiyun             sourceid = pDev->id;        /* when from WindowsRestructured */
3074*4882a593Smuzhiyun         }
3075*4882a593Smuzhiyun         else
3076*4882a593Smuzhiyun             sourceid = ev->sourceid;
3077*4882a593Smuzhiyun 
3078*4882a593Smuzhiyun         if (prevSpriteWin != NullWindow) {
3079*4882a593Smuzhiyun             if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin))
3080*4882a593Smuzhiyun                 DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin,
3081*4882a593Smuzhiyun                                    newSpriteWin, NotifyNormal);
3082*4882a593Smuzhiyun         }
3083*4882a593Smuzhiyun         /* set pSprite->win after ActivateEnterGrab, otherwise
3084*4882a593Smuzhiyun            sprite window == grab_window and no enter/leave events are
3085*4882a593Smuzhiyun            sent. */
3086*4882a593Smuzhiyun         pSprite->win = newSpriteWin;
3087*4882a593Smuzhiyun         PostNewCursor(pDev);
3088*4882a593Smuzhiyun         return FALSE;
3089*4882a593Smuzhiyun     }
3090*4882a593Smuzhiyun     return TRUE;
3091*4882a593Smuzhiyun }
3092*4882a593Smuzhiyun 
3093*4882a593Smuzhiyun /**
3094*4882a593Smuzhiyun  * Windows have restructured, we need to update the sprite position and the
3095*4882a593Smuzhiyun  * sprite's cursor.
3096*4882a593Smuzhiyun  */
3097*4882a593Smuzhiyun void
WindowsRestructured(void)3098*4882a593Smuzhiyun WindowsRestructured(void)
3099*4882a593Smuzhiyun {
3100*4882a593Smuzhiyun     DeviceIntPtr pDev = inputInfo.devices;
3101*4882a593Smuzhiyun 
3102*4882a593Smuzhiyun     while (pDev) {
3103*4882a593Smuzhiyun         if (IsMaster(pDev) || IsFloating(pDev))
3104*4882a593Smuzhiyun             CheckMotion(NULL, pDev);
3105*4882a593Smuzhiyun         pDev = pDev->next;
3106*4882a593Smuzhiyun     }
3107*4882a593Smuzhiyun }
3108*4882a593Smuzhiyun 
3109*4882a593Smuzhiyun #ifdef PANORAMIX
3110*4882a593Smuzhiyun /* This was added to support reconfiguration under Xdmx.  The problem is
3111*4882a593Smuzhiyun  * that if the 0th screen (i.e., screenInfo.screens[0]) is moved to an origin
3112*4882a593Smuzhiyun  * other than 0,0, the information in the private sprite structure must
3113*4882a593Smuzhiyun  * be updated accordingly, or XYToWindow (and other routines) will not
3114*4882a593Smuzhiyun  * compute correctly. */
3115*4882a593Smuzhiyun void
ReinitializeRootWindow(WindowPtr win,int xoff,int yoff)3116*4882a593Smuzhiyun ReinitializeRootWindow(WindowPtr win, int xoff, int yoff)
3117*4882a593Smuzhiyun {
3118*4882a593Smuzhiyun     GrabPtr grab;
3119*4882a593Smuzhiyun     DeviceIntPtr pDev;
3120*4882a593Smuzhiyun     SpritePtr pSprite;
3121*4882a593Smuzhiyun 
3122*4882a593Smuzhiyun     if (noPanoramiXExtension)
3123*4882a593Smuzhiyun         return;
3124*4882a593Smuzhiyun 
3125*4882a593Smuzhiyun     pDev = inputInfo.devices;
3126*4882a593Smuzhiyun     while (pDev) {
3127*4882a593Smuzhiyun         if (DevHasCursor(pDev)) {
3128*4882a593Smuzhiyun             pSprite = pDev->spriteInfo->sprite;
3129*4882a593Smuzhiyun             pSprite->hot.x -= xoff;
3130*4882a593Smuzhiyun             pSprite->hot.y -= yoff;
3131*4882a593Smuzhiyun 
3132*4882a593Smuzhiyun             pSprite->hotPhys.x -= xoff;
3133*4882a593Smuzhiyun             pSprite->hotPhys.y -= yoff;
3134*4882a593Smuzhiyun 
3135*4882a593Smuzhiyun             pSprite->hotLimits.x1 -= xoff;
3136*4882a593Smuzhiyun             pSprite->hotLimits.y1 -= yoff;
3137*4882a593Smuzhiyun             pSprite->hotLimits.x2 -= xoff;
3138*4882a593Smuzhiyun             pSprite->hotLimits.y2 -= yoff;
3139*4882a593Smuzhiyun 
3140*4882a593Smuzhiyun             if (RegionNotEmpty(&pSprite->Reg1))
3141*4882a593Smuzhiyun                 RegionTranslate(&pSprite->Reg1, xoff, yoff);
3142*4882a593Smuzhiyun             if (RegionNotEmpty(&pSprite->Reg2))
3143*4882a593Smuzhiyun                 RegionTranslate(&pSprite->Reg2, xoff, yoff);
3144*4882a593Smuzhiyun 
3145*4882a593Smuzhiyun             /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */
3146*4882a593Smuzhiyun             if ((grab = pDev->deviceGrab.grab) && grab->confineTo) {
3147*4882a593Smuzhiyun                 if (grab->confineTo->drawable.pScreen
3148*4882a593Smuzhiyun                     != pSprite->hotPhys.pScreen)
3149*4882a593Smuzhiyun                     pSprite->hotPhys.x = pSprite->hotPhys.y = 0;
3150*4882a593Smuzhiyun                 ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE);
3151*4882a593Smuzhiyun             }
3152*4882a593Smuzhiyun             else
3153*4882a593Smuzhiyun                 ConfineCursorToWindow(pDev,
3154*4882a593Smuzhiyun                                       pSprite->hotPhys.pScreen->root,
3155*4882a593Smuzhiyun                                       TRUE, FALSE);
3156*4882a593Smuzhiyun 
3157*4882a593Smuzhiyun         }
3158*4882a593Smuzhiyun         pDev = pDev->next;
3159*4882a593Smuzhiyun     }
3160*4882a593Smuzhiyun }
3161*4882a593Smuzhiyun #endif
3162*4882a593Smuzhiyun 
3163*4882a593Smuzhiyun /**
3164*4882a593Smuzhiyun  * Initialize a sprite for the given device and set it to some sane values. If
3165*4882a593Smuzhiyun  * the device already has a sprite alloc'd, don't realloc but just reset to
3166*4882a593Smuzhiyun  * default values.
3167*4882a593Smuzhiyun  * If a window is supplied, the sprite will be initialized with the window's
3168*4882a593Smuzhiyun  * cursor and positioned in the center of the window's screen. The root window
3169*4882a593Smuzhiyun  * is a good choice to pass in here.
3170*4882a593Smuzhiyun  *
3171*4882a593Smuzhiyun  * It's a good idea to call it only for pointer devices, unless you have a
3172*4882a593Smuzhiyun  * really talented keyboard.
3173*4882a593Smuzhiyun  *
3174*4882a593Smuzhiyun  * @param pDev The device to initialize.
3175*4882a593Smuzhiyun  * @param pWin The window where to generate the sprite in.
3176*4882a593Smuzhiyun  *
3177*4882a593Smuzhiyun  */
3178*4882a593Smuzhiyun void
InitializeSprite(DeviceIntPtr pDev,WindowPtr pWin)3179*4882a593Smuzhiyun InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin)
3180*4882a593Smuzhiyun {
3181*4882a593Smuzhiyun     SpritePtr pSprite;
3182*4882a593Smuzhiyun     ScreenPtr pScreen;
3183*4882a593Smuzhiyun     CursorPtr pCursor;
3184*4882a593Smuzhiyun 
3185*4882a593Smuzhiyun     if (!pDev->spriteInfo->sprite) {
3186*4882a593Smuzhiyun         DeviceIntPtr it;
3187*4882a593Smuzhiyun 
3188*4882a593Smuzhiyun         pDev->spriteInfo->sprite = (SpritePtr) calloc(1, sizeof(SpriteRec));
3189*4882a593Smuzhiyun         if (!pDev->spriteInfo->sprite)
3190*4882a593Smuzhiyun             FatalError("InitializeSprite: failed to allocate sprite struct");
3191*4882a593Smuzhiyun 
3192*4882a593Smuzhiyun         /* We may have paired another device with this device before our
3193*4882a593Smuzhiyun          * device had a actual sprite. We need to check for this and reset the
3194*4882a593Smuzhiyun          * sprite field for all paired devices.
3195*4882a593Smuzhiyun          *
3196*4882a593Smuzhiyun          * The VCK is always paired with the VCP before the VCP has a sprite.
3197*4882a593Smuzhiyun          */
3198*4882a593Smuzhiyun         for (it = inputInfo.devices; it; it = it->next) {
3199*4882a593Smuzhiyun             if (it->spriteInfo->paired == pDev)
3200*4882a593Smuzhiyun                 it->spriteInfo->sprite = pDev->spriteInfo->sprite;
3201*4882a593Smuzhiyun         }
3202*4882a593Smuzhiyun         if (inputInfo.keyboard->spriteInfo->paired == pDev)
3203*4882a593Smuzhiyun             inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite;
3204*4882a593Smuzhiyun     }
3205*4882a593Smuzhiyun 
3206*4882a593Smuzhiyun     pSprite = pDev->spriteInfo->sprite;
3207*4882a593Smuzhiyun     pDev->spriteInfo->spriteOwner = TRUE;
3208*4882a593Smuzhiyun 
3209*4882a593Smuzhiyun     pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr) NULL;
3210*4882a593Smuzhiyun     pSprite->hot.pScreen = pScreen;
3211*4882a593Smuzhiyun     pSprite->hotPhys.pScreen = pScreen;
3212*4882a593Smuzhiyun     if (pScreen) {
3213*4882a593Smuzhiyun         pSprite->hotPhys.x = pScreen->width / 2;
3214*4882a593Smuzhiyun         pSprite->hotPhys.y = pScreen->height / 2;
3215*4882a593Smuzhiyun         pSprite->hotLimits.x2 = pScreen->width;
3216*4882a593Smuzhiyun         pSprite->hotLimits.y2 = pScreen->height;
3217*4882a593Smuzhiyun     }
3218*4882a593Smuzhiyun 
3219*4882a593Smuzhiyun     pSprite->hot = pSprite->hotPhys;
3220*4882a593Smuzhiyun     pSprite->win = pWin;
3221*4882a593Smuzhiyun 
3222*4882a593Smuzhiyun     if (pWin) {
3223*4882a593Smuzhiyun         pCursor = wCursor(pWin);
3224*4882a593Smuzhiyun         pSprite->spriteTrace = (WindowPtr *) calloc(1, 32 * sizeof(WindowPtr));
3225*4882a593Smuzhiyun         if (!pSprite->spriteTrace)
3226*4882a593Smuzhiyun             FatalError("Failed to allocate spriteTrace");
3227*4882a593Smuzhiyun         pSprite->spriteTraceSize = 32;
3228*4882a593Smuzhiyun 
3229*4882a593Smuzhiyun         RootWindow(pDev->spriteInfo->sprite) = pWin;
3230*4882a593Smuzhiyun         pSprite->spriteTraceGood = 1;
3231*4882a593Smuzhiyun 
3232*4882a593Smuzhiyun         pSprite->pEnqueueScreen = pScreen;
3233*4882a593Smuzhiyun         pSprite->pDequeueScreen = pSprite->pEnqueueScreen;
3234*4882a593Smuzhiyun 
3235*4882a593Smuzhiyun     }
3236*4882a593Smuzhiyun     else {
3237*4882a593Smuzhiyun         pCursor = NullCursor;
3238*4882a593Smuzhiyun         pSprite->spriteTrace = NULL;
3239*4882a593Smuzhiyun         pSprite->spriteTraceSize = 0;
3240*4882a593Smuzhiyun         pSprite->spriteTraceGood = 0;
3241*4882a593Smuzhiyun         pSprite->pEnqueueScreen = screenInfo.screens[0];
3242*4882a593Smuzhiyun         pSprite->pDequeueScreen = pSprite->pEnqueueScreen;
3243*4882a593Smuzhiyun     }
3244*4882a593Smuzhiyun     pCursor = RefCursor(pCursor);
3245*4882a593Smuzhiyun     if (pSprite->current)
3246*4882a593Smuzhiyun         FreeCursor(pSprite->current, None);
3247*4882a593Smuzhiyun     pSprite->current = pCursor;
3248*4882a593Smuzhiyun 
3249*4882a593Smuzhiyun     if (pScreen) {
3250*4882a593Smuzhiyun         (*pScreen->RealizeCursor) (pDev, pScreen, pSprite->current);
3251*4882a593Smuzhiyun         (*pScreen->CursorLimits) (pDev, pScreen, pSprite->current,
3252*4882a593Smuzhiyun                                   &pSprite->hotLimits, &pSprite->physLimits);
3253*4882a593Smuzhiyun         pSprite->confined = FALSE;
3254*4882a593Smuzhiyun 
3255*4882a593Smuzhiyun         (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits);
3256*4882a593Smuzhiyun         (*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x,
3257*4882a593Smuzhiyun                                        pSprite->hot.y, FALSE);
3258*4882a593Smuzhiyun         (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current);
3259*4882a593Smuzhiyun     }
3260*4882a593Smuzhiyun #ifdef PANORAMIX
3261*4882a593Smuzhiyun     if (!noPanoramiXExtension) {
3262*4882a593Smuzhiyun         pSprite->hotLimits.x1 = -screenInfo.screens[0]->x;
3263*4882a593Smuzhiyun         pSprite->hotLimits.y1 = -screenInfo.screens[0]->y;
3264*4882a593Smuzhiyun         pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x;
3265*4882a593Smuzhiyun         pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y;
3266*4882a593Smuzhiyun         pSprite->physLimits = pSprite->hotLimits;
3267*4882a593Smuzhiyun         pSprite->confineWin = NullWindow;
3268*4882a593Smuzhiyun         pSprite->hotShape = NullRegion;
3269*4882a593Smuzhiyun         pSprite->screen = pScreen;
3270*4882a593Smuzhiyun         /* gotta UNINIT these someplace */
3271*4882a593Smuzhiyun         RegionNull(&pSprite->Reg1);
3272*4882a593Smuzhiyun         RegionNull(&pSprite->Reg2);
3273*4882a593Smuzhiyun     }
3274*4882a593Smuzhiyun #endif
3275*4882a593Smuzhiyun }
3276*4882a593Smuzhiyun 
FreeSprite(DeviceIntPtr dev)3277*4882a593Smuzhiyun void FreeSprite(DeviceIntPtr dev)
3278*4882a593Smuzhiyun {
3279*4882a593Smuzhiyun     if (DevHasCursor(dev) && dev->spriteInfo->sprite) {
3280*4882a593Smuzhiyun         if (dev->spriteInfo->sprite->current)
3281*4882a593Smuzhiyun             FreeCursor(dev->spriteInfo->sprite->current, None);
3282*4882a593Smuzhiyun         free(dev->spriteInfo->sprite->spriteTrace);
3283*4882a593Smuzhiyun         free(dev->spriteInfo->sprite);
3284*4882a593Smuzhiyun     }
3285*4882a593Smuzhiyun     dev->spriteInfo->sprite = NULL;
3286*4882a593Smuzhiyun }
3287*4882a593Smuzhiyun 
3288*4882a593Smuzhiyun 
3289*4882a593Smuzhiyun /**
3290*4882a593Smuzhiyun  * Update the mouse sprite info when the server switches from a pScreen to another.
3291*4882a593Smuzhiyun  * Otherwise, the pScreen of the mouse sprite is never updated when we switch
3292*4882a593Smuzhiyun  * from a pScreen to another. Never updating the pScreen of the mouse sprite
3293*4882a593Smuzhiyun  * implies that windows that are in pScreen whose pScreen->myNum >0 will never
3294*4882a593Smuzhiyun  * get pointer events. This is  because in CheckMotion(), sprite.hotPhys.pScreen
3295*4882a593Smuzhiyun  * always points to the first pScreen it has been set by
3296*4882a593Smuzhiyun  * DefineInitialRootWindow().
3297*4882a593Smuzhiyun  *
3298*4882a593Smuzhiyun  * Calling this function is useful for use cases where the server
3299*4882a593Smuzhiyun  * has more than one pScreen.
3300*4882a593Smuzhiyun  * This function is similar to DefineInitialRootWindow() but it does not
3301*4882a593Smuzhiyun  * reset the mouse pointer position.
3302*4882a593Smuzhiyun  * @param win must be the new pScreen we are switching to.
3303*4882a593Smuzhiyun  */
3304*4882a593Smuzhiyun void
UpdateSpriteForScreen(DeviceIntPtr pDev,ScreenPtr pScreen)3305*4882a593Smuzhiyun UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen)
3306*4882a593Smuzhiyun {
3307*4882a593Smuzhiyun     SpritePtr pSprite = NULL;
3308*4882a593Smuzhiyun     WindowPtr win = NULL;
3309*4882a593Smuzhiyun     CursorPtr pCursor;
3310*4882a593Smuzhiyun 
3311*4882a593Smuzhiyun     if (!pScreen)
3312*4882a593Smuzhiyun         return;
3313*4882a593Smuzhiyun 
3314*4882a593Smuzhiyun     if (!pDev->spriteInfo->sprite)
3315*4882a593Smuzhiyun         return;
3316*4882a593Smuzhiyun 
3317*4882a593Smuzhiyun     pSprite = pDev->spriteInfo->sprite;
3318*4882a593Smuzhiyun 
3319*4882a593Smuzhiyun     win = pScreen->root;
3320*4882a593Smuzhiyun 
3321*4882a593Smuzhiyun     pSprite->hotPhys.pScreen = pScreen;
3322*4882a593Smuzhiyun     pSprite->hot = pSprite->hotPhys;
3323*4882a593Smuzhiyun     pSprite->hotLimits.x2 = pScreen->width;
3324*4882a593Smuzhiyun     pSprite->hotLimits.y2 = pScreen->height;
3325*4882a593Smuzhiyun     pSprite->win = win;
3326*4882a593Smuzhiyun     pCursor = RefCursor(wCursor(win));
3327*4882a593Smuzhiyun     if (pSprite->current)
3328*4882a593Smuzhiyun         FreeCursor(pSprite->current, 0);
3329*4882a593Smuzhiyun     pSprite->current = pCursor;
3330*4882a593Smuzhiyun     pSprite->spriteTraceGood = 1;
3331*4882a593Smuzhiyun     pSprite->spriteTrace[0] = win;
3332*4882a593Smuzhiyun     (*pScreen->CursorLimits) (pDev,
3333*4882a593Smuzhiyun                               pScreen,
3334*4882a593Smuzhiyun                               pSprite->current,
3335*4882a593Smuzhiyun                               &pSprite->hotLimits, &pSprite->physLimits);
3336*4882a593Smuzhiyun     pSprite->confined = FALSE;
3337*4882a593Smuzhiyun     (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits);
3338*4882a593Smuzhiyun     (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current);
3339*4882a593Smuzhiyun 
3340*4882a593Smuzhiyun #ifdef PANORAMIX
3341*4882a593Smuzhiyun     if (!noPanoramiXExtension) {
3342*4882a593Smuzhiyun         pSprite->hotLimits.x1 = -screenInfo.screens[0]->x;
3343*4882a593Smuzhiyun         pSprite->hotLimits.y1 = -screenInfo.screens[0]->y;
3344*4882a593Smuzhiyun         pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x;
3345*4882a593Smuzhiyun         pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y;
3346*4882a593Smuzhiyun         pSprite->physLimits = pSprite->hotLimits;
3347*4882a593Smuzhiyun         pSprite->screen = pScreen;
3348*4882a593Smuzhiyun     }
3349*4882a593Smuzhiyun #endif
3350*4882a593Smuzhiyun }
3351*4882a593Smuzhiyun 
3352*4882a593Smuzhiyun /*
3353*4882a593Smuzhiyun  * This does not take any shortcuts, and even ignores its argument, since
3354*4882a593Smuzhiyun  * it does not happen very often, and one has to walk up the tree since
3355*4882a593Smuzhiyun  * this might be a newly instantiated cursor for an intermediate window
3356*4882a593Smuzhiyun  * between the one the pointer is in and the one that the last cursor was
3357*4882a593Smuzhiyun  * instantiated from.
3358*4882a593Smuzhiyun  */
3359*4882a593Smuzhiyun void
WindowHasNewCursor(WindowPtr pWin)3360*4882a593Smuzhiyun WindowHasNewCursor(WindowPtr pWin)
3361*4882a593Smuzhiyun {
3362*4882a593Smuzhiyun     DeviceIntPtr pDev;
3363*4882a593Smuzhiyun 
3364*4882a593Smuzhiyun     for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
3365*4882a593Smuzhiyun         if (DevHasCursor(pDev))
3366*4882a593Smuzhiyun             PostNewCursor(pDev);
3367*4882a593Smuzhiyun }
3368*4882a593Smuzhiyun 
3369*4882a593Smuzhiyun void
NewCurrentScreen(DeviceIntPtr pDev,ScreenPtr newScreen,int x,int y)3370*4882a593Smuzhiyun NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y)
3371*4882a593Smuzhiyun {
3372*4882a593Smuzhiyun     DeviceIntPtr ptr;
3373*4882a593Smuzhiyun     SpritePtr pSprite;
3374*4882a593Smuzhiyun 
3375*4882a593Smuzhiyun     ptr =
3376*4882a593Smuzhiyun         IsFloating(pDev) ? pDev :
3377*4882a593Smuzhiyun         GetXTestDevice(GetMaster(pDev, MASTER_POINTER));
3378*4882a593Smuzhiyun     pSprite = ptr->spriteInfo->sprite;
3379*4882a593Smuzhiyun 
3380*4882a593Smuzhiyun     pSprite->hotPhys.x = x;
3381*4882a593Smuzhiyun     pSprite->hotPhys.y = y;
3382*4882a593Smuzhiyun #ifdef PANORAMIX
3383*4882a593Smuzhiyun     if (!noPanoramiXExtension) {
3384*4882a593Smuzhiyun         pSprite->hotPhys.x += newScreen->x - screenInfo.screens[0]->x;
3385*4882a593Smuzhiyun         pSprite->hotPhys.y += newScreen->y - screenInfo.screens[0]->y;
3386*4882a593Smuzhiyun         if (newScreen != pSprite->screen) {
3387*4882a593Smuzhiyun             pSprite->screen = newScreen;
3388*4882a593Smuzhiyun             /* Make sure we tell the DDX to update its copy of the screen */
3389*4882a593Smuzhiyun             if (pSprite->confineWin)
3390*4882a593Smuzhiyun                 XineramaConfineCursorToWindow(ptr, pSprite->confineWin, TRUE);
3391*4882a593Smuzhiyun             else
3392*4882a593Smuzhiyun                 XineramaConfineCursorToWindow(ptr, screenInfo.screens[0]->root,
3393*4882a593Smuzhiyun                                               TRUE);
3394*4882a593Smuzhiyun             /* if the pointer wasn't confined, the DDX won't get
3395*4882a593Smuzhiyun                told of the pointer warp so we reposition it here */
3396*4882a593Smuzhiyun             if (!syncEvents.playingEvents)
3397*4882a593Smuzhiyun                 (*pSprite->screen->SetCursorPosition) (ptr,
3398*4882a593Smuzhiyun                                                        pSprite->screen,
3399*4882a593Smuzhiyun                                                        pSprite->hotPhys.x +
3400*4882a593Smuzhiyun                                                        screenInfo.screens[0]->
3401*4882a593Smuzhiyun                                                        x - pSprite->screen->x,
3402*4882a593Smuzhiyun                                                        pSprite->hotPhys.y +
3403*4882a593Smuzhiyun                                                        screenInfo.screens[0]->
3404*4882a593Smuzhiyun                                                        y - pSprite->screen->y,
3405*4882a593Smuzhiyun                                                        FALSE);
3406*4882a593Smuzhiyun         }
3407*4882a593Smuzhiyun     }
3408*4882a593Smuzhiyun     else
3409*4882a593Smuzhiyun #endif
3410*4882a593Smuzhiyun     if (newScreen != pSprite->hotPhys.pScreen)
3411*4882a593Smuzhiyun         ConfineCursorToWindow(ptr, newScreen->root, TRUE, FALSE);
3412*4882a593Smuzhiyun }
3413*4882a593Smuzhiyun 
3414*4882a593Smuzhiyun #ifdef PANORAMIX
3415*4882a593Smuzhiyun 
3416*4882a593Smuzhiyun static Bool
XineramaPointInWindowIsVisible(WindowPtr pWin,int x,int y)3417*4882a593Smuzhiyun XineramaPointInWindowIsVisible(WindowPtr pWin, int x, int y)
3418*4882a593Smuzhiyun {
3419*4882a593Smuzhiyun     BoxRec box;
3420*4882a593Smuzhiyun     int i, xoff, yoff;
3421*4882a593Smuzhiyun 
3422*4882a593Smuzhiyun     if (!pWin->realized)
3423*4882a593Smuzhiyun         return FALSE;
3424*4882a593Smuzhiyun 
3425*4882a593Smuzhiyun     if (RegionContainsPoint(&pWin->borderClip, x, y, &box))
3426*4882a593Smuzhiyun         return TRUE;
3427*4882a593Smuzhiyun 
3428*4882a593Smuzhiyun     if (!XineramaSetWindowPntrs(inputInfo.pointer, pWin))
3429*4882a593Smuzhiyun          return FALSE;
3430*4882a593Smuzhiyun 
3431*4882a593Smuzhiyun     xoff = x + screenInfo.screens[0]->x;
3432*4882a593Smuzhiyun     yoff = y + screenInfo.screens[0]->y;
3433*4882a593Smuzhiyun 
3434*4882a593Smuzhiyun     FOR_NSCREENS_FORWARD_SKIP(i) {
3435*4882a593Smuzhiyun         pWin = inputInfo.pointer->spriteInfo->sprite->windows[i];
3436*4882a593Smuzhiyun 
3437*4882a593Smuzhiyun         x = xoff - screenInfo.screens[i]->x;
3438*4882a593Smuzhiyun         y = yoff - screenInfo.screens[i]->y;
3439*4882a593Smuzhiyun 
3440*4882a593Smuzhiyun         if (RegionContainsPoint(&pWin->borderClip, x, y, &box)
3441*4882a593Smuzhiyun             && (!wInputShape(pWin) ||
3442*4882a593Smuzhiyun                 RegionContainsPoint(wInputShape(pWin),
3443*4882a593Smuzhiyun                                     x - pWin->drawable.x,
3444*4882a593Smuzhiyun                                     y - pWin->drawable.y, &box)))
3445*4882a593Smuzhiyun             return TRUE;
3446*4882a593Smuzhiyun 
3447*4882a593Smuzhiyun     }
3448*4882a593Smuzhiyun 
3449*4882a593Smuzhiyun     return FALSE;
3450*4882a593Smuzhiyun }
3451*4882a593Smuzhiyun 
3452*4882a593Smuzhiyun static int
XineramaWarpPointer(ClientPtr client)3453*4882a593Smuzhiyun XineramaWarpPointer(ClientPtr client)
3454*4882a593Smuzhiyun {
3455*4882a593Smuzhiyun     WindowPtr dest = NULL;
3456*4882a593Smuzhiyun     int x, y, rc;
3457*4882a593Smuzhiyun     SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
3458*4882a593Smuzhiyun 
3459*4882a593Smuzhiyun     REQUEST(xWarpPointerReq);
3460*4882a593Smuzhiyun 
3461*4882a593Smuzhiyun     if (stuff->dstWid != None) {
3462*4882a593Smuzhiyun         rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess);
3463*4882a593Smuzhiyun         if (rc != Success)
3464*4882a593Smuzhiyun             return rc;
3465*4882a593Smuzhiyun     }
3466*4882a593Smuzhiyun     x = pSprite->hotPhys.x;
3467*4882a593Smuzhiyun     y = pSprite->hotPhys.y;
3468*4882a593Smuzhiyun 
3469*4882a593Smuzhiyun     if (stuff->srcWid != None) {
3470*4882a593Smuzhiyun         int winX, winY;
3471*4882a593Smuzhiyun         XID winID = stuff->srcWid;
3472*4882a593Smuzhiyun         WindowPtr source;
3473*4882a593Smuzhiyun 
3474*4882a593Smuzhiyun         rc = dixLookupWindow(&source, winID, client, DixReadAccess);
3475*4882a593Smuzhiyun         if (rc != Success)
3476*4882a593Smuzhiyun             return rc;
3477*4882a593Smuzhiyun 
3478*4882a593Smuzhiyun         winX = source->drawable.x;
3479*4882a593Smuzhiyun         winY = source->drawable.y;
3480*4882a593Smuzhiyun         if (source == screenInfo.screens[0]->root) {
3481*4882a593Smuzhiyun             winX -= screenInfo.screens[0]->x;
3482*4882a593Smuzhiyun             winY -= screenInfo.screens[0]->y;
3483*4882a593Smuzhiyun         }
3484*4882a593Smuzhiyun         if (x < winX + stuff->srcX ||
3485*4882a593Smuzhiyun             y < winY + stuff->srcY ||
3486*4882a593Smuzhiyun             (stuff->srcWidth != 0 &&
3487*4882a593Smuzhiyun              winX + stuff->srcX + (int) stuff->srcWidth < x) ||
3488*4882a593Smuzhiyun             (stuff->srcHeight != 0 &&
3489*4882a593Smuzhiyun              winY + stuff->srcY + (int) stuff->srcHeight < y) ||
3490*4882a593Smuzhiyun             !XineramaPointInWindowIsVisible(source, x, y))
3491*4882a593Smuzhiyun             return Success;
3492*4882a593Smuzhiyun     }
3493*4882a593Smuzhiyun     if (dest) {
3494*4882a593Smuzhiyun         x = dest->drawable.x;
3495*4882a593Smuzhiyun         y = dest->drawable.y;
3496*4882a593Smuzhiyun         if (dest == screenInfo.screens[0]->root) {
3497*4882a593Smuzhiyun             x -= screenInfo.screens[0]->x;
3498*4882a593Smuzhiyun             y -= screenInfo.screens[0]->y;
3499*4882a593Smuzhiyun         }
3500*4882a593Smuzhiyun     }
3501*4882a593Smuzhiyun 
3502*4882a593Smuzhiyun     x += stuff->dstX;
3503*4882a593Smuzhiyun     y += stuff->dstY;
3504*4882a593Smuzhiyun 
3505*4882a593Smuzhiyun     if (x < pSprite->physLimits.x1)
3506*4882a593Smuzhiyun         x = pSprite->physLimits.x1;
3507*4882a593Smuzhiyun     else if (x >= pSprite->physLimits.x2)
3508*4882a593Smuzhiyun         x = pSprite->physLimits.x2 - 1;
3509*4882a593Smuzhiyun     if (y < pSprite->physLimits.y1)
3510*4882a593Smuzhiyun         y = pSprite->physLimits.y1;
3511*4882a593Smuzhiyun     else if (y >= pSprite->physLimits.y2)
3512*4882a593Smuzhiyun         y = pSprite->physLimits.y2 - 1;
3513*4882a593Smuzhiyun     if (pSprite->hotShape)
3514*4882a593Smuzhiyun         ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y);
3515*4882a593Smuzhiyun 
3516*4882a593Smuzhiyun     XineramaSetCursorPosition(PickPointer(client), x, y, TRUE);
3517*4882a593Smuzhiyun 
3518*4882a593Smuzhiyun     return Success;
3519*4882a593Smuzhiyun }
3520*4882a593Smuzhiyun 
3521*4882a593Smuzhiyun #endif
3522*4882a593Smuzhiyun 
3523*4882a593Smuzhiyun /**
3524*4882a593Smuzhiyun  * Server-side protocol handling for WarpPointer request.
3525*4882a593Smuzhiyun  * Warps the cursor position to the coordinates given in the request.
3526*4882a593Smuzhiyun  */
3527*4882a593Smuzhiyun int
ProcWarpPointer(ClientPtr client)3528*4882a593Smuzhiyun ProcWarpPointer(ClientPtr client)
3529*4882a593Smuzhiyun {
3530*4882a593Smuzhiyun     WindowPtr dest = NULL;
3531*4882a593Smuzhiyun     int x, y, rc;
3532*4882a593Smuzhiyun     ScreenPtr newScreen;
3533*4882a593Smuzhiyun     DeviceIntPtr dev, tmp;
3534*4882a593Smuzhiyun     SpritePtr pSprite;
3535*4882a593Smuzhiyun 
3536*4882a593Smuzhiyun     REQUEST(xWarpPointerReq);
3537*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xWarpPointerReq);
3538*4882a593Smuzhiyun 
3539*4882a593Smuzhiyun     dev = PickPointer(client);
3540*4882a593Smuzhiyun 
3541*4882a593Smuzhiyun     for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
3542*4882a593Smuzhiyun         if (GetMaster(tmp, MASTER_ATTACHED) == dev) {
3543*4882a593Smuzhiyun             rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess);
3544*4882a593Smuzhiyun             if (rc != Success)
3545*4882a593Smuzhiyun                 return rc;
3546*4882a593Smuzhiyun         }
3547*4882a593Smuzhiyun     }
3548*4882a593Smuzhiyun 
3549*4882a593Smuzhiyun     if (dev->lastSlave)
3550*4882a593Smuzhiyun         dev = dev->lastSlave;
3551*4882a593Smuzhiyun     pSprite = dev->spriteInfo->sprite;
3552*4882a593Smuzhiyun 
3553*4882a593Smuzhiyun #ifdef PANORAMIX
3554*4882a593Smuzhiyun     if (!noPanoramiXExtension)
3555*4882a593Smuzhiyun         return XineramaWarpPointer(client);
3556*4882a593Smuzhiyun #endif
3557*4882a593Smuzhiyun 
3558*4882a593Smuzhiyun     if (stuff->dstWid != None) {
3559*4882a593Smuzhiyun         rc = dixLookupWindow(&dest, stuff->dstWid, client, DixGetAttrAccess);
3560*4882a593Smuzhiyun         if (rc != Success)
3561*4882a593Smuzhiyun             return rc;
3562*4882a593Smuzhiyun     }
3563*4882a593Smuzhiyun     x = pSprite->hotPhys.x;
3564*4882a593Smuzhiyun     y = pSprite->hotPhys.y;
3565*4882a593Smuzhiyun 
3566*4882a593Smuzhiyun     if (stuff->srcWid != None) {
3567*4882a593Smuzhiyun         int winX, winY;
3568*4882a593Smuzhiyun         XID winID = stuff->srcWid;
3569*4882a593Smuzhiyun         WindowPtr source;
3570*4882a593Smuzhiyun 
3571*4882a593Smuzhiyun         rc = dixLookupWindow(&source, winID, client, DixGetAttrAccess);
3572*4882a593Smuzhiyun         if (rc != Success)
3573*4882a593Smuzhiyun             return rc;
3574*4882a593Smuzhiyun 
3575*4882a593Smuzhiyun         winX = source->drawable.x;
3576*4882a593Smuzhiyun         winY = source->drawable.y;
3577*4882a593Smuzhiyun         if (source->drawable.pScreen != pSprite->hotPhys.pScreen ||
3578*4882a593Smuzhiyun             x < winX + stuff->srcX ||
3579*4882a593Smuzhiyun             y < winY + stuff->srcY ||
3580*4882a593Smuzhiyun             (stuff->srcWidth != 0 &&
3581*4882a593Smuzhiyun              winX + stuff->srcX + (int) stuff->srcWidth < x) ||
3582*4882a593Smuzhiyun             (stuff->srcHeight != 0 &&
3583*4882a593Smuzhiyun              winY + stuff->srcY + (int) stuff->srcHeight < y) ||
3584*4882a593Smuzhiyun             (source->parent && !PointInWindowIsVisible(source, x, y)))
3585*4882a593Smuzhiyun             return Success;
3586*4882a593Smuzhiyun     }
3587*4882a593Smuzhiyun     if (dest) {
3588*4882a593Smuzhiyun         x = dest->drawable.x;
3589*4882a593Smuzhiyun         y = dest->drawable.y;
3590*4882a593Smuzhiyun         newScreen = dest->drawable.pScreen;
3591*4882a593Smuzhiyun     }
3592*4882a593Smuzhiyun     else
3593*4882a593Smuzhiyun         newScreen = pSprite->hotPhys.pScreen;
3594*4882a593Smuzhiyun 
3595*4882a593Smuzhiyun     x += stuff->dstX;
3596*4882a593Smuzhiyun     y += stuff->dstY;
3597*4882a593Smuzhiyun 
3598*4882a593Smuzhiyun     if (x < 0)
3599*4882a593Smuzhiyun         x = 0;
3600*4882a593Smuzhiyun     else if (x >= newScreen->width)
3601*4882a593Smuzhiyun         x = newScreen->width - 1;
3602*4882a593Smuzhiyun     if (y < 0)
3603*4882a593Smuzhiyun         y = 0;
3604*4882a593Smuzhiyun     else if (y >= newScreen->height)
3605*4882a593Smuzhiyun         y = newScreen->height - 1;
3606*4882a593Smuzhiyun 
3607*4882a593Smuzhiyun     if (newScreen == pSprite->hotPhys.pScreen) {
3608*4882a593Smuzhiyun         if (x < pSprite->physLimits.x1)
3609*4882a593Smuzhiyun             x = pSprite->physLimits.x1;
3610*4882a593Smuzhiyun         else if (x >= pSprite->physLimits.x2)
3611*4882a593Smuzhiyun             x = pSprite->physLimits.x2 - 1;
3612*4882a593Smuzhiyun         if (y < pSprite->physLimits.y1)
3613*4882a593Smuzhiyun             y = pSprite->physLimits.y1;
3614*4882a593Smuzhiyun         else if (y >= pSprite->physLimits.y2)
3615*4882a593Smuzhiyun             y = pSprite->physLimits.y2 - 1;
3616*4882a593Smuzhiyun         if (pSprite->hotShape)
3617*4882a593Smuzhiyun             ConfineToShape(dev, pSprite->hotShape, &x, &y);
3618*4882a593Smuzhiyun         (*newScreen->SetCursorPosition) (dev, newScreen, x, y, TRUE);
3619*4882a593Smuzhiyun     }
3620*4882a593Smuzhiyun     else if (!PointerConfinedToScreen(dev)) {
3621*4882a593Smuzhiyun         NewCurrentScreen(dev, newScreen, x, y);
3622*4882a593Smuzhiyun     }
3623*4882a593Smuzhiyun     if (*newScreen->CursorWarpedTo)
3624*4882a593Smuzhiyun         (*newScreen->CursorWarpedTo) (dev, newScreen, client,
3625*4882a593Smuzhiyun                                       dest, pSprite, x, y);
3626*4882a593Smuzhiyun     return Success;
3627*4882a593Smuzhiyun }
3628*4882a593Smuzhiyun 
3629*4882a593Smuzhiyun static Bool
BorderSizeNotEmpty(DeviceIntPtr pDev,WindowPtr pWin)3630*4882a593Smuzhiyun BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin)
3631*4882a593Smuzhiyun {
3632*4882a593Smuzhiyun     if (RegionNotEmpty(&pWin->borderSize))
3633*4882a593Smuzhiyun         return TRUE;
3634*4882a593Smuzhiyun 
3635*4882a593Smuzhiyun #ifdef PANORAMIX
3636*4882a593Smuzhiyun     if (!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) {
3637*4882a593Smuzhiyun         int i;
3638*4882a593Smuzhiyun 
3639*4882a593Smuzhiyun         FOR_NSCREENS_FORWARD_SKIP(i) {
3640*4882a593Smuzhiyun             if (RegionNotEmpty
3641*4882a593Smuzhiyun                 (&pDev->spriteInfo->sprite->windows[i]->borderSize))
3642*4882a593Smuzhiyun                 return TRUE;
3643*4882a593Smuzhiyun         }
3644*4882a593Smuzhiyun     }
3645*4882a593Smuzhiyun #endif
3646*4882a593Smuzhiyun     return FALSE;
3647*4882a593Smuzhiyun }
3648*4882a593Smuzhiyun 
3649*4882a593Smuzhiyun /**
3650*4882a593Smuzhiyun  * Activate the given passive grab. If the grab is activated successfully, the
3651*4882a593Smuzhiyun  * event has been delivered to the client.
3652*4882a593Smuzhiyun  *
3653*4882a593Smuzhiyun  * @param device The device of the event to check.
3654*4882a593Smuzhiyun  * @param grab The grab to check.
3655*4882a593Smuzhiyun  * @param event The current device event.
3656*4882a593Smuzhiyun  * @param real_event The original event, in case of touch emulation. The
3657*4882a593Smuzhiyun  * real event is the one stored in the sync queue.
3658*4882a593Smuzhiyun  *
3659*4882a593Smuzhiyun  * @return Whether the grab has been activated.
3660*4882a593Smuzhiyun  */
3661*4882a593Smuzhiyun Bool
ActivatePassiveGrab(DeviceIntPtr device,GrabPtr grab,InternalEvent * event,InternalEvent * real_event)3662*4882a593Smuzhiyun ActivatePassiveGrab(DeviceIntPtr device, GrabPtr grab, InternalEvent *event,
3663*4882a593Smuzhiyun                     InternalEvent *real_event)
3664*4882a593Smuzhiyun {
3665*4882a593Smuzhiyun     SpritePtr pSprite = device->spriteInfo->sprite;
3666*4882a593Smuzhiyun     GrabInfoPtr grabinfo = &device->deviceGrab;
3667*4882a593Smuzhiyun     xEvent *xE = NULL;
3668*4882a593Smuzhiyun     int count;
3669*4882a593Smuzhiyun     int rc;
3670*4882a593Smuzhiyun 
3671*4882a593Smuzhiyun     /* The only consumers of corestate are Xi 1.x and core events, which
3672*4882a593Smuzhiyun      * are guaranteed to come from DeviceEvents. */
3673*4882a593Smuzhiyun     if (grab->grabtype == XI || grab->grabtype == CORE) {
3674*4882a593Smuzhiyun         DeviceIntPtr gdev;
3675*4882a593Smuzhiyun 
3676*4882a593Smuzhiyun         event->device_event.corestate &= 0x1f00;
3677*4882a593Smuzhiyun 
3678*4882a593Smuzhiyun         if (grab->grabtype == CORE)
3679*4882a593Smuzhiyun             gdev = GetMaster(device, KEYBOARD_OR_FLOAT);
3680*4882a593Smuzhiyun         else
3681*4882a593Smuzhiyun             gdev = grab->modifierDevice;
3682*4882a593Smuzhiyun 
3683*4882a593Smuzhiyun         if (gdev && gdev->key && gdev->key->xkbInfo)
3684*4882a593Smuzhiyun             event->device_event.corestate |=
3685*4882a593Smuzhiyun                 gdev->key->xkbInfo->state.grab_mods & (~0x1f00);
3686*4882a593Smuzhiyun     }
3687*4882a593Smuzhiyun 
3688*4882a593Smuzhiyun     if (grab->grabtype == CORE) {
3689*4882a593Smuzhiyun         rc = EventToCore(event, &xE, &count);
3690*4882a593Smuzhiyun         if (rc != Success) {
3691*4882a593Smuzhiyun             BUG_WARN_MSG(rc != BadMatch, "[dix] %s: core conversion failed"
3692*4882a593Smuzhiyun                          "(%d, %d).\n", device->name, event->any.type, rc);
3693*4882a593Smuzhiyun             return FALSE;
3694*4882a593Smuzhiyun         }
3695*4882a593Smuzhiyun     }
3696*4882a593Smuzhiyun     else if (grab->grabtype == XI2) {
3697*4882a593Smuzhiyun         rc = EventToXI2(event, &xE);
3698*4882a593Smuzhiyun         if (rc != Success) {
3699*4882a593Smuzhiyun             if (rc != BadMatch)
3700*4882a593Smuzhiyun                 BUG_WARN_MSG(rc != BadMatch, "[dix] %s: XI2 conversion failed"
3701*4882a593Smuzhiyun                              "(%d, %d).\n", device->name, event->any.type, rc);
3702*4882a593Smuzhiyun             return FALSE;
3703*4882a593Smuzhiyun         }
3704*4882a593Smuzhiyun         count = 1;
3705*4882a593Smuzhiyun     }
3706*4882a593Smuzhiyun     else {
3707*4882a593Smuzhiyun         rc = EventToXI(event, &xE, &count);
3708*4882a593Smuzhiyun         if (rc != Success) {
3709*4882a593Smuzhiyun             if (rc != BadMatch)
3710*4882a593Smuzhiyun                 BUG_WARN_MSG(rc != BadMatch, "[dix] %s: XI conversion failed"
3711*4882a593Smuzhiyun                              "(%d, %d).\n", device->name, event->any.type, rc);
3712*4882a593Smuzhiyun             return FALSE;
3713*4882a593Smuzhiyun         }
3714*4882a593Smuzhiyun     }
3715*4882a593Smuzhiyun 
3716*4882a593Smuzhiyun     (*grabinfo->ActivateGrab) (device, grab,
3717*4882a593Smuzhiyun                                ClientTimeToServerTime(event->any.time), TRUE);
3718*4882a593Smuzhiyun 
3719*4882a593Smuzhiyun     if (xE) {
3720*4882a593Smuzhiyun         FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE);
3721*4882a593Smuzhiyun 
3722*4882a593Smuzhiyun         /* XXX: XACE? */
3723*4882a593Smuzhiyun         TryClientEvents(rClient(grab), device, xE, count,
3724*4882a593Smuzhiyun                         GetEventFilter(device, xE),
3725*4882a593Smuzhiyun                         GetEventFilter(device, xE), grab);
3726*4882a593Smuzhiyun     }
3727*4882a593Smuzhiyun 
3728*4882a593Smuzhiyun     if (grabinfo->sync.state == FROZEN_NO_EVENT)
3729*4882a593Smuzhiyun         grabinfo->sync.state = FROZEN_WITH_EVENT;
3730*4882a593Smuzhiyun     *grabinfo->sync.event = real_event->device_event;
3731*4882a593Smuzhiyun 
3732*4882a593Smuzhiyun     free(xE);
3733*4882a593Smuzhiyun     return TRUE;
3734*4882a593Smuzhiyun }
3735*4882a593Smuzhiyun 
3736*4882a593Smuzhiyun static BOOL
CoreGrabInterferes(DeviceIntPtr device,GrabPtr grab)3737*4882a593Smuzhiyun CoreGrabInterferes(DeviceIntPtr device, GrabPtr grab)
3738*4882a593Smuzhiyun {
3739*4882a593Smuzhiyun     DeviceIntPtr other;
3740*4882a593Smuzhiyun     BOOL interfering = FALSE;
3741*4882a593Smuzhiyun 
3742*4882a593Smuzhiyun     for (other = inputInfo.devices; other; other = other->next) {
3743*4882a593Smuzhiyun         GrabPtr othergrab = other->deviceGrab.grab;
3744*4882a593Smuzhiyun 
3745*4882a593Smuzhiyun         if (othergrab && othergrab->grabtype == CORE &&
3746*4882a593Smuzhiyun             SameClient(grab, rClient(othergrab)) &&
3747*4882a593Smuzhiyun             ((IsPointerDevice(grab->device) &&
3748*4882a593Smuzhiyun               IsPointerDevice(othergrab->device)) ||
3749*4882a593Smuzhiyun              (IsKeyboardDevice(grab->device) &&
3750*4882a593Smuzhiyun               IsKeyboardDevice(othergrab->device)))) {
3751*4882a593Smuzhiyun             interfering = TRUE;
3752*4882a593Smuzhiyun             break;
3753*4882a593Smuzhiyun         }
3754*4882a593Smuzhiyun     }
3755*4882a593Smuzhiyun 
3756*4882a593Smuzhiyun     return interfering;
3757*4882a593Smuzhiyun }
3758*4882a593Smuzhiyun 
3759*4882a593Smuzhiyun enum MatchFlags {
3760*4882a593Smuzhiyun     NO_MATCH = 0x0,
3761*4882a593Smuzhiyun     CORE_MATCH = 0x1,
3762*4882a593Smuzhiyun     XI_MATCH = 0x2,
3763*4882a593Smuzhiyun     XI2_MATCH = 0x4,
3764*4882a593Smuzhiyun };
3765*4882a593Smuzhiyun 
3766*4882a593Smuzhiyun /**
3767*4882a593Smuzhiyun  * Match the grab against the temporary grab on the given input level.
3768*4882a593Smuzhiyun  * Modifies the temporary grab pointer.
3769*4882a593Smuzhiyun  *
3770*4882a593Smuzhiyun  * @param grab The grab to match against
3771*4882a593Smuzhiyun  * @param tmp The temporary grab to use for matching
3772*4882a593Smuzhiyun  * @param level The input level we want to match on
3773*4882a593Smuzhiyun  * @param event_type Wire protocol event type
3774*4882a593Smuzhiyun  *
3775*4882a593Smuzhiyun  * @return The respective matched flag or 0 for no match
3776*4882a593Smuzhiyun  */
3777*4882a593Smuzhiyun static enum MatchFlags
MatchForType(const GrabPtr grab,GrabPtr tmp,enum InputLevel level,int event_type)3778*4882a593Smuzhiyun MatchForType(const GrabPtr grab, GrabPtr tmp, enum InputLevel level,
3779*4882a593Smuzhiyun              int event_type)
3780*4882a593Smuzhiyun {
3781*4882a593Smuzhiyun     enum MatchFlags match;
3782*4882a593Smuzhiyun     BOOL ignore_device = FALSE;
3783*4882a593Smuzhiyun     int grabtype;
3784*4882a593Smuzhiyun     int evtype;
3785*4882a593Smuzhiyun 
3786*4882a593Smuzhiyun     switch (level) {
3787*4882a593Smuzhiyun     case XI2:
3788*4882a593Smuzhiyun         grabtype = XI2;
3789*4882a593Smuzhiyun         evtype = GetXI2Type(event_type);
3790*4882a593Smuzhiyun         BUG_WARN(!evtype);
3791*4882a593Smuzhiyun         match = XI2_MATCH;
3792*4882a593Smuzhiyun         break;
3793*4882a593Smuzhiyun     case XI:
3794*4882a593Smuzhiyun         grabtype = XI;
3795*4882a593Smuzhiyun         evtype = GetXIType(event_type);
3796*4882a593Smuzhiyun         match = XI_MATCH;
3797*4882a593Smuzhiyun         break;
3798*4882a593Smuzhiyun     case CORE:
3799*4882a593Smuzhiyun         grabtype = CORE;
3800*4882a593Smuzhiyun         evtype = GetCoreType(event_type);
3801*4882a593Smuzhiyun         match = CORE_MATCH;
3802*4882a593Smuzhiyun         ignore_device = TRUE;
3803*4882a593Smuzhiyun         break;
3804*4882a593Smuzhiyun     default:
3805*4882a593Smuzhiyun         return NO_MATCH;
3806*4882a593Smuzhiyun     }
3807*4882a593Smuzhiyun 
3808*4882a593Smuzhiyun     tmp->grabtype = grabtype;
3809*4882a593Smuzhiyun     tmp->type = evtype;
3810*4882a593Smuzhiyun 
3811*4882a593Smuzhiyun     if (tmp->type && GrabMatchesSecond(tmp, grab, ignore_device))
3812*4882a593Smuzhiyun         return match;
3813*4882a593Smuzhiyun 
3814*4882a593Smuzhiyun     return NO_MATCH;
3815*4882a593Smuzhiyun }
3816*4882a593Smuzhiyun 
3817*4882a593Smuzhiyun /**
3818*4882a593Smuzhiyun  * Check an individual grab against an event to determine if a passive grab
3819*4882a593Smuzhiyun  * should be activated.
3820*4882a593Smuzhiyun  *
3821*4882a593Smuzhiyun  * @param device The device of the event to check.
3822*4882a593Smuzhiyun  * @param grab The grab to check.
3823*4882a593Smuzhiyun  * @param event The current device event.
3824*4882a593Smuzhiyun  * @param checkCore Check for core grabs too.
3825*4882a593Smuzhiyun  * @param tempGrab A pre-allocated temporary grab record for matching. This
3826*4882a593Smuzhiyun  *        must have the window and device values filled in.
3827*4882a593Smuzhiyun  *
3828*4882a593Smuzhiyun  * @return Whether the grab matches the event.
3829*4882a593Smuzhiyun  */
3830*4882a593Smuzhiyun static Bool
CheckPassiveGrab(DeviceIntPtr device,GrabPtr grab,InternalEvent * event,Bool checkCore,GrabPtr tempGrab)3831*4882a593Smuzhiyun CheckPassiveGrab(DeviceIntPtr device, GrabPtr grab, InternalEvent *event,
3832*4882a593Smuzhiyun                  Bool checkCore, GrabPtr tempGrab)
3833*4882a593Smuzhiyun {
3834*4882a593Smuzhiyun     DeviceIntPtr gdev;
3835*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi = NULL;
3836*4882a593Smuzhiyun     enum MatchFlags match = 0;
3837*4882a593Smuzhiyun     int emulated_type = 0;
3838*4882a593Smuzhiyun 
3839*4882a593Smuzhiyun     gdev = grab->modifierDevice;
3840*4882a593Smuzhiyun     if (grab->grabtype == CORE) {
3841*4882a593Smuzhiyun         gdev = GetMaster(device, KEYBOARD_OR_FLOAT);
3842*4882a593Smuzhiyun     }
3843*4882a593Smuzhiyun     else if (grab->grabtype == XI2) {
3844*4882a593Smuzhiyun         /* if the device is an attached slave device, gdev must be the
3845*4882a593Smuzhiyun          * attached master keyboard. Since the slave may have been
3846*4882a593Smuzhiyun          * reattached after the grab, the modifier device may not be the
3847*4882a593Smuzhiyun          * same. */
3848*4882a593Smuzhiyun         if (!IsMaster(grab->device) && !IsFloating(device))
3849*4882a593Smuzhiyun             gdev = GetMaster(device, MASTER_KEYBOARD);
3850*4882a593Smuzhiyun     }
3851*4882a593Smuzhiyun 
3852*4882a593Smuzhiyun     if (gdev && gdev->key)
3853*4882a593Smuzhiyun         xkbi = gdev->key->xkbInfo;
3854*4882a593Smuzhiyun     tempGrab->modifierDevice = grab->modifierDevice;
3855*4882a593Smuzhiyun     tempGrab->modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0;
3856*4882a593Smuzhiyun 
3857*4882a593Smuzhiyun     /* Check for XI2 and XI grabs first */
3858*4882a593Smuzhiyun     match = MatchForType(grab, tempGrab, XI2, event->any.type);
3859*4882a593Smuzhiyun 
3860*4882a593Smuzhiyun     if (!match && IsTouchEvent(event) &&
3861*4882a593Smuzhiyun         (event->device_event.flags & TOUCH_POINTER_EMULATED)) {
3862*4882a593Smuzhiyun         emulated_type = TouchGetPointerEventType(event);
3863*4882a593Smuzhiyun         match = MatchForType(grab, tempGrab, XI2, emulated_type);
3864*4882a593Smuzhiyun     }
3865*4882a593Smuzhiyun 
3866*4882a593Smuzhiyun     if (!match)
3867*4882a593Smuzhiyun         match = MatchForType(grab, tempGrab, XI, event->any.type);
3868*4882a593Smuzhiyun 
3869*4882a593Smuzhiyun     if (!match && emulated_type)
3870*4882a593Smuzhiyun         match = MatchForType(grab, tempGrab, XI, emulated_type);
3871*4882a593Smuzhiyun 
3872*4882a593Smuzhiyun     if (!match && checkCore) {
3873*4882a593Smuzhiyun         match = MatchForType(grab, tempGrab, CORE, event->any.type);
3874*4882a593Smuzhiyun         if (!match && emulated_type)
3875*4882a593Smuzhiyun             match = MatchForType(grab, tempGrab, CORE, emulated_type);
3876*4882a593Smuzhiyun     }
3877*4882a593Smuzhiyun 
3878*4882a593Smuzhiyun     if (!match || (grab->confineTo &&
3879*4882a593Smuzhiyun                    (!grab->confineTo->realized ||
3880*4882a593Smuzhiyun                     !BorderSizeNotEmpty(device, grab->confineTo))))
3881*4882a593Smuzhiyun         return FALSE;
3882*4882a593Smuzhiyun 
3883*4882a593Smuzhiyun     /* In some cases a passive core grab may exist, but the client
3884*4882a593Smuzhiyun      * already has a core grab on some other device. In this case we
3885*4882a593Smuzhiyun      * must not get the grab, otherwise we may never ungrab the
3886*4882a593Smuzhiyun      * device.
3887*4882a593Smuzhiyun      */
3888*4882a593Smuzhiyun 
3889*4882a593Smuzhiyun     if (grab->grabtype == CORE) {
3890*4882a593Smuzhiyun         /* A passive grab may have been created for a different device
3891*4882a593Smuzhiyun            than it is assigned to at this point in time.
3892*4882a593Smuzhiyun            Update the grab's device and modifier device to reflect the
3893*4882a593Smuzhiyun            current state.
3894*4882a593Smuzhiyun            Since XGrabDeviceButton requires to specify the
3895*4882a593Smuzhiyun            modifierDevice explicitly, we don't override this choice.
3896*4882a593Smuzhiyun          */
3897*4882a593Smuzhiyun         if (grab->type < GenericEvent) {
3898*4882a593Smuzhiyun             grab->device = device;
3899*4882a593Smuzhiyun             grab->modifierDevice = GetMaster(device, MASTER_KEYBOARD);
3900*4882a593Smuzhiyun         }
3901*4882a593Smuzhiyun 
3902*4882a593Smuzhiyun         if (CoreGrabInterferes(device, grab))
3903*4882a593Smuzhiyun             return FALSE;
3904*4882a593Smuzhiyun     }
3905*4882a593Smuzhiyun 
3906*4882a593Smuzhiyun     return TRUE;
3907*4882a593Smuzhiyun }
3908*4882a593Smuzhiyun 
3909*4882a593Smuzhiyun /**
3910*4882a593Smuzhiyun  * "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a
3911*4882a593Smuzhiyun  * passive grab set on the window to be activated.
3912*4882a593Smuzhiyun  * If activate is true and a passive grab is found, it will be activated,
3913*4882a593Smuzhiyun  * and the event will be delivered to the client.
3914*4882a593Smuzhiyun  *
3915*4882a593Smuzhiyun  * @param pWin The window that may be subject to a passive grab.
3916*4882a593Smuzhiyun  * @param device Device that caused the event.
3917*4882a593Smuzhiyun  * @param event The current device event.
3918*4882a593Smuzhiyun  * @param checkCore Check for core grabs too.
3919*4882a593Smuzhiyun  * @param activate If a grab is found, activate it and deliver the event.
3920*4882a593Smuzhiyun  */
3921*4882a593Smuzhiyun 
3922*4882a593Smuzhiyun GrabPtr
CheckPassiveGrabsOnWindow(WindowPtr pWin,DeviceIntPtr device,InternalEvent * event,BOOL checkCore,BOOL activate)3923*4882a593Smuzhiyun CheckPassiveGrabsOnWindow(WindowPtr pWin,
3924*4882a593Smuzhiyun                           DeviceIntPtr device,
3925*4882a593Smuzhiyun                           InternalEvent *event, BOOL checkCore, BOOL activate)
3926*4882a593Smuzhiyun {
3927*4882a593Smuzhiyun     GrabPtr grab = wPassiveGrabs(pWin);
3928*4882a593Smuzhiyun     GrabPtr tempGrab;
3929*4882a593Smuzhiyun 
3930*4882a593Smuzhiyun     if (!grab)
3931*4882a593Smuzhiyun         return NULL;
3932*4882a593Smuzhiyun 
3933*4882a593Smuzhiyun     tempGrab = AllocGrab(NULL);
3934*4882a593Smuzhiyun     if (tempGrab == NULL)
3935*4882a593Smuzhiyun         return NULL;
3936*4882a593Smuzhiyun 
3937*4882a593Smuzhiyun     /* Fill out the grab details, but leave the type for later before
3938*4882a593Smuzhiyun      * comparing */
3939*4882a593Smuzhiyun     switch (event->any.type) {
3940*4882a593Smuzhiyun     case ET_KeyPress:
3941*4882a593Smuzhiyun     case ET_KeyRelease:
3942*4882a593Smuzhiyun         tempGrab->detail.exact = event->device_event.detail.key;
3943*4882a593Smuzhiyun         break;
3944*4882a593Smuzhiyun     case ET_ButtonPress:
3945*4882a593Smuzhiyun     case ET_ButtonRelease:
3946*4882a593Smuzhiyun     case ET_TouchBegin:
3947*4882a593Smuzhiyun     case ET_TouchEnd:
3948*4882a593Smuzhiyun         tempGrab->detail.exact = event->device_event.detail.button;
3949*4882a593Smuzhiyun         break;
3950*4882a593Smuzhiyun     default:
3951*4882a593Smuzhiyun         tempGrab->detail.exact = 0;
3952*4882a593Smuzhiyun         break;
3953*4882a593Smuzhiyun     }
3954*4882a593Smuzhiyun     tempGrab->window = pWin;
3955*4882a593Smuzhiyun     tempGrab->device = device;
3956*4882a593Smuzhiyun     tempGrab->detail.pMask = NULL;
3957*4882a593Smuzhiyun     tempGrab->modifiersDetail.pMask = NULL;
3958*4882a593Smuzhiyun     tempGrab->next = NULL;
3959*4882a593Smuzhiyun 
3960*4882a593Smuzhiyun     for (; grab; grab = grab->next) {
3961*4882a593Smuzhiyun         if (!CheckPassiveGrab(device, grab, event, checkCore, tempGrab))
3962*4882a593Smuzhiyun             continue;
3963*4882a593Smuzhiyun 
3964*4882a593Smuzhiyun         if (activate && !ActivatePassiveGrab(device, grab, event, event))
3965*4882a593Smuzhiyun             continue;
3966*4882a593Smuzhiyun 
3967*4882a593Smuzhiyun         break;
3968*4882a593Smuzhiyun     }
3969*4882a593Smuzhiyun 
3970*4882a593Smuzhiyun     FreeGrab(tempGrab);
3971*4882a593Smuzhiyun     return grab;
3972*4882a593Smuzhiyun }
3973*4882a593Smuzhiyun 
3974*4882a593Smuzhiyun /**
3975*4882a593Smuzhiyun  * CheckDeviceGrabs handles both keyboard and pointer events that may cause
3976*4882a593Smuzhiyun  * a passive grab to be activated.
3977*4882a593Smuzhiyun  *
3978*4882a593Smuzhiyun  * If the event is a keyboard event, the ancestors of the focus window are
3979*4882a593Smuzhiyun  * traced down and tried to see if they have any passive grabs to be
3980*4882a593Smuzhiyun  * activated.  If the focus window itself is reached and it's descendants
3981*4882a593Smuzhiyun  * contain the pointer, the ancestors of the window that the pointer is in
3982*4882a593Smuzhiyun  * are then traced down starting at the focus window, otherwise no grabs are
3983*4882a593Smuzhiyun  * activated.
3984*4882a593Smuzhiyun  * If the event is a pointer event, the ancestors of the window that the
3985*4882a593Smuzhiyun  * pointer is in are traced down starting at the root until CheckPassiveGrabs
3986*4882a593Smuzhiyun  * causes a passive grab to activate or all the windows are
3987*4882a593Smuzhiyun  * tried. PRH
3988*4882a593Smuzhiyun  *
3989*4882a593Smuzhiyun  * If a grab is activated, the event has been sent to the client already!
3990*4882a593Smuzhiyun  *
3991*4882a593Smuzhiyun  * The event we pass in must always be an XI event. From this, we then emulate
3992*4882a593Smuzhiyun  * the core event and then check for grabs.
3993*4882a593Smuzhiyun  *
3994*4882a593Smuzhiyun  * @param device The device that caused the event.
3995*4882a593Smuzhiyun  * @param xE The event to handle (Device{Button|Key}Press).
3996*4882a593Smuzhiyun  * @param count Number of events in list.
3997*4882a593Smuzhiyun  * @return TRUE if a grab has been activated or false otherwise.
3998*4882a593Smuzhiyun */
3999*4882a593Smuzhiyun 
4000*4882a593Smuzhiyun Bool
CheckDeviceGrabs(DeviceIntPtr device,DeviceEvent * event,WindowPtr ancestor)4001*4882a593Smuzhiyun CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor)
4002*4882a593Smuzhiyun {
4003*4882a593Smuzhiyun     int i;
4004*4882a593Smuzhiyun     WindowPtr pWin = NULL;
4005*4882a593Smuzhiyun     FocusClassPtr focus =
4006*4882a593Smuzhiyun         IsPointerEvent((InternalEvent *) event) ? NULL : device->focus;
4007*4882a593Smuzhiyun     BOOL sendCore = (IsMaster(device) && device->coreEvents);
4008*4882a593Smuzhiyun     Bool ret = FALSE;
4009*4882a593Smuzhiyun 
4010*4882a593Smuzhiyun     if (event->type != ET_ButtonPress && event->type != ET_KeyPress)
4011*4882a593Smuzhiyun         return FALSE;
4012*4882a593Smuzhiyun 
4013*4882a593Smuzhiyun     if (event->type == ET_ButtonPress && (device->button->buttonsDown != 1))
4014*4882a593Smuzhiyun         return FALSE;
4015*4882a593Smuzhiyun 
4016*4882a593Smuzhiyun     if (device->deviceGrab.grab)
4017*4882a593Smuzhiyun         return FALSE;
4018*4882a593Smuzhiyun 
4019*4882a593Smuzhiyun     i = 0;
4020*4882a593Smuzhiyun     if (ancestor) {
4021*4882a593Smuzhiyun         while (i < device->spriteInfo->sprite->spriteTraceGood)
4022*4882a593Smuzhiyun             if (device->spriteInfo->sprite->spriteTrace[i++] == ancestor)
4023*4882a593Smuzhiyun                 break;
4024*4882a593Smuzhiyun         if (i == device->spriteInfo->sprite->spriteTraceGood)
4025*4882a593Smuzhiyun             goto out;
4026*4882a593Smuzhiyun     }
4027*4882a593Smuzhiyun 
4028*4882a593Smuzhiyun     if (focus) {
4029*4882a593Smuzhiyun         for (; i < focus->traceGood; i++) {
4030*4882a593Smuzhiyun             pWin = focus->trace[i];
4031*4882a593Smuzhiyun             if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event,
4032*4882a593Smuzhiyun                                           sendCore, TRUE)) {
4033*4882a593Smuzhiyun                 ret = TRUE;
4034*4882a593Smuzhiyun                 goto out;
4035*4882a593Smuzhiyun             }
4036*4882a593Smuzhiyun         }
4037*4882a593Smuzhiyun 
4038*4882a593Smuzhiyun         if ((focus->win == NoneWin) ||
4039*4882a593Smuzhiyun             (i >= device->spriteInfo->sprite->spriteTraceGood) ||
4040*4882a593Smuzhiyun             (pWin && pWin != device->spriteInfo->sprite->spriteTrace[i - 1]))
4041*4882a593Smuzhiyun             goto out;
4042*4882a593Smuzhiyun     }
4043*4882a593Smuzhiyun 
4044*4882a593Smuzhiyun     for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) {
4045*4882a593Smuzhiyun         pWin = device->spriteInfo->sprite->spriteTrace[i];
4046*4882a593Smuzhiyun         if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event,
4047*4882a593Smuzhiyun                                       sendCore, TRUE)) {
4048*4882a593Smuzhiyun             ret = TRUE;
4049*4882a593Smuzhiyun             goto out;
4050*4882a593Smuzhiyun         }
4051*4882a593Smuzhiyun     }
4052*4882a593Smuzhiyun 
4053*4882a593Smuzhiyun  out:
4054*4882a593Smuzhiyun     if (ret == TRUE && event->type == ET_KeyPress)
4055*4882a593Smuzhiyun         device->deviceGrab.activatingKey = event->detail.key;
4056*4882a593Smuzhiyun     return ret;
4057*4882a593Smuzhiyun }
4058*4882a593Smuzhiyun 
4059*4882a593Smuzhiyun /**
4060*4882a593Smuzhiyun  * Called for keyboard events to deliver event to whatever client owns the
4061*4882a593Smuzhiyun  * focus.
4062*4882a593Smuzhiyun  *
4063*4882a593Smuzhiyun  * The event is delivered to the keyboard's focus window, the root window or
4064*4882a593Smuzhiyun  * to the window owning the input focus.
4065*4882a593Smuzhiyun  *
4066*4882a593Smuzhiyun  * @param keybd The keyboard originating the event.
4067*4882a593Smuzhiyun  * @param event The event, not yet in wire format.
4068*4882a593Smuzhiyun  * @param window Window underneath the sprite.
4069*4882a593Smuzhiyun  */
4070*4882a593Smuzhiyun void
DeliverFocusedEvent(DeviceIntPtr keybd,InternalEvent * event,WindowPtr window)4071*4882a593Smuzhiyun DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window)
4072*4882a593Smuzhiyun {
4073*4882a593Smuzhiyun     DeviceIntPtr ptr;
4074*4882a593Smuzhiyun     WindowPtr focus = keybd->focus->win;
4075*4882a593Smuzhiyun     BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents);
4076*4882a593Smuzhiyun     xEvent *core = NULL, *xE = NULL, *xi2 = NULL;
4077*4882a593Smuzhiyun     int count, rc;
4078*4882a593Smuzhiyun     int deliveries = 0;
4079*4882a593Smuzhiyun 
4080*4882a593Smuzhiyun     if (focus == FollowKeyboardWin)
4081*4882a593Smuzhiyun         focus = inputInfo.keyboard->focus->win;
4082*4882a593Smuzhiyun     if (!focus)
4083*4882a593Smuzhiyun         return;
4084*4882a593Smuzhiyun     if (focus == PointerRootWin) {
4085*4882a593Smuzhiyun         DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd);
4086*4882a593Smuzhiyun         return;
4087*4882a593Smuzhiyun     }
4088*4882a593Smuzhiyun     if ((focus == window) || IsParent(focus, window)) {
4089*4882a593Smuzhiyun         if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd))
4090*4882a593Smuzhiyun             return;
4091*4882a593Smuzhiyun     }
4092*4882a593Smuzhiyun 
4093*4882a593Smuzhiyun     /* just deliver it to the focus window */
4094*4882a593Smuzhiyun     ptr = GetMaster(keybd, POINTER_OR_FLOAT);
4095*4882a593Smuzhiyun 
4096*4882a593Smuzhiyun     rc = EventToXI2(event, &xi2);
4097*4882a593Smuzhiyun     if (rc == Success) {
4098*4882a593Smuzhiyun         /* XXX: XACE */
4099*4882a593Smuzhiyun         int filter = GetEventFilter(keybd, xi2);
4100*4882a593Smuzhiyun 
4101*4882a593Smuzhiyun         FixUpEventFromWindow(ptr->spriteInfo->sprite, xi2, focus, None, FALSE);
4102*4882a593Smuzhiyun         deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1,
4103*4882a593Smuzhiyun                                            filter, NullGrab);
4104*4882a593Smuzhiyun         if (deliveries > 0)
4105*4882a593Smuzhiyun             goto unwind;
4106*4882a593Smuzhiyun     }
4107*4882a593Smuzhiyun     else if (rc != BadMatch)
4108*4882a593Smuzhiyun         ErrorF
4109*4882a593Smuzhiyun             ("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n",
4110*4882a593Smuzhiyun              keybd->name, event->any.type, rc);
4111*4882a593Smuzhiyun 
4112*4882a593Smuzhiyun     rc = EventToXI(event, &xE, &count);
4113*4882a593Smuzhiyun     if (rc == Success &&
4114*4882a593Smuzhiyun         XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success) {
4115*4882a593Smuzhiyun         FixUpEventFromWindow(ptr->spriteInfo->sprite, xE, focus, None, FALSE);
4116*4882a593Smuzhiyun         deliveries = DeliverEventsToWindow(keybd, focus, xE, count,
4117*4882a593Smuzhiyun                                            GetEventFilter(keybd, xE), NullGrab);
4118*4882a593Smuzhiyun 
4119*4882a593Smuzhiyun         if (deliveries > 0)
4120*4882a593Smuzhiyun             goto unwind;
4121*4882a593Smuzhiyun     }
4122*4882a593Smuzhiyun     else if (rc != BadMatch)
4123*4882a593Smuzhiyun         ErrorF
4124*4882a593Smuzhiyun             ("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n",
4125*4882a593Smuzhiyun              keybd->name, event->any.type, rc);
4126*4882a593Smuzhiyun 
4127*4882a593Smuzhiyun     if (sendCore) {
4128*4882a593Smuzhiyun         rc = EventToCore(event, &core, &count);
4129*4882a593Smuzhiyun         if (rc == Success) {
4130*4882a593Smuzhiyun             if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, core, count) ==
4131*4882a593Smuzhiyun                 Success) {
4132*4882a593Smuzhiyun                 FixUpEventFromWindow(keybd->spriteInfo->sprite, core, focus,
4133*4882a593Smuzhiyun                                      None, FALSE);
4134*4882a593Smuzhiyun                 deliveries =
4135*4882a593Smuzhiyun                     DeliverEventsToWindow(keybd, focus, core, count,
4136*4882a593Smuzhiyun                                           GetEventFilter(keybd, core),
4137*4882a593Smuzhiyun                                           NullGrab);
4138*4882a593Smuzhiyun             }
4139*4882a593Smuzhiyun         }
4140*4882a593Smuzhiyun         else if (rc != BadMatch)
4141*4882a593Smuzhiyun             ErrorF
4142*4882a593Smuzhiyun                 ("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n",
4143*4882a593Smuzhiyun                  keybd->name, event->any.type, rc);
4144*4882a593Smuzhiyun     }
4145*4882a593Smuzhiyun 
4146*4882a593Smuzhiyun  unwind:
4147*4882a593Smuzhiyun     free(core);
4148*4882a593Smuzhiyun     free(xE);
4149*4882a593Smuzhiyun     free(xi2);
4150*4882a593Smuzhiyun     return;
4151*4882a593Smuzhiyun }
4152*4882a593Smuzhiyun 
4153*4882a593Smuzhiyun int
DeliverOneGrabbedEvent(InternalEvent * event,DeviceIntPtr dev,enum InputLevel level)4154*4882a593Smuzhiyun DeliverOneGrabbedEvent(InternalEvent *event, DeviceIntPtr dev,
4155*4882a593Smuzhiyun                        enum InputLevel level)
4156*4882a593Smuzhiyun {
4157*4882a593Smuzhiyun     SpritePtr pSprite = dev->spriteInfo->sprite;
4158*4882a593Smuzhiyun     int rc;
4159*4882a593Smuzhiyun     xEvent *xE = NULL;
4160*4882a593Smuzhiyun     int count = 0;
4161*4882a593Smuzhiyun     int deliveries = 0;
4162*4882a593Smuzhiyun     Mask mask;
4163*4882a593Smuzhiyun     GrabInfoPtr grabinfo = &dev->deviceGrab;
4164*4882a593Smuzhiyun     GrabPtr grab = grabinfo->grab;
4165*4882a593Smuzhiyun     Mask filter;
4166*4882a593Smuzhiyun 
4167*4882a593Smuzhiyun     if (grab->grabtype != level)
4168*4882a593Smuzhiyun         return 0;
4169*4882a593Smuzhiyun 
4170*4882a593Smuzhiyun     switch (level) {
4171*4882a593Smuzhiyun     case XI2:
4172*4882a593Smuzhiyun         rc = EventToXI2(event, &xE);
4173*4882a593Smuzhiyun         count = 1;
4174*4882a593Smuzhiyun         if (rc == Success) {
4175*4882a593Smuzhiyun             int evtype = xi2_get_type(xE);
4176*4882a593Smuzhiyun 
4177*4882a593Smuzhiyun             mask = GetXI2MaskByte(grab->xi2mask, dev, evtype);
4178*4882a593Smuzhiyun             filter = GetEventFilter(dev, xE);
4179*4882a593Smuzhiyun         }
4180*4882a593Smuzhiyun         break;
4181*4882a593Smuzhiyun     case XI:
4182*4882a593Smuzhiyun         if (grabinfo->fromPassiveGrab && grabinfo->implicitGrab)
4183*4882a593Smuzhiyun             mask = grab->deviceMask;
4184*4882a593Smuzhiyun         else
4185*4882a593Smuzhiyun             mask = grab->eventMask;
4186*4882a593Smuzhiyun         rc = EventToXI(event, &xE, &count);
4187*4882a593Smuzhiyun         if (rc == Success)
4188*4882a593Smuzhiyun             filter = GetEventFilter(dev, xE);
4189*4882a593Smuzhiyun         break;
4190*4882a593Smuzhiyun     case CORE:
4191*4882a593Smuzhiyun         rc = EventToCore(event, &xE, &count);
4192*4882a593Smuzhiyun         mask = grab->eventMask;
4193*4882a593Smuzhiyun         if (rc == Success)
4194*4882a593Smuzhiyun             filter = GetEventFilter(dev, xE);
4195*4882a593Smuzhiyun         break;
4196*4882a593Smuzhiyun     default:
4197*4882a593Smuzhiyun         BUG_WARN_MSG(1, "Invalid input level %d\n", level);
4198*4882a593Smuzhiyun         return 0;
4199*4882a593Smuzhiyun     }
4200*4882a593Smuzhiyun 
4201*4882a593Smuzhiyun     if (rc == Success) {
4202*4882a593Smuzhiyun         FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE);
4203*4882a593Smuzhiyun         if (XaceHook(XACE_SEND_ACCESS, 0, dev,
4204*4882a593Smuzhiyun                      grab->window, xE, count) ||
4205*4882a593Smuzhiyun             XaceHook(XACE_RECEIVE_ACCESS, rClient(grab),
4206*4882a593Smuzhiyun                      grab->window, xE, count))
4207*4882a593Smuzhiyun             deliveries = 1;     /* don't send, but pretend we did */
4208*4882a593Smuzhiyun         else if (level != CORE || !IsInterferingGrab(rClient(grab), dev, xE)) {
4209*4882a593Smuzhiyun             deliveries = TryClientEvents(rClient(grab), dev,
4210*4882a593Smuzhiyun                                          xE, count, mask, filter, grab);
4211*4882a593Smuzhiyun         }
4212*4882a593Smuzhiyun     }
4213*4882a593Smuzhiyun     else
4214*4882a593Smuzhiyun         BUG_WARN_MSG(rc != BadMatch,
4215*4882a593Smuzhiyun                      "%s: conversion to mode %d failed on %d with %d\n",
4216*4882a593Smuzhiyun                      dev->name, level, event->any.type, rc);
4217*4882a593Smuzhiyun 
4218*4882a593Smuzhiyun     free(xE);
4219*4882a593Smuzhiyun     return deliveries;
4220*4882a593Smuzhiyun }
4221*4882a593Smuzhiyun 
4222*4882a593Smuzhiyun /**
4223*4882a593Smuzhiyun  * Deliver an event from a device that is currently grabbed. Uses
4224*4882a593Smuzhiyun  * DeliverDeviceEvents() for further delivery if a ownerEvents is set on the
4225*4882a593Smuzhiyun  * grab. If not, TryClientEvents() is used.
4226*4882a593Smuzhiyun  *
4227*4882a593Smuzhiyun  * @param deactivateGrab True if the device's grab should be deactivated.
4228*4882a593Smuzhiyun  *
4229*4882a593Smuzhiyun  * @return The number of events delivered.
4230*4882a593Smuzhiyun  */
4231*4882a593Smuzhiyun int
DeliverGrabbedEvent(InternalEvent * event,DeviceIntPtr thisDev,Bool deactivateGrab)4232*4882a593Smuzhiyun DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev,
4233*4882a593Smuzhiyun                     Bool deactivateGrab)
4234*4882a593Smuzhiyun {
4235*4882a593Smuzhiyun     GrabPtr grab;
4236*4882a593Smuzhiyun     GrabInfoPtr grabinfo;
4237*4882a593Smuzhiyun     int deliveries = 0;
4238*4882a593Smuzhiyun     DeviceIntPtr dev;
4239*4882a593Smuzhiyun     SpritePtr pSprite = thisDev->spriteInfo->sprite;
4240*4882a593Smuzhiyun     BOOL sendCore = FALSE;
4241*4882a593Smuzhiyun 
4242*4882a593Smuzhiyun     grabinfo = &thisDev->deviceGrab;
4243*4882a593Smuzhiyun     grab = grabinfo->grab;
4244*4882a593Smuzhiyun 
4245*4882a593Smuzhiyun     if (grab->ownerEvents) {
4246*4882a593Smuzhiyun         WindowPtr focus;
4247*4882a593Smuzhiyun 
4248*4882a593Smuzhiyun         /* Hack: Some pointer device have a focus class. So we need to check
4249*4882a593Smuzhiyun          * for the type of event, to see if we really want to deliver it to
4250*4882a593Smuzhiyun          * the focus window. For pointer events, the answer is no.
4251*4882a593Smuzhiyun          */
4252*4882a593Smuzhiyun         if (IsPointerEvent(event))
4253*4882a593Smuzhiyun             focus = PointerRootWin;
4254*4882a593Smuzhiyun         else if (thisDev->focus) {
4255*4882a593Smuzhiyun             focus = thisDev->focus->win;
4256*4882a593Smuzhiyun             if (focus == FollowKeyboardWin)
4257*4882a593Smuzhiyun                 focus = inputInfo.keyboard->focus->win;
4258*4882a593Smuzhiyun         }
4259*4882a593Smuzhiyun         else
4260*4882a593Smuzhiyun             focus = PointerRootWin;
4261*4882a593Smuzhiyun         if (focus == PointerRootWin)
4262*4882a593Smuzhiyun             deliveries = DeliverDeviceEvents(pSprite->win, event, grab,
4263*4882a593Smuzhiyun                                              NullWindow, thisDev);
4264*4882a593Smuzhiyun         else if (focus && (focus == pSprite->win ||
4265*4882a593Smuzhiyun                            IsParent(focus, pSprite->win)))
4266*4882a593Smuzhiyun             deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus,
4267*4882a593Smuzhiyun                                              thisDev);
4268*4882a593Smuzhiyun         else if (focus)
4269*4882a593Smuzhiyun             deliveries = DeliverDeviceEvents(focus, event, grab, focus,
4270*4882a593Smuzhiyun                                              thisDev);
4271*4882a593Smuzhiyun     }
4272*4882a593Smuzhiyun     if (!deliveries) {
4273*4882a593Smuzhiyun         sendCore = (IsMaster(thisDev) && thisDev->coreEvents);
4274*4882a593Smuzhiyun         /* try core event */
4275*4882a593Smuzhiyun         if ((sendCore && grab->grabtype == CORE) || grab->grabtype != CORE)
4276*4882a593Smuzhiyun             deliveries = DeliverOneGrabbedEvent(event, thisDev, grab->grabtype);
4277*4882a593Smuzhiyun 
4278*4882a593Smuzhiyun         if (deliveries && (event->any.type == ET_Motion))
4279*4882a593Smuzhiyun             thisDev->valuator->motionHintWindow = grab->window;
4280*4882a593Smuzhiyun     }
4281*4882a593Smuzhiyun     if (deliveries && !deactivateGrab &&
4282*4882a593Smuzhiyun         (event->any.type == ET_KeyPress ||
4283*4882a593Smuzhiyun          event->any.type == ET_KeyRelease ||
4284*4882a593Smuzhiyun          event->any.type == ET_ButtonPress ||
4285*4882a593Smuzhiyun          event->any.type == ET_ButtonRelease)) {
4286*4882a593Smuzhiyun         switch (grabinfo->sync.state) {
4287*4882a593Smuzhiyun         case FREEZE_BOTH_NEXT_EVENT:
4288*4882a593Smuzhiyun             dev = GetPairedDevice(thisDev);
4289*4882a593Smuzhiyun             if (dev) {
4290*4882a593Smuzhiyun                 FreezeThaw(dev, TRUE);
4291*4882a593Smuzhiyun                 if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) &&
4292*4882a593Smuzhiyun                     (CLIENT_BITS(grab->resource) ==
4293*4882a593Smuzhiyun                      CLIENT_BITS(dev->deviceGrab.grab->resource)))
4294*4882a593Smuzhiyun                     dev->deviceGrab.sync.state = FROZEN_NO_EVENT;
4295*4882a593Smuzhiyun                 else
4296*4882a593Smuzhiyun                     dev->deviceGrab.sync.other = grab;
4297*4882a593Smuzhiyun             }
4298*4882a593Smuzhiyun             /* fall through */
4299*4882a593Smuzhiyun         case FREEZE_NEXT_EVENT:
4300*4882a593Smuzhiyun             grabinfo->sync.state = FROZEN_WITH_EVENT;
4301*4882a593Smuzhiyun             FreezeThaw(thisDev, TRUE);
4302*4882a593Smuzhiyun             *grabinfo->sync.event = event->device_event;
4303*4882a593Smuzhiyun             break;
4304*4882a593Smuzhiyun         }
4305*4882a593Smuzhiyun     }
4306*4882a593Smuzhiyun 
4307*4882a593Smuzhiyun     return deliveries;
4308*4882a593Smuzhiyun }
4309*4882a593Smuzhiyun 
4310*4882a593Smuzhiyun /* This function is used to set the key pressed or key released state -
4311*4882a593Smuzhiyun    this is only used when the pressing of keys does not cause
4312*4882a593Smuzhiyun    the device's processInputProc to be called, as in for example Mouse Keys.
4313*4882a593Smuzhiyun */
4314*4882a593Smuzhiyun void
FixKeyState(DeviceEvent * event,DeviceIntPtr keybd)4315*4882a593Smuzhiyun FixKeyState(DeviceEvent *event, DeviceIntPtr keybd)
4316*4882a593Smuzhiyun {
4317*4882a593Smuzhiyun     int key = event->detail.key;
4318*4882a593Smuzhiyun 
4319*4882a593Smuzhiyun     if (event->type == ET_KeyPress) {
4320*4882a593Smuzhiyun         DebugF("FixKeyState: Key %d %s\n", key,
4321*4882a593Smuzhiyun                ((event->type == ET_KeyPress) ? "down" : "up"));
4322*4882a593Smuzhiyun     }
4323*4882a593Smuzhiyun 
4324*4882a593Smuzhiyun     if (event->type == ET_KeyPress)
4325*4882a593Smuzhiyun         set_key_down(keybd, key, KEY_PROCESSED);
4326*4882a593Smuzhiyun     else if (event->type == ET_KeyRelease)
4327*4882a593Smuzhiyun         set_key_up(keybd, key, KEY_PROCESSED);
4328*4882a593Smuzhiyun     else
4329*4882a593Smuzhiyun         FatalError("Impossible keyboard event");
4330*4882a593Smuzhiyun }
4331*4882a593Smuzhiyun 
4332*4882a593Smuzhiyun #define AtMostOneClient \
4333*4882a593Smuzhiyun 	(SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask)
4334*4882a593Smuzhiyun #define ManagerMask \
4335*4882a593Smuzhiyun 	(SubstructureRedirectMask | ResizeRedirectMask)
4336*4882a593Smuzhiyun 
4337*4882a593Smuzhiyun /**
4338*4882a593Smuzhiyun  * Recalculate which events may be deliverable for the given window.
4339*4882a593Smuzhiyun  * Recalculated mask is used for quicker determination which events may be
4340*4882a593Smuzhiyun  * delivered to a window.
4341*4882a593Smuzhiyun  *
4342*4882a593Smuzhiyun  * The otherEventMasks on a WindowOptional is the combination of all event
4343*4882a593Smuzhiyun  * masks set by all clients on the window.
4344*4882a593Smuzhiyun  * deliverableEventMask is the combination of the eventMask and the
4345*4882a593Smuzhiyun  * otherEventMask plus the events that may be propagated to the parent.
4346*4882a593Smuzhiyun  *
4347*4882a593Smuzhiyun  * Traverses to siblings and parents of the window.
4348*4882a593Smuzhiyun  */
4349*4882a593Smuzhiyun void
RecalculateDeliverableEvents(WindowPtr pWin)4350*4882a593Smuzhiyun RecalculateDeliverableEvents(WindowPtr pWin)
4351*4882a593Smuzhiyun {
4352*4882a593Smuzhiyun     OtherClients *others;
4353*4882a593Smuzhiyun     WindowPtr pChild;
4354*4882a593Smuzhiyun 
4355*4882a593Smuzhiyun     pChild = pWin;
4356*4882a593Smuzhiyun     while (1) {
4357*4882a593Smuzhiyun         if (pChild->optional) {
4358*4882a593Smuzhiyun             pChild->optional->otherEventMasks = 0;
4359*4882a593Smuzhiyun             for (others = wOtherClients(pChild); others; others = others->next) {
4360*4882a593Smuzhiyun                 pChild->optional->otherEventMasks |= others->mask;
4361*4882a593Smuzhiyun             }
4362*4882a593Smuzhiyun         }
4363*4882a593Smuzhiyun         pChild->deliverableEvents = pChild->eventMask |
4364*4882a593Smuzhiyun             wOtherEventMasks(pChild);
4365*4882a593Smuzhiyun         if (pChild->parent)
4366*4882a593Smuzhiyun             pChild->deliverableEvents |=
4367*4882a593Smuzhiyun                 (pChild->parent->deliverableEvents &
4368*4882a593Smuzhiyun                  ~wDontPropagateMask(pChild) & PropagateMask);
4369*4882a593Smuzhiyun         if (pChild->firstChild) {
4370*4882a593Smuzhiyun             pChild = pChild->firstChild;
4371*4882a593Smuzhiyun             continue;
4372*4882a593Smuzhiyun         }
4373*4882a593Smuzhiyun         while (!pChild->nextSib && (pChild != pWin))
4374*4882a593Smuzhiyun             pChild = pChild->parent;
4375*4882a593Smuzhiyun         if (pChild == pWin)
4376*4882a593Smuzhiyun             break;
4377*4882a593Smuzhiyun         pChild = pChild->nextSib;
4378*4882a593Smuzhiyun     }
4379*4882a593Smuzhiyun }
4380*4882a593Smuzhiyun 
4381*4882a593Smuzhiyun /**
4382*4882a593Smuzhiyun  *
4383*4882a593Smuzhiyun  *  \param value must conform to DeleteType
4384*4882a593Smuzhiyun  */
4385*4882a593Smuzhiyun int
OtherClientGone(void * value,XID id)4386*4882a593Smuzhiyun OtherClientGone(void *value, XID id)
4387*4882a593Smuzhiyun {
4388*4882a593Smuzhiyun     OtherClientsPtr other, prev;
4389*4882a593Smuzhiyun     WindowPtr pWin = (WindowPtr) value;
4390*4882a593Smuzhiyun 
4391*4882a593Smuzhiyun     prev = 0;
4392*4882a593Smuzhiyun     for (other = wOtherClients(pWin); other; other = other->next) {
4393*4882a593Smuzhiyun         if (other->resource == id) {
4394*4882a593Smuzhiyun             if (prev)
4395*4882a593Smuzhiyun                 prev->next = other->next;
4396*4882a593Smuzhiyun             else {
4397*4882a593Smuzhiyun                 if (!(pWin->optional->otherClients = other->next))
4398*4882a593Smuzhiyun                     CheckWindowOptionalNeed(pWin);
4399*4882a593Smuzhiyun             }
4400*4882a593Smuzhiyun             free(other);
4401*4882a593Smuzhiyun             RecalculateDeliverableEvents(pWin);
4402*4882a593Smuzhiyun             return Success;
4403*4882a593Smuzhiyun         }
4404*4882a593Smuzhiyun         prev = other;
4405*4882a593Smuzhiyun     }
4406*4882a593Smuzhiyun     FatalError("client not on event list");
4407*4882a593Smuzhiyun }
4408*4882a593Smuzhiyun 
4409*4882a593Smuzhiyun int
EventSelectForWindow(WindowPtr pWin,ClientPtr client,Mask mask)4410*4882a593Smuzhiyun EventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask)
4411*4882a593Smuzhiyun {
4412*4882a593Smuzhiyun     Mask check;
4413*4882a593Smuzhiyun     OtherClients *others;
4414*4882a593Smuzhiyun     DeviceIntPtr dev;
4415*4882a593Smuzhiyun     int rc;
4416*4882a593Smuzhiyun 
4417*4882a593Smuzhiyun     if (mask & ~AllEventMasks) {
4418*4882a593Smuzhiyun         client->errorValue = mask;
4419*4882a593Smuzhiyun         return BadValue;
4420*4882a593Smuzhiyun     }
4421*4882a593Smuzhiyun     check = (mask & ManagerMask);
4422*4882a593Smuzhiyun     if (check) {
4423*4882a593Smuzhiyun         rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id,
4424*4882a593Smuzhiyun                       RT_WINDOW, pWin, RT_NONE, NULL, DixManageAccess);
4425*4882a593Smuzhiyun         if (rc != Success)
4426*4882a593Smuzhiyun             return rc;
4427*4882a593Smuzhiyun     }
4428*4882a593Smuzhiyun     check = (mask & AtMostOneClient);
4429*4882a593Smuzhiyun     if (check & (pWin->eventMask | wOtherEventMasks(pWin))) {
4430*4882a593Smuzhiyun         /* It is illegal for two different clients to select on any of the
4431*4882a593Smuzhiyun            events for AtMostOneClient. However, it is OK, for some client to
4432*4882a593Smuzhiyun            continue selecting on one of those events.  */
4433*4882a593Smuzhiyun         if ((wClient(pWin) != client) && (check & pWin->eventMask))
4434*4882a593Smuzhiyun             return BadAccess;
4435*4882a593Smuzhiyun         for (others = wOtherClients(pWin); others; others = others->next) {
4436*4882a593Smuzhiyun             if (!SameClient(others, client) && (check & others->mask))
4437*4882a593Smuzhiyun                 return BadAccess;
4438*4882a593Smuzhiyun         }
4439*4882a593Smuzhiyun     }
4440*4882a593Smuzhiyun     if (wClient(pWin) == client) {
4441*4882a593Smuzhiyun         check = pWin->eventMask;
4442*4882a593Smuzhiyun         pWin->eventMask = mask;
4443*4882a593Smuzhiyun     }
4444*4882a593Smuzhiyun     else {
4445*4882a593Smuzhiyun         for (others = wOtherClients(pWin); others; others = others->next) {
4446*4882a593Smuzhiyun             if (SameClient(others, client)) {
4447*4882a593Smuzhiyun                 check = others->mask;
4448*4882a593Smuzhiyun                 if (mask == 0) {
4449*4882a593Smuzhiyun                     FreeResource(others->resource, RT_NONE);
4450*4882a593Smuzhiyun                     return Success;
4451*4882a593Smuzhiyun                 }
4452*4882a593Smuzhiyun                 else
4453*4882a593Smuzhiyun                     others->mask = mask;
4454*4882a593Smuzhiyun                 goto maskSet;
4455*4882a593Smuzhiyun             }
4456*4882a593Smuzhiyun         }
4457*4882a593Smuzhiyun         check = 0;
4458*4882a593Smuzhiyun         if (!pWin->optional && !MakeWindowOptional(pWin))
4459*4882a593Smuzhiyun             return BadAlloc;
4460*4882a593Smuzhiyun         others = malloc(sizeof(OtherClients));
4461*4882a593Smuzhiyun         if (!others)
4462*4882a593Smuzhiyun             return BadAlloc;
4463*4882a593Smuzhiyun         others->mask = mask;
4464*4882a593Smuzhiyun         others->resource = FakeClientID(client->index);
4465*4882a593Smuzhiyun         others->next = pWin->optional->otherClients;
4466*4882a593Smuzhiyun         pWin->optional->otherClients = others;
4467*4882a593Smuzhiyun         if (!AddResource(others->resource, RT_OTHERCLIENT, (void *) pWin))
4468*4882a593Smuzhiyun             return BadAlloc;
4469*4882a593Smuzhiyun     }
4470*4882a593Smuzhiyun  maskSet:
4471*4882a593Smuzhiyun     if ((mask & PointerMotionHintMask) && !(check & PointerMotionHintMask)) {
4472*4882a593Smuzhiyun         for (dev = inputInfo.devices; dev; dev = dev->next) {
4473*4882a593Smuzhiyun             if (dev->valuator && dev->valuator->motionHintWindow == pWin)
4474*4882a593Smuzhiyun                 dev->valuator->motionHintWindow = NullWindow;
4475*4882a593Smuzhiyun         }
4476*4882a593Smuzhiyun     }
4477*4882a593Smuzhiyun     RecalculateDeliverableEvents(pWin);
4478*4882a593Smuzhiyun     return Success;
4479*4882a593Smuzhiyun }
4480*4882a593Smuzhiyun 
4481*4882a593Smuzhiyun int
EventSuppressForWindow(WindowPtr pWin,ClientPtr client,Mask mask,Bool * checkOptional)4482*4882a593Smuzhiyun EventSuppressForWindow(WindowPtr pWin, ClientPtr client,
4483*4882a593Smuzhiyun                        Mask mask, Bool *checkOptional)
4484*4882a593Smuzhiyun {
4485*4882a593Smuzhiyun     int i, freed;
4486*4882a593Smuzhiyun 
4487*4882a593Smuzhiyun     if (mask & ~PropagateMask) {
4488*4882a593Smuzhiyun         client->errorValue = mask;
4489*4882a593Smuzhiyun         return BadValue;
4490*4882a593Smuzhiyun     }
4491*4882a593Smuzhiyun     if (pWin->dontPropagate)
4492*4882a593Smuzhiyun         DontPropagateRefCnts[pWin->dontPropagate]--;
4493*4882a593Smuzhiyun     if (!mask)
4494*4882a593Smuzhiyun         i = 0;
4495*4882a593Smuzhiyun     else {
4496*4882a593Smuzhiyun         for (i = DNPMCOUNT, freed = 0; --i > 0;) {
4497*4882a593Smuzhiyun             if (!DontPropagateRefCnts[i])
4498*4882a593Smuzhiyun                 freed = i;
4499*4882a593Smuzhiyun             else if (mask == DontPropagateMasks[i])
4500*4882a593Smuzhiyun                 break;
4501*4882a593Smuzhiyun         }
4502*4882a593Smuzhiyun         if (!i && freed) {
4503*4882a593Smuzhiyun             i = freed;
4504*4882a593Smuzhiyun             DontPropagateMasks[i] = mask;
4505*4882a593Smuzhiyun         }
4506*4882a593Smuzhiyun     }
4507*4882a593Smuzhiyun     if (i || !mask) {
4508*4882a593Smuzhiyun         pWin->dontPropagate = i;
4509*4882a593Smuzhiyun         if (i)
4510*4882a593Smuzhiyun             DontPropagateRefCnts[i]++;
4511*4882a593Smuzhiyun         if (pWin->optional) {
4512*4882a593Smuzhiyun             pWin->optional->dontPropagateMask = mask;
4513*4882a593Smuzhiyun             *checkOptional = TRUE;
4514*4882a593Smuzhiyun         }
4515*4882a593Smuzhiyun     }
4516*4882a593Smuzhiyun     else {
4517*4882a593Smuzhiyun         if (!pWin->optional && !MakeWindowOptional(pWin)) {
4518*4882a593Smuzhiyun             if (pWin->dontPropagate)
4519*4882a593Smuzhiyun                 DontPropagateRefCnts[pWin->dontPropagate]++;
4520*4882a593Smuzhiyun             return BadAlloc;
4521*4882a593Smuzhiyun         }
4522*4882a593Smuzhiyun         pWin->dontPropagate = 0;
4523*4882a593Smuzhiyun         pWin->optional->dontPropagateMask = mask;
4524*4882a593Smuzhiyun     }
4525*4882a593Smuzhiyun     RecalculateDeliverableEvents(pWin);
4526*4882a593Smuzhiyun     return Success;
4527*4882a593Smuzhiyun }
4528*4882a593Smuzhiyun 
4529*4882a593Smuzhiyun /**
4530*4882a593Smuzhiyun  * Assembles an EnterNotify or LeaveNotify and sends it event to the client.
4531*4882a593Smuzhiyun  * Uses the paired keyboard to get some additional information.
4532*4882a593Smuzhiyun  */
4533*4882a593Smuzhiyun void
CoreEnterLeaveEvent(DeviceIntPtr mouse,int type,int mode,int detail,WindowPtr pWin,Window child)4534*4882a593Smuzhiyun CoreEnterLeaveEvent(DeviceIntPtr mouse,
4535*4882a593Smuzhiyun                     int type,
4536*4882a593Smuzhiyun                     int mode, int detail, WindowPtr pWin, Window child)
4537*4882a593Smuzhiyun {
4538*4882a593Smuzhiyun     xEvent event = {
4539*4882a593Smuzhiyun         .u.u.type = type,
4540*4882a593Smuzhiyun         .u.u.detail = detail
4541*4882a593Smuzhiyun     };
4542*4882a593Smuzhiyun     WindowPtr focus;
4543*4882a593Smuzhiyun     DeviceIntPtr keybd;
4544*4882a593Smuzhiyun     GrabPtr grab = mouse->deviceGrab.grab;
4545*4882a593Smuzhiyun     Mask mask;
4546*4882a593Smuzhiyun 
4547*4882a593Smuzhiyun     keybd = GetMaster(mouse, KEYBOARD_OR_FLOAT);
4548*4882a593Smuzhiyun 
4549*4882a593Smuzhiyun     if ((pWin == mouse->valuator->motionHintWindow) &&
4550*4882a593Smuzhiyun         (detail != NotifyInferior))
4551*4882a593Smuzhiyun         mouse->valuator->motionHintWindow = NullWindow;
4552*4882a593Smuzhiyun     if (grab) {
4553*4882a593Smuzhiyun         mask = (pWin == grab->window) ? grab->eventMask : 0;
4554*4882a593Smuzhiyun         if (grab->ownerEvents)
4555*4882a593Smuzhiyun             mask |= EventMaskForClient(pWin, rClient(grab));
4556*4882a593Smuzhiyun     }
4557*4882a593Smuzhiyun     else {
4558*4882a593Smuzhiyun         mask = pWin->eventMask | wOtherEventMasks(pWin);
4559*4882a593Smuzhiyun     }
4560*4882a593Smuzhiyun 
4561*4882a593Smuzhiyun     event.u.enterLeave.time = currentTime.milliseconds;
4562*4882a593Smuzhiyun     event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x;
4563*4882a593Smuzhiyun     event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y;
4564*4882a593Smuzhiyun     /* Counts on the same initial structure of crossing & button events! */
4565*4882a593Smuzhiyun     FixUpEventFromWindow(mouse->spriteInfo->sprite, &event, pWin, None, FALSE);
4566*4882a593Smuzhiyun     /* Enter/Leave events always set child */
4567*4882a593Smuzhiyun     event.u.enterLeave.child = child;
4568*4882a593Smuzhiyun     event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ?
4569*4882a593Smuzhiyun         ELFlagSameScreen : 0;
4570*4882a593Smuzhiyun     event.u.enterLeave.state =
4571*4882a593Smuzhiyun         mouse->button ? (mouse->button->state & 0x1f00) : 0;
4572*4882a593Smuzhiyun     if (keybd)
4573*4882a593Smuzhiyun         event.u.enterLeave.state |=
4574*4882a593Smuzhiyun             XkbGrabStateFromRec(&keybd->key->xkbInfo->state);
4575*4882a593Smuzhiyun     event.u.enterLeave.mode = mode;
4576*4882a593Smuzhiyun     focus = (keybd) ? keybd->focus->win : None;
4577*4882a593Smuzhiyun     if ((focus != NoneWin) &&
4578*4882a593Smuzhiyun         ((pWin == focus) || (focus == PointerRootWin) || IsParent(focus, pWin)))
4579*4882a593Smuzhiyun         event.u.enterLeave.flags |= ELFlagFocus;
4580*4882a593Smuzhiyun 
4581*4882a593Smuzhiyun     if ((mask & GetEventFilter(mouse, &event))) {
4582*4882a593Smuzhiyun         if (grab)
4583*4882a593Smuzhiyun             TryClientEvents(rClient(grab), mouse, &event, 1, mask,
4584*4882a593Smuzhiyun                             GetEventFilter(mouse, &event), grab);
4585*4882a593Smuzhiyun         else
4586*4882a593Smuzhiyun             DeliverEventsToWindow(mouse, pWin, &event, 1,
4587*4882a593Smuzhiyun                                   GetEventFilter(mouse, &event), NullGrab);
4588*4882a593Smuzhiyun     }
4589*4882a593Smuzhiyun 
4590*4882a593Smuzhiyun     if ((type == EnterNotify) && (mask & KeymapStateMask)) {
4591*4882a593Smuzhiyun         xKeymapEvent ke = {
4592*4882a593Smuzhiyun             .type = KeymapNotify
4593*4882a593Smuzhiyun         };
4594*4882a593Smuzhiyun         ClientPtr client = grab ? rClient(grab) : wClient(pWin);
4595*4882a593Smuzhiyun         int rc;
4596*4882a593Smuzhiyun 
4597*4882a593Smuzhiyun         rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess);
4598*4882a593Smuzhiyun         if (rc == Success)
4599*4882a593Smuzhiyun             memcpy((char *) &ke.map[0], (char *) &keybd->key->down[1], 31);
4600*4882a593Smuzhiyun 
4601*4882a593Smuzhiyun         if (grab)
4602*4882a593Smuzhiyun             TryClientEvents(rClient(grab), keybd, (xEvent *) &ke, 1,
4603*4882a593Smuzhiyun                             mask, KeymapStateMask, grab);
4604*4882a593Smuzhiyun         else
4605*4882a593Smuzhiyun             DeliverEventsToWindow(mouse, pWin, (xEvent *) &ke, 1,
4606*4882a593Smuzhiyun                                   KeymapStateMask, NullGrab);
4607*4882a593Smuzhiyun     }
4608*4882a593Smuzhiyun }
4609*4882a593Smuzhiyun 
4610*4882a593Smuzhiyun void
DeviceEnterLeaveEvent(DeviceIntPtr mouse,int sourceid,int type,int mode,int detail,WindowPtr pWin,Window child)4611*4882a593Smuzhiyun DeviceEnterLeaveEvent(DeviceIntPtr mouse,
4612*4882a593Smuzhiyun                       int sourceid,
4613*4882a593Smuzhiyun                       int type,
4614*4882a593Smuzhiyun                       int mode, int detail, WindowPtr pWin, Window child)
4615*4882a593Smuzhiyun {
4616*4882a593Smuzhiyun     GrabPtr grab = mouse->deviceGrab.grab;
4617*4882a593Smuzhiyun     xXIEnterEvent *event;
4618*4882a593Smuzhiyun     WindowPtr focus;
4619*4882a593Smuzhiyun     int filter;
4620*4882a593Smuzhiyun     int btlen, len, i;
4621*4882a593Smuzhiyun     DeviceIntPtr kbd;
4622*4882a593Smuzhiyun 
4623*4882a593Smuzhiyun     if ((mode == XINotifyPassiveGrab && type == XI_Leave) ||
4624*4882a593Smuzhiyun         (mode == XINotifyPassiveUngrab && type == XI_Enter))
4625*4882a593Smuzhiyun         return;
4626*4882a593Smuzhiyun 
4627*4882a593Smuzhiyun     btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0;
4628*4882a593Smuzhiyun     btlen = bytes_to_int32(btlen);
4629*4882a593Smuzhiyun     len = sizeof(xXIEnterEvent) + btlen * 4;
4630*4882a593Smuzhiyun 
4631*4882a593Smuzhiyun     event = calloc(1, len);
4632*4882a593Smuzhiyun     event->type = GenericEvent;
4633*4882a593Smuzhiyun     event->extension = IReqCode;
4634*4882a593Smuzhiyun     event->evtype = type;
4635*4882a593Smuzhiyun     event->length = (len - sizeof(xEvent)) / 4;
4636*4882a593Smuzhiyun     event->buttons_len = btlen;
4637*4882a593Smuzhiyun     event->detail = detail;
4638*4882a593Smuzhiyun     event->time = currentTime.milliseconds;
4639*4882a593Smuzhiyun     event->deviceid = mouse->id;
4640*4882a593Smuzhiyun     event->sourceid = sourceid;
4641*4882a593Smuzhiyun     event->mode = mode;
4642*4882a593Smuzhiyun     event->root_x = double_to_fp1616(mouse->spriteInfo->sprite->hot.x);
4643*4882a593Smuzhiyun     event->root_y = double_to_fp1616(mouse->spriteInfo->sprite->hot.y);
4644*4882a593Smuzhiyun 
4645*4882a593Smuzhiyun     for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++)
4646*4882a593Smuzhiyun         if (BitIsOn(mouse->button->down, i))
4647*4882a593Smuzhiyun             SetBit(&event[1], i);
4648*4882a593Smuzhiyun 
4649*4882a593Smuzhiyun     kbd = GetMaster(mouse, MASTER_KEYBOARD);
4650*4882a593Smuzhiyun     if (kbd && kbd->key) {
4651*4882a593Smuzhiyun         event->mods.base_mods = kbd->key->xkbInfo->state.base_mods;
4652*4882a593Smuzhiyun         event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods;
4653*4882a593Smuzhiyun         event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods;
4654*4882a593Smuzhiyun 
4655*4882a593Smuzhiyun         event->group.base_group = kbd->key->xkbInfo->state.base_group;
4656*4882a593Smuzhiyun         event->group.latched_group = kbd->key->xkbInfo->state.latched_group;
4657*4882a593Smuzhiyun         event->group.locked_group = kbd->key->xkbInfo->state.locked_group;
4658*4882a593Smuzhiyun     }
4659*4882a593Smuzhiyun 
4660*4882a593Smuzhiyun     focus = (kbd) ? kbd->focus->win : None;
4661*4882a593Smuzhiyun     if ((focus != NoneWin) &&
4662*4882a593Smuzhiyun         ((pWin == focus) || (focus == PointerRootWin) || IsParent(focus, pWin)))
4663*4882a593Smuzhiyun         event->focus = TRUE;
4664*4882a593Smuzhiyun 
4665*4882a593Smuzhiyun     FixUpEventFromWindow(mouse->spriteInfo->sprite, (xEvent *) event, pWin,
4666*4882a593Smuzhiyun                          None, FALSE);
4667*4882a593Smuzhiyun 
4668*4882a593Smuzhiyun     filter = GetEventFilter(mouse, (xEvent *) event);
4669*4882a593Smuzhiyun 
4670*4882a593Smuzhiyun     if (grab && grab->grabtype == XI2) {
4671*4882a593Smuzhiyun         Mask mask;
4672*4882a593Smuzhiyun 
4673*4882a593Smuzhiyun         mask = xi2mask_isset(grab->xi2mask, mouse, type);
4674*4882a593Smuzhiyun         TryClientEvents(rClient(grab), mouse, (xEvent *) event, 1, mask, 1,
4675*4882a593Smuzhiyun                         grab);
4676*4882a593Smuzhiyun     }
4677*4882a593Smuzhiyun     else {
4678*4882a593Smuzhiyun         if (!WindowXI2MaskIsset(mouse, pWin, (xEvent *) event))
4679*4882a593Smuzhiyun             goto out;
4680*4882a593Smuzhiyun         DeliverEventsToWindow(mouse, pWin, (xEvent *) event, 1, filter,
4681*4882a593Smuzhiyun                               NullGrab);
4682*4882a593Smuzhiyun     }
4683*4882a593Smuzhiyun 
4684*4882a593Smuzhiyun  out:
4685*4882a593Smuzhiyun     free(event);
4686*4882a593Smuzhiyun }
4687*4882a593Smuzhiyun 
4688*4882a593Smuzhiyun void
CoreFocusEvent(DeviceIntPtr dev,int type,int mode,int detail,WindowPtr pWin)4689*4882a593Smuzhiyun CoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin)
4690*4882a593Smuzhiyun {
4691*4882a593Smuzhiyun     xEvent event = {
4692*4882a593Smuzhiyun         .u.u.type = type,
4693*4882a593Smuzhiyun         .u.u.detail = detail
4694*4882a593Smuzhiyun     };
4695*4882a593Smuzhiyun     event.u.focus.mode = mode;
4696*4882a593Smuzhiyun     event.u.focus.window = pWin->drawable.id;
4697*4882a593Smuzhiyun 
4698*4882a593Smuzhiyun     DeliverEventsToWindow(dev, pWin, &event, 1,
4699*4882a593Smuzhiyun                           GetEventFilter(dev, &event), NullGrab);
4700*4882a593Smuzhiyun     if ((type == FocusIn) &&
4701*4882a593Smuzhiyun         ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) {
4702*4882a593Smuzhiyun         xKeymapEvent ke = {
4703*4882a593Smuzhiyun             .type = KeymapNotify
4704*4882a593Smuzhiyun         };
4705*4882a593Smuzhiyun         ClientPtr client = wClient(pWin);
4706*4882a593Smuzhiyun         int rc;
4707*4882a593Smuzhiyun 
4708*4882a593Smuzhiyun         rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess);
4709*4882a593Smuzhiyun         if (rc == Success)
4710*4882a593Smuzhiyun             memcpy((char *) &ke.map[0], (char *) &dev->key->down[1], 31);
4711*4882a593Smuzhiyun 
4712*4882a593Smuzhiyun         DeliverEventsToWindow(dev, pWin, (xEvent *) &ke, 1,
4713*4882a593Smuzhiyun                               KeymapStateMask, NullGrab);
4714*4882a593Smuzhiyun     }
4715*4882a593Smuzhiyun }
4716*4882a593Smuzhiyun 
4717*4882a593Smuzhiyun /**
4718*4882a593Smuzhiyun  * Set the input focus to the given window. Subsequent keyboard events will be
4719*4882a593Smuzhiyun  * delivered to the given window.
4720*4882a593Smuzhiyun  *
4721*4882a593Smuzhiyun  * Usually called from ProcSetInputFocus as result of a client request. If so,
4722*4882a593Smuzhiyun  * the device is the inputInfo.keyboard.
4723*4882a593Smuzhiyun  * If called from ProcXSetInputFocus as result of a client xinput request, the
4724*4882a593Smuzhiyun  * device is set to the device specified by the client.
4725*4882a593Smuzhiyun  *
4726*4882a593Smuzhiyun  * @param client Client that requested input focus change.
4727*4882a593Smuzhiyun  * @param dev Focus device.
4728*4882a593Smuzhiyun  * @param focusID The window to obtain the focus. Can be PointerRoot or None.
4729*4882a593Smuzhiyun  * @param revertTo Specifies where the focus reverts to when window becomes
4730*4882a593Smuzhiyun  * unviewable.
4731*4882a593Smuzhiyun  * @param ctime Specifies the time.
4732*4882a593Smuzhiyun  * @param followOK True if pointer is allowed to follow the keyboard.
4733*4882a593Smuzhiyun  */
4734*4882a593Smuzhiyun int
SetInputFocus(ClientPtr client,DeviceIntPtr dev,Window focusID,CARD8 revertTo,Time ctime,Bool followOK)4735*4882a593Smuzhiyun SetInputFocus(ClientPtr client,
4736*4882a593Smuzhiyun               DeviceIntPtr dev,
4737*4882a593Smuzhiyun               Window focusID, CARD8 revertTo, Time ctime, Bool followOK)
4738*4882a593Smuzhiyun {
4739*4882a593Smuzhiyun     FocusClassPtr focus;
4740*4882a593Smuzhiyun     WindowPtr focusWin;
4741*4882a593Smuzhiyun     int mode, rc;
4742*4882a593Smuzhiyun     TimeStamp time;
4743*4882a593Smuzhiyun     DeviceIntPtr keybd;         /* used for FollowKeyboard or FollowKeyboardWin */
4744*4882a593Smuzhiyun 
4745*4882a593Smuzhiyun     UpdateCurrentTime();
4746*4882a593Smuzhiyun     if ((revertTo != RevertToParent) &&
4747*4882a593Smuzhiyun         (revertTo != RevertToPointerRoot) &&
4748*4882a593Smuzhiyun         (revertTo != RevertToNone) &&
4749*4882a593Smuzhiyun         ((revertTo != RevertToFollowKeyboard) || !followOK)) {
4750*4882a593Smuzhiyun         client->errorValue = revertTo;
4751*4882a593Smuzhiyun         return BadValue;
4752*4882a593Smuzhiyun     }
4753*4882a593Smuzhiyun     time = ClientTimeToServerTime(ctime);
4754*4882a593Smuzhiyun 
4755*4882a593Smuzhiyun     keybd = GetMaster(dev, KEYBOARD_OR_FLOAT);
4756*4882a593Smuzhiyun 
4757*4882a593Smuzhiyun     if ((focusID == None) || (focusID == PointerRoot))
4758*4882a593Smuzhiyun         focusWin = (WindowPtr) (long) focusID;
4759*4882a593Smuzhiyun     else if ((focusID == FollowKeyboard) && followOK) {
4760*4882a593Smuzhiyun         focusWin = keybd->focus->win;
4761*4882a593Smuzhiyun     }
4762*4882a593Smuzhiyun     else {
4763*4882a593Smuzhiyun         rc = dixLookupWindow(&focusWin, focusID, client, DixSetAttrAccess);
4764*4882a593Smuzhiyun         if (rc != Success)
4765*4882a593Smuzhiyun             return rc;
4766*4882a593Smuzhiyun         /* It is a match error to try to set the input focus to an
4767*4882a593Smuzhiyun            unviewable window. */
4768*4882a593Smuzhiyun         if (!focusWin->realized)
4769*4882a593Smuzhiyun             return BadMatch;
4770*4882a593Smuzhiyun     }
4771*4882a593Smuzhiyun     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixSetFocusAccess);
4772*4882a593Smuzhiyun     if (rc != Success)
4773*4882a593Smuzhiyun         return Success;
4774*4882a593Smuzhiyun 
4775*4882a593Smuzhiyun     focus = dev->focus;
4776*4882a593Smuzhiyun     if ((CompareTimeStamps(time, currentTime) == LATER) ||
4777*4882a593Smuzhiyun         (CompareTimeStamps(time, focus->time) == EARLIER))
4778*4882a593Smuzhiyun         return Success;
4779*4882a593Smuzhiyun     mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal;
4780*4882a593Smuzhiyun     if (focus->win == FollowKeyboardWin) {
4781*4882a593Smuzhiyun         if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin))
4782*4882a593Smuzhiyun             DoFocusEvents(dev, keybd->focus->win, focusWin, mode);
4783*4882a593Smuzhiyun     }
4784*4882a593Smuzhiyun     else {
4785*4882a593Smuzhiyun         if (!ActivateFocusInGrab(dev, focus->win, focusWin))
4786*4882a593Smuzhiyun             DoFocusEvents(dev, focus->win, focusWin, mode);
4787*4882a593Smuzhiyun     }
4788*4882a593Smuzhiyun     focus->time = time;
4789*4882a593Smuzhiyun     focus->revert = revertTo;
4790*4882a593Smuzhiyun     if (focusID == FollowKeyboard)
4791*4882a593Smuzhiyun         focus->win = FollowKeyboardWin;
4792*4882a593Smuzhiyun     else
4793*4882a593Smuzhiyun         focus->win = focusWin;
4794*4882a593Smuzhiyun     if ((focusWin == NoneWin) || (focusWin == PointerRootWin))
4795*4882a593Smuzhiyun         focus->traceGood = 0;
4796*4882a593Smuzhiyun     else {
4797*4882a593Smuzhiyun         int depth = 0;
4798*4882a593Smuzhiyun         WindowPtr pWin;
4799*4882a593Smuzhiyun 
4800*4882a593Smuzhiyun         for (pWin = focusWin; pWin; pWin = pWin->parent)
4801*4882a593Smuzhiyun             depth++;
4802*4882a593Smuzhiyun         if (depth > focus->traceSize) {
4803*4882a593Smuzhiyun             focus->traceSize = depth + 1;
4804*4882a593Smuzhiyun             focus->trace = reallocarray(focus->trace, focus->traceSize,
4805*4882a593Smuzhiyun                                         sizeof(WindowPtr));
4806*4882a593Smuzhiyun         }
4807*4882a593Smuzhiyun         focus->traceGood = depth;
4808*4882a593Smuzhiyun         for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--)
4809*4882a593Smuzhiyun             focus->trace[depth] = pWin;
4810*4882a593Smuzhiyun     }
4811*4882a593Smuzhiyun     return Success;
4812*4882a593Smuzhiyun }
4813*4882a593Smuzhiyun 
4814*4882a593Smuzhiyun /**
4815*4882a593Smuzhiyun  * Server-side protocol handling for SetInputFocus request.
4816*4882a593Smuzhiyun  *
4817*4882a593Smuzhiyun  * Sets the input focus for the virtual core keyboard.
4818*4882a593Smuzhiyun  */
4819*4882a593Smuzhiyun int
ProcSetInputFocus(ClientPtr client)4820*4882a593Smuzhiyun ProcSetInputFocus(ClientPtr client)
4821*4882a593Smuzhiyun {
4822*4882a593Smuzhiyun     DeviceIntPtr kbd = PickKeyboard(client);
4823*4882a593Smuzhiyun 
4824*4882a593Smuzhiyun     REQUEST(xSetInputFocusReq);
4825*4882a593Smuzhiyun 
4826*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xSetInputFocusReq);
4827*4882a593Smuzhiyun 
4828*4882a593Smuzhiyun     return SetInputFocus(client, kbd, stuff->focus,
4829*4882a593Smuzhiyun                          stuff->revertTo, stuff->time, FALSE);
4830*4882a593Smuzhiyun }
4831*4882a593Smuzhiyun 
4832*4882a593Smuzhiyun /**
4833*4882a593Smuzhiyun  * Server-side protocol handling for GetInputFocus request.
4834*4882a593Smuzhiyun  *
4835*4882a593Smuzhiyun  * Sends the current input focus for the client's keyboard back to the
4836*4882a593Smuzhiyun  * client.
4837*4882a593Smuzhiyun  */
4838*4882a593Smuzhiyun int
ProcGetInputFocus(ClientPtr client)4839*4882a593Smuzhiyun ProcGetInputFocus(ClientPtr client)
4840*4882a593Smuzhiyun {
4841*4882a593Smuzhiyun     DeviceIntPtr kbd = PickKeyboard(client);
4842*4882a593Smuzhiyun     xGetInputFocusReply rep;
4843*4882a593Smuzhiyun     FocusClassPtr focus = kbd->focus;
4844*4882a593Smuzhiyun     int rc;
4845*4882a593Smuzhiyun 
4846*4882a593Smuzhiyun     /* REQUEST(xReq); */
4847*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xReq);
4848*4882a593Smuzhiyun 
4849*4882a593Smuzhiyun     rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetFocusAccess);
4850*4882a593Smuzhiyun     if (rc != Success)
4851*4882a593Smuzhiyun         return rc;
4852*4882a593Smuzhiyun 
4853*4882a593Smuzhiyun     rep = (xGetInputFocusReply) {
4854*4882a593Smuzhiyun         .type = X_Reply,
4855*4882a593Smuzhiyun         .length = 0,
4856*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
4857*4882a593Smuzhiyun         .revertTo = focus->revert
4858*4882a593Smuzhiyun     };
4859*4882a593Smuzhiyun 
4860*4882a593Smuzhiyun     if (focus->win == NoneWin)
4861*4882a593Smuzhiyun         rep.focus = None;
4862*4882a593Smuzhiyun     else if (focus->win == PointerRootWin)
4863*4882a593Smuzhiyun         rep.focus = PointerRoot;
4864*4882a593Smuzhiyun     else
4865*4882a593Smuzhiyun         rep.focus = focus->win->drawable.id;
4866*4882a593Smuzhiyun 
4867*4882a593Smuzhiyun     WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep);
4868*4882a593Smuzhiyun     return Success;
4869*4882a593Smuzhiyun }
4870*4882a593Smuzhiyun 
4871*4882a593Smuzhiyun /**
4872*4882a593Smuzhiyun  * Server-side protocol handling for GrabPointer request.
4873*4882a593Smuzhiyun  *
4874*4882a593Smuzhiyun  * Sets an active grab on the client's ClientPointer and returns success
4875*4882a593Smuzhiyun  * status to client.
4876*4882a593Smuzhiyun  */
4877*4882a593Smuzhiyun int
ProcGrabPointer(ClientPtr client)4878*4882a593Smuzhiyun ProcGrabPointer(ClientPtr client)
4879*4882a593Smuzhiyun {
4880*4882a593Smuzhiyun     xGrabPointerReply rep;
4881*4882a593Smuzhiyun     DeviceIntPtr device = PickPointer(client);
4882*4882a593Smuzhiyun     GrabPtr grab;
4883*4882a593Smuzhiyun     GrabMask mask;
4884*4882a593Smuzhiyun     WindowPtr confineTo;
4885*4882a593Smuzhiyun     BYTE status;
4886*4882a593Smuzhiyun 
4887*4882a593Smuzhiyun     REQUEST(xGrabPointerReq);
4888*4882a593Smuzhiyun     int rc;
4889*4882a593Smuzhiyun 
4890*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xGrabPointerReq);
4891*4882a593Smuzhiyun     UpdateCurrentTime();
4892*4882a593Smuzhiyun 
4893*4882a593Smuzhiyun     if (stuff->eventMask & ~PointerGrabMask) {
4894*4882a593Smuzhiyun         client->errorValue = stuff->eventMask;
4895*4882a593Smuzhiyun         return BadValue;
4896*4882a593Smuzhiyun     }
4897*4882a593Smuzhiyun 
4898*4882a593Smuzhiyun     if (stuff->confineTo == None)
4899*4882a593Smuzhiyun         confineTo = NullWindow;
4900*4882a593Smuzhiyun     else {
4901*4882a593Smuzhiyun         rc = dixLookupWindow(&confineTo, stuff->confineTo, client,
4902*4882a593Smuzhiyun                              DixSetAttrAccess);
4903*4882a593Smuzhiyun         if (rc != Success)
4904*4882a593Smuzhiyun             return rc;
4905*4882a593Smuzhiyun     }
4906*4882a593Smuzhiyun 
4907*4882a593Smuzhiyun     grab = device->deviceGrab.grab;
4908*4882a593Smuzhiyun 
4909*4882a593Smuzhiyun     if (grab && grab->confineTo && !confineTo)
4910*4882a593Smuzhiyun         ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE, FALSE);
4911*4882a593Smuzhiyun 
4912*4882a593Smuzhiyun     mask.core = stuff->eventMask;
4913*4882a593Smuzhiyun 
4914*4882a593Smuzhiyun     rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode,
4915*4882a593Smuzhiyun                     stuff->grabWindow, stuff->ownerEvents, stuff->time,
4916*4882a593Smuzhiyun                     &mask, CORE, stuff->cursor, stuff->confineTo, &status);
4917*4882a593Smuzhiyun     if (rc != Success)
4918*4882a593Smuzhiyun         return rc;
4919*4882a593Smuzhiyun 
4920*4882a593Smuzhiyun     rep = (xGrabPointerReply) {
4921*4882a593Smuzhiyun         .type = X_Reply,
4922*4882a593Smuzhiyun         .status = status,
4923*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
4924*4882a593Smuzhiyun         .length = 0
4925*4882a593Smuzhiyun     };
4926*4882a593Smuzhiyun     WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep);
4927*4882a593Smuzhiyun     return Success;
4928*4882a593Smuzhiyun }
4929*4882a593Smuzhiyun 
4930*4882a593Smuzhiyun /**
4931*4882a593Smuzhiyun  * Server-side protocol handling for ChangeActivePointerGrab request.
4932*4882a593Smuzhiyun  *
4933*4882a593Smuzhiyun  * Changes properties of the grab hold by the client. If the client does not
4934*4882a593Smuzhiyun  * hold an active grab on the device, nothing happens.
4935*4882a593Smuzhiyun  */
4936*4882a593Smuzhiyun int
ProcChangeActivePointerGrab(ClientPtr client)4937*4882a593Smuzhiyun ProcChangeActivePointerGrab(ClientPtr client)
4938*4882a593Smuzhiyun {
4939*4882a593Smuzhiyun     DeviceIntPtr device;
4940*4882a593Smuzhiyun     GrabPtr grab;
4941*4882a593Smuzhiyun     CursorPtr newCursor, oldCursor;
4942*4882a593Smuzhiyun 
4943*4882a593Smuzhiyun     REQUEST(xChangeActivePointerGrabReq);
4944*4882a593Smuzhiyun     TimeStamp time;
4945*4882a593Smuzhiyun 
4946*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq);
4947*4882a593Smuzhiyun     if (stuff->eventMask & ~PointerGrabMask) {
4948*4882a593Smuzhiyun         client->errorValue = stuff->eventMask;
4949*4882a593Smuzhiyun         return BadValue;
4950*4882a593Smuzhiyun     }
4951*4882a593Smuzhiyun     if (stuff->cursor == None)
4952*4882a593Smuzhiyun         newCursor = NullCursor;
4953*4882a593Smuzhiyun     else {
4954*4882a593Smuzhiyun         int rc = dixLookupResourceByType((void **) &newCursor, stuff->cursor,
4955*4882a593Smuzhiyun                                          RT_CURSOR, client, DixUseAccess);
4956*4882a593Smuzhiyun 
4957*4882a593Smuzhiyun         if (rc != Success) {
4958*4882a593Smuzhiyun             client->errorValue = stuff->cursor;
4959*4882a593Smuzhiyun             return rc;
4960*4882a593Smuzhiyun         }
4961*4882a593Smuzhiyun     }
4962*4882a593Smuzhiyun 
4963*4882a593Smuzhiyun     device = PickPointer(client);
4964*4882a593Smuzhiyun     grab = device->deviceGrab.grab;
4965*4882a593Smuzhiyun 
4966*4882a593Smuzhiyun     if (!grab)
4967*4882a593Smuzhiyun         return Success;
4968*4882a593Smuzhiyun     if (!SameClient(grab, client))
4969*4882a593Smuzhiyun         return Success;
4970*4882a593Smuzhiyun     UpdateCurrentTime();
4971*4882a593Smuzhiyun     time = ClientTimeToServerTime(stuff->time);
4972*4882a593Smuzhiyun     if ((CompareTimeStamps(time, currentTime) == LATER) ||
4973*4882a593Smuzhiyun         (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER))
4974*4882a593Smuzhiyun         return Success;
4975*4882a593Smuzhiyun     oldCursor = grab->cursor;
4976*4882a593Smuzhiyun     grab->cursor = RefCursor(newCursor);
4977*4882a593Smuzhiyun     PostNewCursor(device);
4978*4882a593Smuzhiyun     if (oldCursor)
4979*4882a593Smuzhiyun         FreeCursor(oldCursor, (Cursor) 0);
4980*4882a593Smuzhiyun     grab->eventMask = stuff->eventMask;
4981*4882a593Smuzhiyun     return Success;
4982*4882a593Smuzhiyun }
4983*4882a593Smuzhiyun 
4984*4882a593Smuzhiyun /**
4985*4882a593Smuzhiyun  * Server-side protocol handling for UngrabPointer request.
4986*4882a593Smuzhiyun  *
4987*4882a593Smuzhiyun  * Deletes a pointer grab on a device the client has grabbed.
4988*4882a593Smuzhiyun  */
4989*4882a593Smuzhiyun int
ProcUngrabPointer(ClientPtr client)4990*4882a593Smuzhiyun ProcUngrabPointer(ClientPtr client)
4991*4882a593Smuzhiyun {
4992*4882a593Smuzhiyun     DeviceIntPtr device = PickPointer(client);
4993*4882a593Smuzhiyun     GrabPtr grab;
4994*4882a593Smuzhiyun     TimeStamp time;
4995*4882a593Smuzhiyun 
4996*4882a593Smuzhiyun     REQUEST(xResourceReq);
4997*4882a593Smuzhiyun 
4998*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xResourceReq);
4999*4882a593Smuzhiyun     UpdateCurrentTime();
5000*4882a593Smuzhiyun     grab = device->deviceGrab.grab;
5001*4882a593Smuzhiyun 
5002*4882a593Smuzhiyun     time = ClientTimeToServerTime(stuff->id);
5003*4882a593Smuzhiyun     if ((CompareTimeStamps(time, currentTime) != LATER) &&
5004*4882a593Smuzhiyun         (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
5005*4882a593Smuzhiyun         (grab) && SameClient(grab, client))
5006*4882a593Smuzhiyun         (*device->deviceGrab.DeactivateGrab) (device);
5007*4882a593Smuzhiyun     return Success;
5008*4882a593Smuzhiyun }
5009*4882a593Smuzhiyun 
5010*4882a593Smuzhiyun /**
5011*4882a593Smuzhiyun  * Sets a grab on the given device.
5012*4882a593Smuzhiyun  *
5013*4882a593Smuzhiyun  * Called from ProcGrabKeyboard to work on the client's keyboard.
5014*4882a593Smuzhiyun  * Called from ProcXGrabDevice to work on the device specified by the client.
5015*4882a593Smuzhiyun  *
5016*4882a593Smuzhiyun  * The parameters this_mode and other_mode represent the keyboard_mode and
5017*4882a593Smuzhiyun  * pointer_mode parameters of XGrabKeyboard().
5018*4882a593Smuzhiyun  * See man page for details on all the parameters
5019*4882a593Smuzhiyun  *
5020*4882a593Smuzhiyun  * @param client Client that owns the grab.
5021*4882a593Smuzhiyun  * @param dev The device to grab.
5022*4882a593Smuzhiyun  * @param this_mode GrabModeSync or GrabModeAsync
5023*4882a593Smuzhiyun  * @param other_mode GrabModeSync or GrabModeAsync
5024*4882a593Smuzhiyun  * @param status Return code to be returned to the caller.
5025*4882a593Smuzhiyun  *
5026*4882a593Smuzhiyun  * @returns Success or BadValue or BadAlloc.
5027*4882a593Smuzhiyun  */
5028*4882a593Smuzhiyun int
GrabDevice(ClientPtr client,DeviceIntPtr dev,unsigned pointer_mode,unsigned keyboard_mode,Window grabWindow,unsigned ownerEvents,Time ctime,GrabMask * mask,int grabtype,Cursor curs,Window confineToWin,CARD8 * status)5029*4882a593Smuzhiyun GrabDevice(ClientPtr client, DeviceIntPtr dev,
5030*4882a593Smuzhiyun            unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow,
5031*4882a593Smuzhiyun            unsigned ownerEvents, Time ctime, GrabMask *mask,
5032*4882a593Smuzhiyun            int grabtype, Cursor curs, Window confineToWin, CARD8 *status)
5033*4882a593Smuzhiyun {
5034*4882a593Smuzhiyun     WindowPtr pWin, confineTo;
5035*4882a593Smuzhiyun     GrabPtr grab;
5036*4882a593Smuzhiyun     TimeStamp time;
5037*4882a593Smuzhiyun     Mask access_mode = DixGrabAccess;
5038*4882a593Smuzhiyun     int rc;
5039*4882a593Smuzhiyun     GrabInfoPtr grabInfo = &dev->deviceGrab;
5040*4882a593Smuzhiyun     CursorPtr cursor;
5041*4882a593Smuzhiyun 
5042*4882a593Smuzhiyun     UpdateCurrentTime();
5043*4882a593Smuzhiyun     if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync)) {
5044*4882a593Smuzhiyun         client->errorValue = keyboard_mode;
5045*4882a593Smuzhiyun         return BadValue;
5046*4882a593Smuzhiyun     }
5047*4882a593Smuzhiyun     if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync)) {
5048*4882a593Smuzhiyun         client->errorValue = pointer_mode;
5049*4882a593Smuzhiyun         return BadValue;
5050*4882a593Smuzhiyun     }
5051*4882a593Smuzhiyun     if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) {
5052*4882a593Smuzhiyun         client->errorValue = ownerEvents;
5053*4882a593Smuzhiyun         return BadValue;
5054*4882a593Smuzhiyun     }
5055*4882a593Smuzhiyun 
5056*4882a593Smuzhiyun     rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess);
5057*4882a593Smuzhiyun     if (rc != Success)
5058*4882a593Smuzhiyun         return rc;
5059*4882a593Smuzhiyun 
5060*4882a593Smuzhiyun     if (confineToWin == None)
5061*4882a593Smuzhiyun         confineTo = NullWindow;
5062*4882a593Smuzhiyun     else {
5063*4882a593Smuzhiyun         rc = dixLookupWindow(&confineTo, confineToWin, client,
5064*4882a593Smuzhiyun                              DixSetAttrAccess);
5065*4882a593Smuzhiyun         if (rc != Success)
5066*4882a593Smuzhiyun             return rc;
5067*4882a593Smuzhiyun     }
5068*4882a593Smuzhiyun 
5069*4882a593Smuzhiyun     if (curs == None)
5070*4882a593Smuzhiyun         cursor = NullCursor;
5071*4882a593Smuzhiyun     else {
5072*4882a593Smuzhiyun         rc = dixLookupResourceByType((void **) &cursor, curs, RT_CURSOR,
5073*4882a593Smuzhiyun                                      client, DixUseAccess);
5074*4882a593Smuzhiyun         if (rc != Success) {
5075*4882a593Smuzhiyun             client->errorValue = curs;
5076*4882a593Smuzhiyun             return rc;
5077*4882a593Smuzhiyun         }
5078*4882a593Smuzhiyun         access_mode |= DixForceAccess;
5079*4882a593Smuzhiyun     }
5080*4882a593Smuzhiyun 
5081*4882a593Smuzhiyun     if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync)
5082*4882a593Smuzhiyun         access_mode |= DixFreezeAccess;
5083*4882a593Smuzhiyun     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
5084*4882a593Smuzhiyun     if (rc != Success)
5085*4882a593Smuzhiyun         return rc;
5086*4882a593Smuzhiyun 
5087*4882a593Smuzhiyun     time = ClientTimeToServerTime(ctime);
5088*4882a593Smuzhiyun     grab = grabInfo->grab;
5089*4882a593Smuzhiyun     if (grab && grab->grabtype != grabtype)
5090*4882a593Smuzhiyun         *status = AlreadyGrabbed;
5091*4882a593Smuzhiyun     else if (grab && !SameClient(grab, client))
5092*4882a593Smuzhiyun         *status = AlreadyGrabbed;
5093*4882a593Smuzhiyun     else if ((!pWin->realized) ||
5094*4882a593Smuzhiyun              (confineTo &&
5095*4882a593Smuzhiyun               !(confineTo->realized && BorderSizeNotEmpty(dev, confineTo))))
5096*4882a593Smuzhiyun         *status = GrabNotViewable;
5097*4882a593Smuzhiyun     else if ((CompareTimeStamps(time, currentTime) == LATER) ||
5098*4882a593Smuzhiyun              (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER))
5099*4882a593Smuzhiyun         *status = GrabInvalidTime;
5100*4882a593Smuzhiyun     else if (grabInfo->sync.frozen &&
5101*4882a593Smuzhiyun              grabInfo->sync.other && !SameClient(grabInfo->sync.other, client))
5102*4882a593Smuzhiyun         *status = GrabFrozen;
5103*4882a593Smuzhiyun     else {
5104*4882a593Smuzhiyun         GrabPtr tempGrab;
5105*4882a593Smuzhiyun 
5106*4882a593Smuzhiyun         tempGrab = AllocGrab(NULL);
5107*4882a593Smuzhiyun         if (tempGrab == NULL)
5108*4882a593Smuzhiyun             return BadAlloc;
5109*4882a593Smuzhiyun 
5110*4882a593Smuzhiyun         tempGrab->next = NULL;
5111*4882a593Smuzhiyun         tempGrab->window = pWin;
5112*4882a593Smuzhiyun         tempGrab->resource = client->clientAsMask;
5113*4882a593Smuzhiyun         tempGrab->ownerEvents = ownerEvents;
5114*4882a593Smuzhiyun         tempGrab->keyboardMode = keyboard_mode;
5115*4882a593Smuzhiyun         tempGrab->pointerMode = pointer_mode;
5116*4882a593Smuzhiyun         if (grabtype == CORE)
5117*4882a593Smuzhiyun             tempGrab->eventMask = mask->core;
5118*4882a593Smuzhiyun         else if (grabtype == XI)
5119*4882a593Smuzhiyun             tempGrab->eventMask = mask->xi;
5120*4882a593Smuzhiyun         else
5121*4882a593Smuzhiyun             xi2mask_merge(tempGrab->xi2mask, mask->xi2mask);
5122*4882a593Smuzhiyun         tempGrab->device = dev;
5123*4882a593Smuzhiyun         tempGrab->cursor = RefCursor(cursor);
5124*4882a593Smuzhiyun         tempGrab->confineTo = confineTo;
5125*4882a593Smuzhiyun         tempGrab->grabtype = grabtype;
5126*4882a593Smuzhiyun         (*grabInfo->ActivateGrab) (dev, tempGrab, time, FALSE);
5127*4882a593Smuzhiyun         *status = GrabSuccess;
5128*4882a593Smuzhiyun 
5129*4882a593Smuzhiyun         FreeGrab(tempGrab);
5130*4882a593Smuzhiyun     }
5131*4882a593Smuzhiyun     return Success;
5132*4882a593Smuzhiyun }
5133*4882a593Smuzhiyun 
5134*4882a593Smuzhiyun /**
5135*4882a593Smuzhiyun  * Server-side protocol handling for GrabKeyboard request.
5136*4882a593Smuzhiyun  *
5137*4882a593Smuzhiyun  * Grabs the client's keyboard and returns success status to client.
5138*4882a593Smuzhiyun  */
5139*4882a593Smuzhiyun int
ProcGrabKeyboard(ClientPtr client)5140*4882a593Smuzhiyun ProcGrabKeyboard(ClientPtr client)
5141*4882a593Smuzhiyun {
5142*4882a593Smuzhiyun     xGrabKeyboardReply rep;
5143*4882a593Smuzhiyun     BYTE status;
5144*4882a593Smuzhiyun 
5145*4882a593Smuzhiyun     REQUEST(xGrabKeyboardReq);
5146*4882a593Smuzhiyun     int result;
5147*4882a593Smuzhiyun     DeviceIntPtr keyboard = PickKeyboard(client);
5148*4882a593Smuzhiyun     GrabMask mask;
5149*4882a593Smuzhiyun 
5150*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xGrabKeyboardReq);
5151*4882a593Smuzhiyun     UpdateCurrentTime();
5152*4882a593Smuzhiyun 
5153*4882a593Smuzhiyun     mask.core = KeyPressMask | KeyReleaseMask;
5154*4882a593Smuzhiyun 
5155*4882a593Smuzhiyun     result = GrabDevice(client, keyboard, stuff->pointerMode,
5156*4882a593Smuzhiyun                         stuff->keyboardMode, stuff->grabWindow,
5157*4882a593Smuzhiyun                         stuff->ownerEvents, stuff->time, &mask, CORE, None,
5158*4882a593Smuzhiyun                         None, &status);
5159*4882a593Smuzhiyun 
5160*4882a593Smuzhiyun     if (result != Success)
5161*4882a593Smuzhiyun         return result;
5162*4882a593Smuzhiyun 
5163*4882a593Smuzhiyun     rep = (xGrabKeyboardReply) {
5164*4882a593Smuzhiyun         .type = X_Reply,
5165*4882a593Smuzhiyun         .status = status,
5166*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
5167*4882a593Smuzhiyun         .length = 0
5168*4882a593Smuzhiyun     };
5169*4882a593Smuzhiyun     WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep);
5170*4882a593Smuzhiyun     return Success;
5171*4882a593Smuzhiyun }
5172*4882a593Smuzhiyun 
5173*4882a593Smuzhiyun /**
5174*4882a593Smuzhiyun  * Server-side protocol handling for UngrabKeyboard request.
5175*4882a593Smuzhiyun  *
5176*4882a593Smuzhiyun  * Deletes a possible grab on the client's keyboard.
5177*4882a593Smuzhiyun  */
5178*4882a593Smuzhiyun int
ProcUngrabKeyboard(ClientPtr client)5179*4882a593Smuzhiyun ProcUngrabKeyboard(ClientPtr client)
5180*4882a593Smuzhiyun {
5181*4882a593Smuzhiyun     DeviceIntPtr device = PickKeyboard(client);
5182*4882a593Smuzhiyun     GrabPtr grab;
5183*4882a593Smuzhiyun     TimeStamp time;
5184*4882a593Smuzhiyun 
5185*4882a593Smuzhiyun     REQUEST(xResourceReq);
5186*4882a593Smuzhiyun 
5187*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xResourceReq);
5188*4882a593Smuzhiyun     UpdateCurrentTime();
5189*4882a593Smuzhiyun 
5190*4882a593Smuzhiyun     grab = device->deviceGrab.grab;
5191*4882a593Smuzhiyun 
5192*4882a593Smuzhiyun     time = ClientTimeToServerTime(stuff->id);
5193*4882a593Smuzhiyun     if ((CompareTimeStamps(time, currentTime) != LATER) &&
5194*4882a593Smuzhiyun         (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) &&
5195*4882a593Smuzhiyun         (grab) && SameClient(grab, client) && grab->grabtype == CORE)
5196*4882a593Smuzhiyun         (*device->deviceGrab.DeactivateGrab) (device);
5197*4882a593Smuzhiyun     return Success;
5198*4882a593Smuzhiyun }
5199*4882a593Smuzhiyun 
5200*4882a593Smuzhiyun /**
5201*4882a593Smuzhiyun  * Server-side protocol handling for QueryPointer request.
5202*4882a593Smuzhiyun  *
5203*4882a593Smuzhiyun  * Returns the current state and position of the client's ClientPointer to the
5204*4882a593Smuzhiyun  * client.
5205*4882a593Smuzhiyun  */
5206*4882a593Smuzhiyun int
ProcQueryPointer(ClientPtr client)5207*4882a593Smuzhiyun ProcQueryPointer(ClientPtr client)
5208*4882a593Smuzhiyun {
5209*4882a593Smuzhiyun     xQueryPointerReply rep;
5210*4882a593Smuzhiyun     WindowPtr pWin, t;
5211*4882a593Smuzhiyun     DeviceIntPtr mouse = PickPointer(client);
5212*4882a593Smuzhiyun     DeviceIntPtr keyboard;
5213*4882a593Smuzhiyun     SpritePtr pSprite;
5214*4882a593Smuzhiyun     int rc;
5215*4882a593Smuzhiyun 
5216*4882a593Smuzhiyun     REQUEST(xResourceReq);
5217*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xResourceReq);
5218*4882a593Smuzhiyun 
5219*4882a593Smuzhiyun     rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess);
5220*4882a593Smuzhiyun     if (rc != Success)
5221*4882a593Smuzhiyun         return rc;
5222*4882a593Smuzhiyun     rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess);
5223*4882a593Smuzhiyun     if (rc != Success && rc != BadAccess)
5224*4882a593Smuzhiyun         return rc;
5225*4882a593Smuzhiyun 
5226*4882a593Smuzhiyun     keyboard = GetMaster(mouse, MASTER_KEYBOARD);
5227*4882a593Smuzhiyun 
5228*4882a593Smuzhiyun     pSprite = mouse->spriteInfo->sprite;
5229*4882a593Smuzhiyun     if (mouse->valuator->motionHintWindow)
5230*4882a593Smuzhiyun         MaybeStopHint(mouse, client);
5231*4882a593Smuzhiyun     rep = (xQueryPointerReply) {
5232*4882a593Smuzhiyun         .type = X_Reply,
5233*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
5234*4882a593Smuzhiyun         .length = 0,
5235*4882a593Smuzhiyun         .mask = event_get_corestate(mouse, keyboard),
5236*4882a593Smuzhiyun         .root = (GetCurrentRootWindow(mouse))->drawable.id,
5237*4882a593Smuzhiyun         .rootX = pSprite->hot.x,
5238*4882a593Smuzhiyun         .rootY = pSprite->hot.y,
5239*4882a593Smuzhiyun         .child = None
5240*4882a593Smuzhiyun     };
5241*4882a593Smuzhiyun     if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
5242*4882a593Smuzhiyun         rep.sameScreen = xTrue;
5243*4882a593Smuzhiyun         rep.winX = pSprite->hot.x - pWin->drawable.x;
5244*4882a593Smuzhiyun         rep.winY = pSprite->hot.y - pWin->drawable.y;
5245*4882a593Smuzhiyun         for (t = pSprite->win; t; t = t->parent)
5246*4882a593Smuzhiyun             if (t->parent == pWin) {
5247*4882a593Smuzhiyun                 rep.child = t->drawable.id;
5248*4882a593Smuzhiyun                 break;
5249*4882a593Smuzhiyun             }
5250*4882a593Smuzhiyun     }
5251*4882a593Smuzhiyun     else {
5252*4882a593Smuzhiyun         rep.sameScreen = xFalse;
5253*4882a593Smuzhiyun         rep.winX = 0;
5254*4882a593Smuzhiyun         rep.winY = 0;
5255*4882a593Smuzhiyun     }
5256*4882a593Smuzhiyun 
5257*4882a593Smuzhiyun #ifdef PANORAMIX
5258*4882a593Smuzhiyun     if (!noPanoramiXExtension) {
5259*4882a593Smuzhiyun         rep.rootX += screenInfo.screens[0]->x;
5260*4882a593Smuzhiyun         rep.rootY += screenInfo.screens[0]->y;
5261*4882a593Smuzhiyun         if (stuff->id == rep.root) {
5262*4882a593Smuzhiyun             rep.winX += screenInfo.screens[0]->x;
5263*4882a593Smuzhiyun             rep.winY += screenInfo.screens[0]->y;
5264*4882a593Smuzhiyun         }
5265*4882a593Smuzhiyun     }
5266*4882a593Smuzhiyun #endif
5267*4882a593Smuzhiyun 
5268*4882a593Smuzhiyun     if (rc == BadAccess) {
5269*4882a593Smuzhiyun         rep.mask = 0;
5270*4882a593Smuzhiyun         rep.child = None;
5271*4882a593Smuzhiyun         rep.rootX = 0;
5272*4882a593Smuzhiyun         rep.rootY = 0;
5273*4882a593Smuzhiyun         rep.winX = 0;
5274*4882a593Smuzhiyun         rep.winY = 0;
5275*4882a593Smuzhiyun     }
5276*4882a593Smuzhiyun 
5277*4882a593Smuzhiyun     WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep);
5278*4882a593Smuzhiyun 
5279*4882a593Smuzhiyun     return Success;
5280*4882a593Smuzhiyun }
5281*4882a593Smuzhiyun 
5282*4882a593Smuzhiyun /**
5283*4882a593Smuzhiyun  * Initializes the device list and the DIX sprite to sane values. Allocates
5284*4882a593Smuzhiyun  * trace memory used for quick window traversal.
5285*4882a593Smuzhiyun  */
5286*4882a593Smuzhiyun void
InitEvents(void)5287*4882a593Smuzhiyun InitEvents(void)
5288*4882a593Smuzhiyun {
5289*4882a593Smuzhiyun     int i;
5290*4882a593Smuzhiyun     QdEventPtr qe, tmp;
5291*4882a593Smuzhiyun 
5292*4882a593Smuzhiyun     inputInfo.numDevices = 0;
5293*4882a593Smuzhiyun     inputInfo.devices = (DeviceIntPtr) NULL;
5294*4882a593Smuzhiyun     inputInfo.off_devices = (DeviceIntPtr) NULL;
5295*4882a593Smuzhiyun     inputInfo.keyboard = (DeviceIntPtr) NULL;
5296*4882a593Smuzhiyun     inputInfo.pointer = (DeviceIntPtr) NULL;
5297*4882a593Smuzhiyun 
5298*4882a593Smuzhiyun     for (i = 0; i < MAXDEVICES; i++) {
5299*4882a593Smuzhiyun         DeviceIntRec dummy;
5300*4882a593Smuzhiyun         memcpy(&event_filters[i], default_filter, sizeof(default_filter));
5301*4882a593Smuzhiyun 
5302*4882a593Smuzhiyun         dummy.id = i;
5303*4882a593Smuzhiyun         NoticeTime(&dummy, currentTime);
5304*4882a593Smuzhiyun         LastEventTimeToggleResetFlag(i, FALSE);
5305*4882a593Smuzhiyun     }
5306*4882a593Smuzhiyun 
5307*4882a593Smuzhiyun     syncEvents.replayDev = (DeviceIntPtr) NULL;
5308*4882a593Smuzhiyun     syncEvents.replayWin = NullWindow;
5309*4882a593Smuzhiyun     if (syncEvents.pending.next)
5310*4882a593Smuzhiyun         xorg_list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next)
5311*4882a593Smuzhiyun             free(qe);
5312*4882a593Smuzhiyun     xorg_list_init(&syncEvents.pending);
5313*4882a593Smuzhiyun     syncEvents.playingEvents = FALSE;
5314*4882a593Smuzhiyun     syncEvents.time.months = 0;
5315*4882a593Smuzhiyun     syncEvents.time.milliseconds = 0;   /* hardly matters */
5316*4882a593Smuzhiyun     currentTime.months = 0;
5317*4882a593Smuzhiyun     currentTime.milliseconds = GetTimeInMillis();
5318*4882a593Smuzhiyun     for (i = 0; i < DNPMCOUNT; i++) {
5319*4882a593Smuzhiyun         DontPropagateMasks[i] = 0;
5320*4882a593Smuzhiyun         DontPropagateRefCnts[i] = 0;
5321*4882a593Smuzhiyun     }
5322*4882a593Smuzhiyun 
5323*4882a593Smuzhiyun     InputEventList = InitEventList(GetMaximumEventsNum());
5324*4882a593Smuzhiyun     if (!InputEventList)
5325*4882a593Smuzhiyun         FatalError("[dix] Failed to allocate input event list.\n");
5326*4882a593Smuzhiyun }
5327*4882a593Smuzhiyun 
5328*4882a593Smuzhiyun void
CloseDownEvents(void)5329*4882a593Smuzhiyun CloseDownEvents(void)
5330*4882a593Smuzhiyun {
5331*4882a593Smuzhiyun     FreeEventList(InputEventList, GetMaximumEventsNum());
5332*4882a593Smuzhiyun     InputEventList = NULL;
5333*4882a593Smuzhiyun }
5334*4882a593Smuzhiyun 
5335*4882a593Smuzhiyun #define SEND_EVENT_BIT 0x80
5336*4882a593Smuzhiyun 
5337*4882a593Smuzhiyun /**
5338*4882a593Smuzhiyun  * Server-side protocol handling for SendEvent request.
5339*4882a593Smuzhiyun  *
5340*4882a593Smuzhiyun  * Locates the window to send the event to and forwards the event.
5341*4882a593Smuzhiyun  */
5342*4882a593Smuzhiyun int
ProcSendEvent(ClientPtr client)5343*4882a593Smuzhiyun ProcSendEvent(ClientPtr client)
5344*4882a593Smuzhiyun {
5345*4882a593Smuzhiyun     WindowPtr pWin;
5346*4882a593Smuzhiyun     WindowPtr effectiveFocus = NullWindow;      /* only set if dest==InputFocus */
5347*4882a593Smuzhiyun     DeviceIntPtr dev = PickPointer(client);
5348*4882a593Smuzhiyun     DeviceIntPtr keybd = GetMaster(dev, MASTER_KEYBOARD);
5349*4882a593Smuzhiyun     SpritePtr pSprite = dev->spriteInfo->sprite;
5350*4882a593Smuzhiyun 
5351*4882a593Smuzhiyun     REQUEST(xSendEventReq);
5352*4882a593Smuzhiyun 
5353*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xSendEventReq);
5354*4882a593Smuzhiyun 
5355*4882a593Smuzhiyun     /* libXext and other extension libraries may set the bit indicating
5356*4882a593Smuzhiyun      * that this event came from a SendEvent request so remove it
5357*4882a593Smuzhiyun      * since otherwise the event type may fail the range checks
5358*4882a593Smuzhiyun      * and cause an invalid BadValue error to be returned.
5359*4882a593Smuzhiyun      *
5360*4882a593Smuzhiyun      * This is safe to do since we later add the SendEvent bit (0x80)
5361*4882a593Smuzhiyun      * back in once we send the event to the client */
5362*4882a593Smuzhiyun 
5363*4882a593Smuzhiyun     stuff->event.u.u.type &= ~(SEND_EVENT_BIT);
5364*4882a593Smuzhiyun 
5365*4882a593Smuzhiyun     /* The client's event type must be a core event type or one defined by an
5366*4882a593Smuzhiyun        extension. */
5367*4882a593Smuzhiyun 
5368*4882a593Smuzhiyun     if (!((stuff->event.u.u.type > X_Reply &&
5369*4882a593Smuzhiyun            stuff->event.u.u.type < LASTEvent) ||
5370*4882a593Smuzhiyun           (stuff->event.u.u.type >= EXTENSION_EVENT_BASE &&
5371*4882a593Smuzhiyun            stuff->event.u.u.type < (unsigned) lastEvent))) {
5372*4882a593Smuzhiyun         client->errorValue = stuff->event.u.u.type;
5373*4882a593Smuzhiyun         return BadValue;
5374*4882a593Smuzhiyun     }
5375*4882a593Smuzhiyun     /* Generic events can have variable size, but SendEvent request holds
5376*4882a593Smuzhiyun        exactly 32B of event data. */
5377*4882a593Smuzhiyun     if (stuff->event.u.u.type == GenericEvent) {
5378*4882a593Smuzhiyun         client->errorValue = stuff->event.u.u.type;
5379*4882a593Smuzhiyun         return BadValue;
5380*4882a593Smuzhiyun     }
5381*4882a593Smuzhiyun     if (stuff->event.u.u.type == ClientMessage &&
5382*4882a593Smuzhiyun         stuff->event.u.u.detail != 8 &&
5383*4882a593Smuzhiyun         stuff->event.u.u.detail != 16 && stuff->event.u.u.detail != 32) {
5384*4882a593Smuzhiyun         client->errorValue = stuff->event.u.u.detail;
5385*4882a593Smuzhiyun         return BadValue;
5386*4882a593Smuzhiyun     }
5387*4882a593Smuzhiyun     if (stuff->eventMask & ~AllEventMasks) {
5388*4882a593Smuzhiyun         client->errorValue = stuff->eventMask;
5389*4882a593Smuzhiyun         return BadValue;
5390*4882a593Smuzhiyun     }
5391*4882a593Smuzhiyun 
5392*4882a593Smuzhiyun     if (stuff->destination == PointerWindow)
5393*4882a593Smuzhiyun         pWin = pSprite->win;
5394*4882a593Smuzhiyun     else if (stuff->destination == InputFocus) {
5395*4882a593Smuzhiyun         WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin;
5396*4882a593Smuzhiyun 
5397*4882a593Smuzhiyun         if (inputFocus == NoneWin)
5398*4882a593Smuzhiyun             return Success;
5399*4882a593Smuzhiyun 
5400*4882a593Smuzhiyun         /* If the input focus is PointerRootWin, send the event to where
5401*4882a593Smuzhiyun            the pointer is if possible, then perhaps propogate up to root. */
5402*4882a593Smuzhiyun         if (inputFocus == PointerRootWin)
5403*4882a593Smuzhiyun             inputFocus = GetCurrentRootWindow(dev);
5404*4882a593Smuzhiyun 
5405*4882a593Smuzhiyun         if (IsParent(inputFocus, pSprite->win)) {
5406*4882a593Smuzhiyun             effectiveFocus = inputFocus;
5407*4882a593Smuzhiyun             pWin = pSprite->win;
5408*4882a593Smuzhiyun         }
5409*4882a593Smuzhiyun         else
5410*4882a593Smuzhiyun             effectiveFocus = pWin = inputFocus;
5411*4882a593Smuzhiyun     }
5412*4882a593Smuzhiyun     else
5413*4882a593Smuzhiyun         dixLookupWindow(&pWin, stuff->destination, client, DixSendAccess);
5414*4882a593Smuzhiyun 
5415*4882a593Smuzhiyun     if (!pWin)
5416*4882a593Smuzhiyun         return BadWindow;
5417*4882a593Smuzhiyun     if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) {
5418*4882a593Smuzhiyun         client->errorValue = stuff->propagate;
5419*4882a593Smuzhiyun         return BadValue;
5420*4882a593Smuzhiyun     }
5421*4882a593Smuzhiyun     stuff->event.u.u.type |= SEND_EVENT_BIT;
5422*4882a593Smuzhiyun     if (stuff->propagate) {
5423*4882a593Smuzhiyun         for (; pWin; pWin = pWin->parent) {
5424*4882a593Smuzhiyun             if (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin,
5425*4882a593Smuzhiyun                          &stuff->event, 1))
5426*4882a593Smuzhiyun                 return Success;
5427*4882a593Smuzhiyun             if (DeliverEventsToWindow(dev, pWin,
5428*4882a593Smuzhiyun                                       &stuff->event, 1, stuff->eventMask,
5429*4882a593Smuzhiyun                                       NullGrab))
5430*4882a593Smuzhiyun                 return Success;
5431*4882a593Smuzhiyun             if (pWin == effectiveFocus)
5432*4882a593Smuzhiyun                 return Success;
5433*4882a593Smuzhiyun             stuff->eventMask &= ~wDontPropagateMask(pWin);
5434*4882a593Smuzhiyun             if (!stuff->eventMask)
5435*4882a593Smuzhiyun                 break;
5436*4882a593Smuzhiyun         }
5437*4882a593Smuzhiyun     }
5438*4882a593Smuzhiyun     else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1))
5439*4882a593Smuzhiyun         DeliverEventsToWindow(dev, pWin, &stuff->event,
5440*4882a593Smuzhiyun                               1, stuff->eventMask, NullGrab);
5441*4882a593Smuzhiyun     return Success;
5442*4882a593Smuzhiyun }
5443*4882a593Smuzhiyun 
5444*4882a593Smuzhiyun /**
5445*4882a593Smuzhiyun  * Server-side protocol handling for UngrabKey request.
5446*4882a593Smuzhiyun  *
5447*4882a593Smuzhiyun  * Deletes a passive grab for the given key. Works on the
5448*4882a593Smuzhiyun  * client's keyboard.
5449*4882a593Smuzhiyun  */
5450*4882a593Smuzhiyun int
ProcUngrabKey(ClientPtr client)5451*4882a593Smuzhiyun ProcUngrabKey(ClientPtr client)
5452*4882a593Smuzhiyun {
5453*4882a593Smuzhiyun     REQUEST(xUngrabKeyReq);
5454*4882a593Smuzhiyun     WindowPtr pWin;
5455*4882a593Smuzhiyun     GrabPtr tempGrab;
5456*4882a593Smuzhiyun     DeviceIntPtr keybd = PickKeyboard(client);
5457*4882a593Smuzhiyun     int rc;
5458*4882a593Smuzhiyun 
5459*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xUngrabKeyReq);
5460*4882a593Smuzhiyun     rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess);
5461*4882a593Smuzhiyun     if (rc != Success)
5462*4882a593Smuzhiyun         return rc;
5463*4882a593Smuzhiyun 
5464*4882a593Smuzhiyun     if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) ||
5465*4882a593Smuzhiyun          (stuff->key < keybd->key->xkbInfo->desc->min_key_code))
5466*4882a593Smuzhiyun         && (stuff->key != AnyKey)) {
5467*4882a593Smuzhiyun         client->errorValue = stuff->key;
5468*4882a593Smuzhiyun         return BadValue;
5469*4882a593Smuzhiyun     }
5470*4882a593Smuzhiyun     if ((stuff->modifiers != AnyModifier) &&
5471*4882a593Smuzhiyun         (stuff->modifiers & ~AllModifiersMask)) {
5472*4882a593Smuzhiyun         client->errorValue = stuff->modifiers;
5473*4882a593Smuzhiyun         return BadValue;
5474*4882a593Smuzhiyun     }
5475*4882a593Smuzhiyun     tempGrab = AllocGrab(NULL);
5476*4882a593Smuzhiyun     if (!tempGrab)
5477*4882a593Smuzhiyun         return BadAlloc;
5478*4882a593Smuzhiyun     tempGrab->resource = client->clientAsMask;
5479*4882a593Smuzhiyun     tempGrab->device = keybd;
5480*4882a593Smuzhiyun     tempGrab->window = pWin;
5481*4882a593Smuzhiyun     tempGrab->modifiersDetail.exact = stuff->modifiers;
5482*4882a593Smuzhiyun     tempGrab->modifiersDetail.pMask = NULL;
5483*4882a593Smuzhiyun     tempGrab->modifierDevice = keybd;
5484*4882a593Smuzhiyun     tempGrab->type = KeyPress;
5485*4882a593Smuzhiyun     tempGrab->grabtype = CORE;
5486*4882a593Smuzhiyun     tempGrab->detail.exact = stuff->key;
5487*4882a593Smuzhiyun     tempGrab->detail.pMask = NULL;
5488*4882a593Smuzhiyun     tempGrab->next = NULL;
5489*4882a593Smuzhiyun 
5490*4882a593Smuzhiyun     if (!DeletePassiveGrabFromList(tempGrab))
5491*4882a593Smuzhiyun         rc = BadAlloc;
5492*4882a593Smuzhiyun 
5493*4882a593Smuzhiyun     FreeGrab(tempGrab);
5494*4882a593Smuzhiyun 
5495*4882a593Smuzhiyun     return rc;
5496*4882a593Smuzhiyun }
5497*4882a593Smuzhiyun 
5498*4882a593Smuzhiyun /**
5499*4882a593Smuzhiyun  * Server-side protocol handling for GrabKey request.
5500*4882a593Smuzhiyun  *
5501*4882a593Smuzhiyun  * Creates a grab for the client's keyboard and adds it to the list of passive
5502*4882a593Smuzhiyun  * grabs.
5503*4882a593Smuzhiyun  */
5504*4882a593Smuzhiyun int
ProcGrabKey(ClientPtr client)5505*4882a593Smuzhiyun ProcGrabKey(ClientPtr client)
5506*4882a593Smuzhiyun {
5507*4882a593Smuzhiyun     WindowPtr pWin;
5508*4882a593Smuzhiyun 
5509*4882a593Smuzhiyun     REQUEST(xGrabKeyReq);
5510*4882a593Smuzhiyun     GrabPtr grab;
5511*4882a593Smuzhiyun     DeviceIntPtr keybd = PickKeyboard(client);
5512*4882a593Smuzhiyun     int rc;
5513*4882a593Smuzhiyun     GrabParameters param;
5514*4882a593Smuzhiyun     GrabMask mask;
5515*4882a593Smuzhiyun 
5516*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xGrabKeyReq);
5517*4882a593Smuzhiyun 
5518*4882a593Smuzhiyun     param = (GrabParameters) {
5519*4882a593Smuzhiyun         .grabtype = CORE,
5520*4882a593Smuzhiyun         .ownerEvents = stuff->ownerEvents,
5521*4882a593Smuzhiyun         .this_device_mode = stuff->keyboardMode,
5522*4882a593Smuzhiyun         .other_devices_mode = stuff->pointerMode,
5523*4882a593Smuzhiyun         .modifiers = stuff->modifiers
5524*4882a593Smuzhiyun     };
5525*4882a593Smuzhiyun 
5526*4882a593Smuzhiyun     rc = CheckGrabValues(client, &param);
5527*4882a593Smuzhiyun     if (rc != Success)
5528*4882a593Smuzhiyun         return rc;
5529*4882a593Smuzhiyun 
5530*4882a593Smuzhiyun     if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) ||
5531*4882a593Smuzhiyun          (stuff->key < keybd->key->xkbInfo->desc->min_key_code))
5532*4882a593Smuzhiyun         && (stuff->key != AnyKey)) {
5533*4882a593Smuzhiyun         client->errorValue = stuff->key;
5534*4882a593Smuzhiyun         return BadValue;
5535*4882a593Smuzhiyun     }
5536*4882a593Smuzhiyun     rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess);
5537*4882a593Smuzhiyun     if (rc != Success)
5538*4882a593Smuzhiyun         return rc;
5539*4882a593Smuzhiyun 
5540*4882a593Smuzhiyun     mask.core = (KeyPressMask | KeyReleaseMask);
5541*4882a593Smuzhiyun 
5542*4882a593Smuzhiyun     grab = CreateGrab(client->index, keybd, keybd, pWin, CORE, &mask,
5543*4882a593Smuzhiyun                       &param, KeyPress, stuff->key, NullWindow, NullCursor);
5544*4882a593Smuzhiyun     if (!grab)
5545*4882a593Smuzhiyun         return BadAlloc;
5546*4882a593Smuzhiyun     return AddPassiveGrabToList(client, grab);
5547*4882a593Smuzhiyun }
5548*4882a593Smuzhiyun 
5549*4882a593Smuzhiyun /**
5550*4882a593Smuzhiyun  * Server-side protocol handling for GrabButton request.
5551*4882a593Smuzhiyun  *
5552*4882a593Smuzhiyun  * Creates a grab for the client's ClientPointer and adds it as a passive grab
5553*4882a593Smuzhiyun  * to the list.
5554*4882a593Smuzhiyun  */
5555*4882a593Smuzhiyun int
ProcGrabButton(ClientPtr client)5556*4882a593Smuzhiyun ProcGrabButton(ClientPtr client)
5557*4882a593Smuzhiyun {
5558*4882a593Smuzhiyun     WindowPtr pWin, confineTo;
5559*4882a593Smuzhiyun 
5560*4882a593Smuzhiyun     REQUEST(xGrabButtonReq);
5561*4882a593Smuzhiyun     CursorPtr cursor;
5562*4882a593Smuzhiyun     GrabPtr grab;
5563*4882a593Smuzhiyun     DeviceIntPtr ptr, modifierDevice;
5564*4882a593Smuzhiyun     Mask access_mode = DixGrabAccess;
5565*4882a593Smuzhiyun     GrabMask mask;
5566*4882a593Smuzhiyun     GrabParameters param;
5567*4882a593Smuzhiyun     int rc;
5568*4882a593Smuzhiyun 
5569*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xGrabButtonReq);
5570*4882a593Smuzhiyun     UpdateCurrentTime();
5571*4882a593Smuzhiyun     if ((stuff->pointerMode != GrabModeSync) &&
5572*4882a593Smuzhiyun         (stuff->pointerMode != GrabModeAsync)) {
5573*4882a593Smuzhiyun         client->errorValue = stuff->pointerMode;
5574*4882a593Smuzhiyun         return BadValue;
5575*4882a593Smuzhiyun     }
5576*4882a593Smuzhiyun     if ((stuff->keyboardMode != GrabModeSync) &&
5577*4882a593Smuzhiyun         (stuff->keyboardMode != GrabModeAsync)) {
5578*4882a593Smuzhiyun         client->errorValue = stuff->keyboardMode;
5579*4882a593Smuzhiyun         return BadValue;
5580*4882a593Smuzhiyun     }
5581*4882a593Smuzhiyun     if ((stuff->modifiers != AnyModifier) &&
5582*4882a593Smuzhiyun         (stuff->modifiers & ~AllModifiersMask)) {
5583*4882a593Smuzhiyun         client->errorValue = stuff->modifiers;
5584*4882a593Smuzhiyun         return BadValue;
5585*4882a593Smuzhiyun     }
5586*4882a593Smuzhiyun     if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) {
5587*4882a593Smuzhiyun         client->errorValue = stuff->ownerEvents;
5588*4882a593Smuzhiyun         return BadValue;
5589*4882a593Smuzhiyun     }
5590*4882a593Smuzhiyun     if (stuff->eventMask & ~PointerGrabMask) {
5591*4882a593Smuzhiyun         client->errorValue = stuff->eventMask;
5592*4882a593Smuzhiyun         return BadValue;
5593*4882a593Smuzhiyun     }
5594*4882a593Smuzhiyun     rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess);
5595*4882a593Smuzhiyun     if (rc != Success)
5596*4882a593Smuzhiyun         return rc;
5597*4882a593Smuzhiyun     if (stuff->confineTo == None)
5598*4882a593Smuzhiyun         confineTo = NullWindow;
5599*4882a593Smuzhiyun     else {
5600*4882a593Smuzhiyun         rc = dixLookupWindow(&confineTo, stuff->confineTo, client,
5601*4882a593Smuzhiyun                              DixSetAttrAccess);
5602*4882a593Smuzhiyun         if (rc != Success)
5603*4882a593Smuzhiyun             return rc;
5604*4882a593Smuzhiyun     }
5605*4882a593Smuzhiyun     if (stuff->cursor == None)
5606*4882a593Smuzhiyun         cursor = NullCursor;
5607*4882a593Smuzhiyun     else {
5608*4882a593Smuzhiyun         rc = dixLookupResourceByType((void **) &cursor, stuff->cursor,
5609*4882a593Smuzhiyun                                      RT_CURSOR, client, DixUseAccess);
5610*4882a593Smuzhiyun         if (rc != Success) {
5611*4882a593Smuzhiyun             client->errorValue = stuff->cursor;
5612*4882a593Smuzhiyun             return rc;
5613*4882a593Smuzhiyun         }
5614*4882a593Smuzhiyun         access_mode |= DixForceAccess;
5615*4882a593Smuzhiyun     }
5616*4882a593Smuzhiyun 
5617*4882a593Smuzhiyun     ptr = PickPointer(client);
5618*4882a593Smuzhiyun     modifierDevice = GetMaster(ptr, MASTER_KEYBOARD);
5619*4882a593Smuzhiyun     if (stuff->pointerMode == GrabModeSync ||
5620*4882a593Smuzhiyun         stuff->keyboardMode == GrabModeSync)
5621*4882a593Smuzhiyun         access_mode |= DixFreezeAccess;
5622*4882a593Smuzhiyun     rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, access_mode);
5623*4882a593Smuzhiyun     if (rc != Success)
5624*4882a593Smuzhiyun         return rc;
5625*4882a593Smuzhiyun 
5626*4882a593Smuzhiyun     param = (GrabParameters) {
5627*4882a593Smuzhiyun         .grabtype = CORE,
5628*4882a593Smuzhiyun         .ownerEvents = stuff->ownerEvents,
5629*4882a593Smuzhiyun         .this_device_mode = stuff->keyboardMode,
5630*4882a593Smuzhiyun         .other_devices_mode = stuff->pointerMode,
5631*4882a593Smuzhiyun         .modifiers = stuff->modifiers
5632*4882a593Smuzhiyun     };
5633*4882a593Smuzhiyun 
5634*4882a593Smuzhiyun     mask.core = stuff->eventMask;
5635*4882a593Smuzhiyun 
5636*4882a593Smuzhiyun     grab = CreateGrab(client->index, ptr, modifierDevice, pWin,
5637*4882a593Smuzhiyun                       CORE, &mask, &param, ButtonPress,
5638*4882a593Smuzhiyun                       stuff->button, confineTo, cursor);
5639*4882a593Smuzhiyun     if (!grab)
5640*4882a593Smuzhiyun         return BadAlloc;
5641*4882a593Smuzhiyun     return AddPassiveGrabToList(client, grab);
5642*4882a593Smuzhiyun }
5643*4882a593Smuzhiyun 
5644*4882a593Smuzhiyun /**
5645*4882a593Smuzhiyun  * Server-side protocol handling for UngrabButton request.
5646*4882a593Smuzhiyun  *
5647*4882a593Smuzhiyun  * Deletes a passive grab on the client's ClientPointer from the list.
5648*4882a593Smuzhiyun  */
5649*4882a593Smuzhiyun int
ProcUngrabButton(ClientPtr client)5650*4882a593Smuzhiyun ProcUngrabButton(ClientPtr client)
5651*4882a593Smuzhiyun {
5652*4882a593Smuzhiyun     REQUEST(xUngrabButtonReq);
5653*4882a593Smuzhiyun     WindowPtr pWin;
5654*4882a593Smuzhiyun     GrabPtr tempGrab;
5655*4882a593Smuzhiyun     int rc;
5656*4882a593Smuzhiyun     DeviceIntPtr ptr;
5657*4882a593Smuzhiyun 
5658*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xUngrabButtonReq);
5659*4882a593Smuzhiyun     UpdateCurrentTime();
5660*4882a593Smuzhiyun     if ((stuff->modifiers != AnyModifier) &&
5661*4882a593Smuzhiyun         (stuff->modifiers & ~AllModifiersMask)) {
5662*4882a593Smuzhiyun         client->errorValue = stuff->modifiers;
5663*4882a593Smuzhiyun         return BadValue;
5664*4882a593Smuzhiyun     }
5665*4882a593Smuzhiyun     rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess);
5666*4882a593Smuzhiyun     if (rc != Success)
5667*4882a593Smuzhiyun         return rc;
5668*4882a593Smuzhiyun 
5669*4882a593Smuzhiyun     ptr = PickPointer(client);
5670*4882a593Smuzhiyun 
5671*4882a593Smuzhiyun     tempGrab = AllocGrab(NULL);
5672*4882a593Smuzhiyun     if (!tempGrab)
5673*4882a593Smuzhiyun         return BadAlloc;
5674*4882a593Smuzhiyun     tempGrab->resource = client->clientAsMask;
5675*4882a593Smuzhiyun     tempGrab->device = ptr;
5676*4882a593Smuzhiyun     tempGrab->window = pWin;
5677*4882a593Smuzhiyun     tempGrab->modifiersDetail.exact = stuff->modifiers;
5678*4882a593Smuzhiyun     tempGrab->modifiersDetail.pMask = NULL;
5679*4882a593Smuzhiyun     tempGrab->modifierDevice = GetMaster(ptr, MASTER_KEYBOARD);
5680*4882a593Smuzhiyun     tempGrab->type = ButtonPress;
5681*4882a593Smuzhiyun     tempGrab->detail.exact = stuff->button;
5682*4882a593Smuzhiyun     tempGrab->grabtype = CORE;
5683*4882a593Smuzhiyun     tempGrab->detail.pMask = NULL;
5684*4882a593Smuzhiyun     tempGrab->next = NULL;
5685*4882a593Smuzhiyun 
5686*4882a593Smuzhiyun     if (!DeletePassiveGrabFromList(tempGrab))
5687*4882a593Smuzhiyun         rc = BadAlloc;
5688*4882a593Smuzhiyun 
5689*4882a593Smuzhiyun     FreeGrab(tempGrab);
5690*4882a593Smuzhiyun     return rc;
5691*4882a593Smuzhiyun }
5692*4882a593Smuzhiyun 
5693*4882a593Smuzhiyun /**
5694*4882a593Smuzhiyun  * Deactivate any grab that may be on the window, remove the focus.
5695*4882a593Smuzhiyun  * Delete any XInput extension events from the window too. Does not change the
5696*4882a593Smuzhiyun  * window mask. Use just before the window is deleted.
5697*4882a593Smuzhiyun  *
5698*4882a593Smuzhiyun  * If freeResources is set, passive grabs on the window are deleted.
5699*4882a593Smuzhiyun  *
5700*4882a593Smuzhiyun  * @param pWin The window to delete events from.
5701*4882a593Smuzhiyun  * @param freeResources True if resources associated with the window should be
5702*4882a593Smuzhiyun  * deleted.
5703*4882a593Smuzhiyun  */
5704*4882a593Smuzhiyun void
DeleteWindowFromAnyEvents(WindowPtr pWin,Bool freeResources)5705*4882a593Smuzhiyun DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources)
5706*4882a593Smuzhiyun {
5707*4882a593Smuzhiyun     WindowPtr parent;
5708*4882a593Smuzhiyun     DeviceIntPtr mouse = inputInfo.pointer;
5709*4882a593Smuzhiyun     DeviceIntPtr keybd = inputInfo.keyboard;
5710*4882a593Smuzhiyun     FocusClassPtr focus;
5711*4882a593Smuzhiyun     OtherClientsPtr oc;
5712*4882a593Smuzhiyun     GrabPtr passive;
5713*4882a593Smuzhiyun     GrabPtr grab;
5714*4882a593Smuzhiyun 
5715*4882a593Smuzhiyun     /* Deactivate any grabs performed on this window, before making any
5716*4882a593Smuzhiyun        input focus changes. */
5717*4882a593Smuzhiyun     grab = mouse->deviceGrab.grab;
5718*4882a593Smuzhiyun     if (grab && ((grab->window == pWin) || (grab->confineTo == pWin)))
5719*4882a593Smuzhiyun         (*mouse->deviceGrab.DeactivateGrab) (mouse);
5720*4882a593Smuzhiyun 
5721*4882a593Smuzhiyun     /* Deactivating a keyboard grab should cause focus events. */
5722*4882a593Smuzhiyun     grab = keybd->deviceGrab.grab;
5723*4882a593Smuzhiyun     if (grab && (grab->window == pWin))
5724*4882a593Smuzhiyun         (*keybd->deviceGrab.DeactivateGrab) (keybd);
5725*4882a593Smuzhiyun 
5726*4882a593Smuzhiyun     /* And now the real devices */
5727*4882a593Smuzhiyun     for (mouse = inputInfo.devices; mouse; mouse = mouse->next) {
5728*4882a593Smuzhiyun         grab = mouse->deviceGrab.grab;
5729*4882a593Smuzhiyun         if (grab && ((grab->window == pWin) || (grab->confineTo == pWin)))
5730*4882a593Smuzhiyun             (*mouse->deviceGrab.DeactivateGrab) (mouse);
5731*4882a593Smuzhiyun     }
5732*4882a593Smuzhiyun 
5733*4882a593Smuzhiyun     for (keybd = inputInfo.devices; keybd; keybd = keybd->next) {
5734*4882a593Smuzhiyun         if (IsKeyboardDevice(keybd)) {
5735*4882a593Smuzhiyun             focus = keybd->focus;
5736*4882a593Smuzhiyun 
5737*4882a593Smuzhiyun             /* If the focus window is a root window (ie. has no parent)
5738*4882a593Smuzhiyun                then don't delete the focus from it. */
5739*4882a593Smuzhiyun 
5740*4882a593Smuzhiyun             if ((pWin == focus->win) && (pWin->parent != NullWindow)) {
5741*4882a593Smuzhiyun                 int focusEventMode = NotifyNormal;
5742*4882a593Smuzhiyun 
5743*4882a593Smuzhiyun                 /* If a grab is in progress, then alter the mode of focus events. */
5744*4882a593Smuzhiyun 
5745*4882a593Smuzhiyun                 if (keybd->deviceGrab.grab)
5746*4882a593Smuzhiyun                     focusEventMode = NotifyWhileGrabbed;
5747*4882a593Smuzhiyun 
5748*4882a593Smuzhiyun                 switch (focus->revert) {
5749*4882a593Smuzhiyun                 case RevertToNone:
5750*4882a593Smuzhiyun                     DoFocusEvents(keybd, pWin, NoneWin, focusEventMode);
5751*4882a593Smuzhiyun                     focus->win = NoneWin;
5752*4882a593Smuzhiyun                     focus->traceGood = 0;
5753*4882a593Smuzhiyun                     break;
5754*4882a593Smuzhiyun                 case RevertToParent:
5755*4882a593Smuzhiyun                     parent = pWin;
5756*4882a593Smuzhiyun                     do {
5757*4882a593Smuzhiyun                         parent = parent->parent;
5758*4882a593Smuzhiyun                         focus->traceGood--;
5759*4882a593Smuzhiyun                     } while (!parent->realized
5760*4882a593Smuzhiyun                     /* This would be a good protocol change -- windows being
5761*4882a593Smuzhiyun                        reparented during SaveSet processing would cause the
5762*4882a593Smuzhiyun                        focus to revert to the nearest enclosing window which
5763*4882a593Smuzhiyun                        will survive the death of the exiting client, instead
5764*4882a593Smuzhiyun                        of ending up reverting to a dying window and thence
5765*4882a593Smuzhiyun                        to None */
5766*4882a593Smuzhiyun #ifdef NOTDEF
5767*4882a593Smuzhiyun                              || wClient(parent)->clientGone
5768*4882a593Smuzhiyun #endif
5769*4882a593Smuzhiyun                         );
5770*4882a593Smuzhiyun                     if (!ActivateFocusInGrab(keybd, pWin, parent))
5771*4882a593Smuzhiyun                         DoFocusEvents(keybd, pWin, parent, focusEventMode);
5772*4882a593Smuzhiyun                     focus->win = parent;
5773*4882a593Smuzhiyun                     focus->revert = RevertToNone;
5774*4882a593Smuzhiyun                     break;
5775*4882a593Smuzhiyun                 case RevertToPointerRoot:
5776*4882a593Smuzhiyun                     if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin))
5777*4882a593Smuzhiyun                         DoFocusEvents(keybd, pWin, PointerRootWin,
5778*4882a593Smuzhiyun                                       focusEventMode);
5779*4882a593Smuzhiyun                     focus->win = PointerRootWin;
5780*4882a593Smuzhiyun                     focus->traceGood = 0;
5781*4882a593Smuzhiyun                     break;
5782*4882a593Smuzhiyun                 }
5783*4882a593Smuzhiyun             }
5784*4882a593Smuzhiyun         }
5785*4882a593Smuzhiyun 
5786*4882a593Smuzhiyun         if (IsPointerDevice(keybd)) {
5787*4882a593Smuzhiyun             if (keybd->valuator->motionHintWindow == pWin)
5788*4882a593Smuzhiyun                 keybd->valuator->motionHintWindow = NullWindow;
5789*4882a593Smuzhiyun         }
5790*4882a593Smuzhiyun     }
5791*4882a593Smuzhiyun 
5792*4882a593Smuzhiyun     if (freeResources) {
5793*4882a593Smuzhiyun         if (pWin->dontPropagate)
5794*4882a593Smuzhiyun             DontPropagateRefCnts[pWin->dontPropagate]--;
5795*4882a593Smuzhiyun         while ((oc = wOtherClients(pWin)))
5796*4882a593Smuzhiyun             FreeResource(oc->resource, RT_NONE);
5797*4882a593Smuzhiyun         while ((passive = wPassiveGrabs(pWin)))
5798*4882a593Smuzhiyun             FreeResource(passive->resource, RT_NONE);
5799*4882a593Smuzhiyun     }
5800*4882a593Smuzhiyun 
5801*4882a593Smuzhiyun     DeleteWindowFromAnyExtEvents(pWin, freeResources);
5802*4882a593Smuzhiyun }
5803*4882a593Smuzhiyun 
5804*4882a593Smuzhiyun /**
5805*4882a593Smuzhiyun  * Call this whenever some window at or below pWin has changed geometry. If
5806*4882a593Smuzhiyun  * there is a grab on the window, the cursor will be re-confined into the
5807*4882a593Smuzhiyun  * window.
5808*4882a593Smuzhiyun  */
5809*4882a593Smuzhiyun void
CheckCursorConfinement(WindowPtr pWin)5810*4882a593Smuzhiyun CheckCursorConfinement(WindowPtr pWin)
5811*4882a593Smuzhiyun {
5812*4882a593Smuzhiyun     GrabPtr grab;
5813*4882a593Smuzhiyun     WindowPtr confineTo;
5814*4882a593Smuzhiyun     DeviceIntPtr pDev;
5815*4882a593Smuzhiyun 
5816*4882a593Smuzhiyun #ifdef PANORAMIX
5817*4882a593Smuzhiyun     if (!noPanoramiXExtension && pWin->drawable.pScreen->myNum)
5818*4882a593Smuzhiyun         return;
5819*4882a593Smuzhiyun #endif
5820*4882a593Smuzhiyun 
5821*4882a593Smuzhiyun     for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
5822*4882a593Smuzhiyun         if (DevHasCursor(pDev)) {
5823*4882a593Smuzhiyun             grab = pDev->deviceGrab.grab;
5824*4882a593Smuzhiyun             if (grab && (confineTo = grab->confineTo)) {
5825*4882a593Smuzhiyun                 if (!BorderSizeNotEmpty(pDev, confineTo))
5826*4882a593Smuzhiyun                     (*pDev->deviceGrab.DeactivateGrab) (pDev);
5827*4882a593Smuzhiyun                 else if ((pWin == confineTo) || IsParent(pWin, confineTo))
5828*4882a593Smuzhiyun                     ConfineCursorToWindow(pDev, confineTo, TRUE, TRUE);
5829*4882a593Smuzhiyun             }
5830*4882a593Smuzhiyun         }
5831*4882a593Smuzhiyun     }
5832*4882a593Smuzhiyun }
5833*4882a593Smuzhiyun 
5834*4882a593Smuzhiyun Mask
EventMaskForClient(WindowPtr pWin,ClientPtr client)5835*4882a593Smuzhiyun EventMaskForClient(WindowPtr pWin, ClientPtr client)
5836*4882a593Smuzhiyun {
5837*4882a593Smuzhiyun     OtherClientsPtr other;
5838*4882a593Smuzhiyun 
5839*4882a593Smuzhiyun     if (wClient(pWin) == client)
5840*4882a593Smuzhiyun         return pWin->eventMask;
5841*4882a593Smuzhiyun     for (other = wOtherClients(pWin); other; other = other->next) {
5842*4882a593Smuzhiyun         if (SameClient(other, client))
5843*4882a593Smuzhiyun             return other->mask;
5844*4882a593Smuzhiyun     }
5845*4882a593Smuzhiyun     return 0;
5846*4882a593Smuzhiyun }
5847*4882a593Smuzhiyun 
5848*4882a593Smuzhiyun /**
5849*4882a593Smuzhiyun  * Server-side protocol handling for RecolorCursor request.
5850*4882a593Smuzhiyun  */
5851*4882a593Smuzhiyun int
ProcRecolorCursor(ClientPtr client)5852*4882a593Smuzhiyun ProcRecolorCursor(ClientPtr client)
5853*4882a593Smuzhiyun {
5854*4882a593Smuzhiyun     CursorPtr pCursor;
5855*4882a593Smuzhiyun     int rc, nscr;
5856*4882a593Smuzhiyun     ScreenPtr pscr;
5857*4882a593Smuzhiyun     Bool displayed;
5858*4882a593Smuzhiyun     SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite;
5859*4882a593Smuzhiyun 
5860*4882a593Smuzhiyun     REQUEST(xRecolorCursorReq);
5861*4882a593Smuzhiyun 
5862*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xRecolorCursorReq);
5863*4882a593Smuzhiyun     rc = dixLookupResourceByType((void **) &pCursor, stuff->cursor, RT_CURSOR,
5864*4882a593Smuzhiyun                                  client, DixWriteAccess);
5865*4882a593Smuzhiyun     if (rc != Success) {
5866*4882a593Smuzhiyun         client->errorValue = stuff->cursor;
5867*4882a593Smuzhiyun         return rc;
5868*4882a593Smuzhiyun     }
5869*4882a593Smuzhiyun 
5870*4882a593Smuzhiyun     pCursor->foreRed = stuff->foreRed;
5871*4882a593Smuzhiyun     pCursor->foreGreen = stuff->foreGreen;
5872*4882a593Smuzhiyun     pCursor->foreBlue = stuff->foreBlue;
5873*4882a593Smuzhiyun 
5874*4882a593Smuzhiyun     pCursor->backRed = stuff->backRed;
5875*4882a593Smuzhiyun     pCursor->backGreen = stuff->backGreen;
5876*4882a593Smuzhiyun     pCursor->backBlue = stuff->backBlue;
5877*4882a593Smuzhiyun 
5878*4882a593Smuzhiyun     for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
5879*4882a593Smuzhiyun         pscr = screenInfo.screens[nscr];
5880*4882a593Smuzhiyun #ifdef PANORAMIX
5881*4882a593Smuzhiyun         if (!noPanoramiXExtension)
5882*4882a593Smuzhiyun             displayed = (pscr == pSprite->screen);
5883*4882a593Smuzhiyun         else
5884*4882a593Smuzhiyun #endif
5885*4882a593Smuzhiyun             displayed = (pscr == pSprite->hotPhys.pScreen);
5886*4882a593Smuzhiyun         (*pscr->RecolorCursor) (PickPointer(client), pscr, pCursor,
5887*4882a593Smuzhiyun                                 (pCursor == pSprite->current) && displayed);
5888*4882a593Smuzhiyun     }
5889*4882a593Smuzhiyun     return Success;
5890*4882a593Smuzhiyun }
5891*4882a593Smuzhiyun 
5892*4882a593Smuzhiyun /**
5893*4882a593Smuzhiyun  * Write the given events to a client, swapping the byte order if necessary.
5894*4882a593Smuzhiyun  * To swap the byte ordering, a callback is called that has to be set up for
5895*4882a593Smuzhiyun  * the given event type.
5896*4882a593Smuzhiyun  *
5897*4882a593Smuzhiyun  * In the case of DeviceMotionNotify trailed by DeviceValuators, the events
5898*4882a593Smuzhiyun  * can be more than one. Usually it's just one event.
5899*4882a593Smuzhiyun  *
5900*4882a593Smuzhiyun  * Do not modify the event structure passed in. See comment below.
5901*4882a593Smuzhiyun  *
5902*4882a593Smuzhiyun  * @param pClient Client to send events to.
5903*4882a593Smuzhiyun  * @param count Number of events.
5904*4882a593Smuzhiyun  * @param events The event list.
5905*4882a593Smuzhiyun  */
5906*4882a593Smuzhiyun void
WriteEventsToClient(ClientPtr pClient,int count,xEvent * events)5907*4882a593Smuzhiyun WriteEventsToClient(ClientPtr pClient, int count, xEvent *events)
5908*4882a593Smuzhiyun {
5909*4882a593Smuzhiyun #ifdef PANORAMIX
5910*4882a593Smuzhiyun     xEvent eventCopy;
5911*4882a593Smuzhiyun #endif
5912*4882a593Smuzhiyun     xEvent *eventTo, *eventFrom;
5913*4882a593Smuzhiyun     int i, eventlength = sizeof(xEvent);
5914*4882a593Smuzhiyun 
5915*4882a593Smuzhiyun     if (!pClient || pClient == serverClient || pClient->clientGone)
5916*4882a593Smuzhiyun         return;
5917*4882a593Smuzhiyun 
5918*4882a593Smuzhiyun     for (i = 0; i < count; i++)
5919*4882a593Smuzhiyun         if ((events[i].u.u.type & 0x7f) != KeymapNotify)
5920*4882a593Smuzhiyun             events[i].u.u.sequenceNumber = pClient->sequence;
5921*4882a593Smuzhiyun 
5922*4882a593Smuzhiyun     /* Let XKB rewrite the state, as it depends on client preferences. */
5923*4882a593Smuzhiyun     XkbFilterEvents(pClient, count, events);
5924*4882a593Smuzhiyun 
5925*4882a593Smuzhiyun #ifdef PANORAMIX
5926*4882a593Smuzhiyun     if (!noPanoramiXExtension &&
5927*4882a593Smuzhiyun         (screenInfo.screens[0]->x || screenInfo.screens[0]->y)) {
5928*4882a593Smuzhiyun         switch (events->u.u.type) {
5929*4882a593Smuzhiyun         case MotionNotify:
5930*4882a593Smuzhiyun         case ButtonPress:
5931*4882a593Smuzhiyun         case ButtonRelease:
5932*4882a593Smuzhiyun         case KeyPress:
5933*4882a593Smuzhiyun         case KeyRelease:
5934*4882a593Smuzhiyun         case EnterNotify:
5935*4882a593Smuzhiyun         case LeaveNotify:
5936*4882a593Smuzhiyun             /*
5937*4882a593Smuzhiyun                When multiple clients want the same event DeliverEventsToWindow
5938*4882a593Smuzhiyun                passes the same event structure multiple times so we can't
5939*4882a593Smuzhiyun                modify the one passed to us
5940*4882a593Smuzhiyun              */
5941*4882a593Smuzhiyun             count = 1;          /* should always be 1 */
5942*4882a593Smuzhiyun             memcpy(&eventCopy, events, sizeof(xEvent));
5943*4882a593Smuzhiyun             eventCopy.u.keyButtonPointer.rootX += screenInfo.screens[0]->x;
5944*4882a593Smuzhiyun             eventCopy.u.keyButtonPointer.rootY += screenInfo.screens[0]->y;
5945*4882a593Smuzhiyun             if (eventCopy.u.keyButtonPointer.event ==
5946*4882a593Smuzhiyun                 eventCopy.u.keyButtonPointer.root) {
5947*4882a593Smuzhiyun                 eventCopy.u.keyButtonPointer.eventX += screenInfo.screens[0]->x;
5948*4882a593Smuzhiyun                 eventCopy.u.keyButtonPointer.eventY += screenInfo.screens[0]->y;
5949*4882a593Smuzhiyun             }
5950*4882a593Smuzhiyun             events = &eventCopy;
5951*4882a593Smuzhiyun             break;
5952*4882a593Smuzhiyun         default:
5953*4882a593Smuzhiyun             break;
5954*4882a593Smuzhiyun         }
5955*4882a593Smuzhiyun     }
5956*4882a593Smuzhiyun #endif
5957*4882a593Smuzhiyun 
5958*4882a593Smuzhiyun     if (EventCallback) {
5959*4882a593Smuzhiyun         EventInfoRec eventinfo;
5960*4882a593Smuzhiyun 
5961*4882a593Smuzhiyun         eventinfo.client = pClient;
5962*4882a593Smuzhiyun         eventinfo.events = events;
5963*4882a593Smuzhiyun         eventinfo.count = count;
5964*4882a593Smuzhiyun         CallCallbacks(&EventCallback, (void *) &eventinfo);
5965*4882a593Smuzhiyun     }
5966*4882a593Smuzhiyun #ifdef XSERVER_DTRACE
5967*4882a593Smuzhiyun     if (XSERVER_SEND_EVENT_ENABLED()) {
5968*4882a593Smuzhiyun         for (i = 0; i < count; i++) {
5969*4882a593Smuzhiyun             XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]);
5970*4882a593Smuzhiyun         }
5971*4882a593Smuzhiyun     }
5972*4882a593Smuzhiyun #endif
5973*4882a593Smuzhiyun     /* Just a safety check to make sure we only have one GenericEvent, it just
5974*4882a593Smuzhiyun      * makes things easier for me right now. (whot) */
5975*4882a593Smuzhiyun     for (i = 1; i < count; i++) {
5976*4882a593Smuzhiyun         if (events[i].u.u.type == GenericEvent) {
5977*4882a593Smuzhiyun             ErrorF("[dix] TryClientEvents: Only one GenericEvent at a time.\n");
5978*4882a593Smuzhiyun             return;
5979*4882a593Smuzhiyun         }
5980*4882a593Smuzhiyun     }
5981*4882a593Smuzhiyun 
5982*4882a593Smuzhiyun     if (events->u.u.type == GenericEvent) {
5983*4882a593Smuzhiyun         eventlength += ((xGenericEvent *) events)->length * 4;
5984*4882a593Smuzhiyun     }
5985*4882a593Smuzhiyun 
5986*4882a593Smuzhiyun     if (pClient->swapped) {
5987*4882a593Smuzhiyun         if (eventlength > swapEventLen) {
5988*4882a593Smuzhiyun             swapEventLen = eventlength;
5989*4882a593Smuzhiyun             swapEvent = realloc(swapEvent, swapEventLen);
5990*4882a593Smuzhiyun             if (!swapEvent) {
5991*4882a593Smuzhiyun                 FatalError("WriteEventsToClient: Out of memory.\n");
5992*4882a593Smuzhiyun                 return;
5993*4882a593Smuzhiyun             }
5994*4882a593Smuzhiyun         }
5995*4882a593Smuzhiyun 
5996*4882a593Smuzhiyun         for (i = 0; i < count; i++) {
5997*4882a593Smuzhiyun             eventFrom = &events[i];
5998*4882a593Smuzhiyun             eventTo = swapEvent;
5999*4882a593Smuzhiyun 
6000*4882a593Smuzhiyun             /* Remember to strip off the leading bit of type in case
6001*4882a593Smuzhiyun                this event was sent with "SendEvent." */
6002*4882a593Smuzhiyun             (*EventSwapVector[eventFrom->u.u.type & 0177])
6003*4882a593Smuzhiyun                 (eventFrom, eventTo);
6004*4882a593Smuzhiyun 
6005*4882a593Smuzhiyun             WriteToClient(pClient, eventlength, eventTo);
6006*4882a593Smuzhiyun         }
6007*4882a593Smuzhiyun     }
6008*4882a593Smuzhiyun     else {
6009*4882a593Smuzhiyun         /* only one GenericEvent, remember? that means either count is 1 and
6010*4882a593Smuzhiyun          * eventlength is arbitrary or eventlength is 32 and count doesn't
6011*4882a593Smuzhiyun          * matter. And we're all set. Woohoo. */
6012*4882a593Smuzhiyun         WriteToClient(pClient, count * eventlength, events);
6013*4882a593Smuzhiyun     }
6014*4882a593Smuzhiyun }
6015*4882a593Smuzhiyun 
6016*4882a593Smuzhiyun /*
6017*4882a593Smuzhiyun  * Set the client pointer for the given client.
6018*4882a593Smuzhiyun  *
6019*4882a593Smuzhiyun  * A client can have exactly one ClientPointer. Each time a
6020*4882a593Smuzhiyun  * request/reply/event is processed and the choice of devices is ambiguous
6021*4882a593Smuzhiyun  * (e.g. QueryPointer request), the server will pick the ClientPointer (see
6022*4882a593Smuzhiyun  * PickPointer()).
6023*4882a593Smuzhiyun  * If a keyboard is needed, the first keyboard paired with the CP is used.
6024*4882a593Smuzhiyun  */
6025*4882a593Smuzhiyun int
SetClientPointer(ClientPtr client,DeviceIntPtr device)6026*4882a593Smuzhiyun SetClientPointer(ClientPtr client, DeviceIntPtr device)
6027*4882a593Smuzhiyun {
6028*4882a593Smuzhiyun     int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess);
6029*4882a593Smuzhiyun 
6030*4882a593Smuzhiyun     if (rc != Success)
6031*4882a593Smuzhiyun         return rc;
6032*4882a593Smuzhiyun 
6033*4882a593Smuzhiyun     if (!IsMaster(device)) {
6034*4882a593Smuzhiyun         ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n");
6035*4882a593Smuzhiyun         return BadDevice;
6036*4882a593Smuzhiyun     }
6037*4882a593Smuzhiyun     else if (!device->spriteInfo->spriteOwner) {
6038*4882a593Smuzhiyun         ErrorF("[dix] Device %d does not have a sprite. "
6039*4882a593Smuzhiyun                "Cannot be ClientPointer\n", device->id);
6040*4882a593Smuzhiyun         return BadDevice;
6041*4882a593Smuzhiyun     }
6042*4882a593Smuzhiyun     client->clientPtr = device;
6043*4882a593Smuzhiyun     return Success;
6044*4882a593Smuzhiyun }
6045*4882a593Smuzhiyun 
6046*4882a593Smuzhiyun /* PickPointer will pick an appropriate pointer for the given client.
6047*4882a593Smuzhiyun  *
6048*4882a593Smuzhiyun  * An "appropriate device" is (in order of priority):
6049*4882a593Smuzhiyun  *  1) A device the given client has a core grab on.
6050*4882a593Smuzhiyun  *  2) A device set as ClientPointer for the given client.
6051*4882a593Smuzhiyun  *  3) The first master device.
6052*4882a593Smuzhiyun  */
6053*4882a593Smuzhiyun DeviceIntPtr
PickPointer(ClientPtr client)6054*4882a593Smuzhiyun PickPointer(ClientPtr client)
6055*4882a593Smuzhiyun {
6056*4882a593Smuzhiyun     DeviceIntPtr it = inputInfo.devices;
6057*4882a593Smuzhiyun 
6058*4882a593Smuzhiyun     /* First, check if the client currently has a grab on a device. Even
6059*4882a593Smuzhiyun      * keyboards count. */
6060*4882a593Smuzhiyun     for (it = inputInfo.devices; it; it = it->next) {
6061*4882a593Smuzhiyun         GrabPtr grab = it->deviceGrab.grab;
6062*4882a593Smuzhiyun 
6063*4882a593Smuzhiyun         if (grab && grab->grabtype == CORE && SameClient(grab, client)) {
6064*4882a593Smuzhiyun             it = GetMaster(it, MASTER_POINTER);
6065*4882a593Smuzhiyun             return it;          /* Always return a core grabbed device */
6066*4882a593Smuzhiyun         }
6067*4882a593Smuzhiyun     }
6068*4882a593Smuzhiyun 
6069*4882a593Smuzhiyun     if (!client->clientPtr) {
6070*4882a593Smuzhiyun         it = inputInfo.devices;
6071*4882a593Smuzhiyun         while (it) {
6072*4882a593Smuzhiyun             if (IsMaster(it) && it->spriteInfo->spriteOwner) {
6073*4882a593Smuzhiyun                 client->clientPtr = it;
6074*4882a593Smuzhiyun                 break;
6075*4882a593Smuzhiyun             }
6076*4882a593Smuzhiyun             it = it->next;
6077*4882a593Smuzhiyun         }
6078*4882a593Smuzhiyun     }
6079*4882a593Smuzhiyun     return client->clientPtr;
6080*4882a593Smuzhiyun }
6081*4882a593Smuzhiyun 
6082*4882a593Smuzhiyun /* PickKeyboard will pick an appropriate keyboard for the given client by
6083*4882a593Smuzhiyun  * searching the list of devices for the keyboard device that is paired with
6084*4882a593Smuzhiyun  * the client's pointer.
6085*4882a593Smuzhiyun  */
6086*4882a593Smuzhiyun DeviceIntPtr
PickKeyboard(ClientPtr client)6087*4882a593Smuzhiyun PickKeyboard(ClientPtr client)
6088*4882a593Smuzhiyun {
6089*4882a593Smuzhiyun     DeviceIntPtr ptr = PickPointer(client);
6090*4882a593Smuzhiyun     DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD);
6091*4882a593Smuzhiyun 
6092*4882a593Smuzhiyun     if (!kbd) {
6093*4882a593Smuzhiyun         ErrorF("[dix] ClientPointer not paired with a keyboard. This "
6094*4882a593Smuzhiyun                "is a bug.\n");
6095*4882a593Smuzhiyun     }
6096*4882a593Smuzhiyun 
6097*4882a593Smuzhiyun     return kbd;
6098*4882a593Smuzhiyun }
6099*4882a593Smuzhiyun 
6100*4882a593Smuzhiyun /* A client that has one or more core grabs does not get core events from
6101*4882a593Smuzhiyun  * devices it does not have a grab on. Legacy applications behave bad
6102*4882a593Smuzhiyun  * otherwise because they are not used to it and the events interfere.
6103*4882a593Smuzhiyun  * Only applies for core events.
6104*4882a593Smuzhiyun  *
6105*4882a593Smuzhiyun  * Return true if a core event from the device would interfere and should not
6106*4882a593Smuzhiyun  * be delivered.
6107*4882a593Smuzhiyun  */
6108*4882a593Smuzhiyun Bool
IsInterferingGrab(ClientPtr client,DeviceIntPtr dev,xEvent * event)6109*4882a593Smuzhiyun IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent *event)
6110*4882a593Smuzhiyun {
6111*4882a593Smuzhiyun     DeviceIntPtr it = inputInfo.devices;
6112*4882a593Smuzhiyun 
6113*4882a593Smuzhiyun     switch (event->u.u.type) {
6114*4882a593Smuzhiyun     case KeyPress:
6115*4882a593Smuzhiyun     case KeyRelease:
6116*4882a593Smuzhiyun     case ButtonPress:
6117*4882a593Smuzhiyun     case ButtonRelease:
6118*4882a593Smuzhiyun     case MotionNotify:
6119*4882a593Smuzhiyun     case EnterNotify:
6120*4882a593Smuzhiyun     case LeaveNotify:
6121*4882a593Smuzhiyun         break;
6122*4882a593Smuzhiyun     default:
6123*4882a593Smuzhiyun         return FALSE;
6124*4882a593Smuzhiyun     }
6125*4882a593Smuzhiyun 
6126*4882a593Smuzhiyun     if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client))
6127*4882a593Smuzhiyun         return FALSE;
6128*4882a593Smuzhiyun 
6129*4882a593Smuzhiyun     while (it) {
6130*4882a593Smuzhiyun         if (it != dev) {
6131*4882a593Smuzhiyun             if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client)
6132*4882a593Smuzhiyun                 && !it->deviceGrab.fromPassiveGrab) {
6133*4882a593Smuzhiyun                 if ((IsPointerDevice(it) && IsPointerDevice(dev)) ||
6134*4882a593Smuzhiyun                     (IsKeyboardDevice(it) && IsKeyboardDevice(dev)))
6135*4882a593Smuzhiyun                     return TRUE;
6136*4882a593Smuzhiyun             }
6137*4882a593Smuzhiyun         }
6138*4882a593Smuzhiyun         it = it->next;
6139*4882a593Smuzhiyun     }
6140*4882a593Smuzhiyun 
6141*4882a593Smuzhiyun     return FALSE;
6142*4882a593Smuzhiyun }
6143*4882a593Smuzhiyun 
6144*4882a593Smuzhiyun /* PointerBarrier events are only delivered to the client that created that
6145*4882a593Smuzhiyun  * barrier */
6146*4882a593Smuzhiyun static Bool
IsWrongPointerBarrierClient(ClientPtr client,DeviceIntPtr dev,xEvent * event)6147*4882a593Smuzhiyun IsWrongPointerBarrierClient(ClientPtr client, DeviceIntPtr dev, xEvent *event)
6148*4882a593Smuzhiyun {
6149*4882a593Smuzhiyun     xXIBarrierEvent *ev = (xXIBarrierEvent*)event;
6150*4882a593Smuzhiyun 
6151*4882a593Smuzhiyun     if (ev->type != GenericEvent || ev->extension != IReqCode)
6152*4882a593Smuzhiyun         return FALSE;
6153*4882a593Smuzhiyun 
6154*4882a593Smuzhiyun     if (ev->evtype != XI_BarrierHit && ev->evtype != XI_BarrierLeave)
6155*4882a593Smuzhiyun         return FALSE;
6156*4882a593Smuzhiyun 
6157*4882a593Smuzhiyun     return client->index != CLIENT_ID(ev->barrier);
6158*4882a593Smuzhiyun }
6159