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