1 /************************************************************
2 
3 Copyright 1989, 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 1989 by Hewlett-Packard Company, Palo Alto, California.
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 Hewlett-Packard not be
34 used in advertising or publicity pertaining to distribution of the
35 software without specific, written prior permission.
36 
37 HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 HEWLETT-PACKARD 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 /*
48  * Copyright © 2010 Collabora Ltd.
49  * Copyright © 2011 Red Hat, Inc.
50  *
51  * Permission is hereby granted, free of charge, to any person obtaining a
52  * copy of this software and associated documentation files (the "Software"),
53  * to deal in the Software without restriction, including without limitation
54  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
55  * and/or sell copies of the Software, and to permit persons to whom the
56  * Software is furnished to do so, subject to the following conditions:
57  *
58  * The above copyright notice and this permission notice (including the next
59  * paragraph) shall be included in all copies or substantial portions of the
60  * Software.
61  *
62  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
63  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
64  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
65  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
66  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
67  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
68  * DEALINGS IN THE SOFTWARE.
69  *
70  * Author: Daniel Stone <daniel@fooishbar.org>
71  */
72 
73 /********************************************************************
74  *
75  *  Routines to register and initialize extension input devices.
76  *  This also contains ProcessOtherEvent, the routine called from DDX
77  *  to route extension events.
78  *
79  */
80 
81 #ifdef HAVE_DIX_CONFIG_H
82 #include <dix-config.h>
83 #endif
84 
85 #include "inputstr.h"
86 #include <X11/X.h>
87 #include <X11/Xproto.h>
88 #include <X11/extensions/XI.h>
89 #include <X11/extensions/XIproto.h>
90 #include <X11/extensions/XI2proto.h>
91 #include <X11/extensions/geproto.h>
92 #include "windowstr.h"
93 #include "miscstruct.h"
94 #include "region.h"
95 #include "exevents.h"
96 #include "extnsionst.h"
97 #include "exglobals.h"
98 #include "dixevents.h"          /* DeliverFocusedEvent */
99 #include "dixgrabs.h"           /* CreateGrab() */
100 #include "scrnintstr.h"
101 #include "listdev.h"            /* for CopySwapXXXClass */
102 #include "xace.h"
103 #include "xiquerydevice.h"      /* For List*Info */
104 #include "eventconvert.h"
105 #include "eventstr.h"
106 #include "inpututils.h"
107 #include "mi.h"
108 
109 #include <X11/extensions/XKBproto.h>
110 #include "xkbsrv.h"
111 
112 #define WID(w) ((w) ? ((w)->drawable.id) : 0)
113 #define AllModifiersMask ( \
114 	ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \
115 	Mod3Mask | Mod4Mask | Mod5Mask )
116 #define AllButtonsMask ( \
117 	Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )
118 
119 Bool ShouldFreeInputMasks(WindowPtr /* pWin */ ,
120                           Bool  /* ignoreSelectedEvents */
121     );
122 static Bool MakeInputMasks(WindowPtr    /* pWin */
123     );
124 
125 /*
126  * Only let the given client know of core events which will affect its
127  * interpretation of input events, if the client's ClientPointer (or the
128  * paired keyboard) is the current device.
129  */
130 int
XIShouldNotify(ClientPtr client,DeviceIntPtr dev)131 XIShouldNotify(ClientPtr client, DeviceIntPtr dev)
132 {
133     DeviceIntPtr current_ptr = PickPointer(client);
134     DeviceIntPtr current_kbd = GetMaster(current_ptr, KEYBOARD_OR_FLOAT);
135 
136     if (dev == current_kbd || dev == current_ptr)
137         return 1;
138 
139     return 0;
140 }
141 
142 Bool
IsPointerEvent(InternalEvent * event)143 IsPointerEvent(InternalEvent *event)
144 {
145     switch (event->any.type) {
146     case ET_ButtonPress:
147     case ET_ButtonRelease:
148     case ET_Motion:
149         /* XXX: enter/leave ?? */
150         return TRUE;
151     default:
152         break;
153     }
154     return FALSE;
155 }
156 
157 Bool
IsTouchEvent(InternalEvent * event)158 IsTouchEvent(InternalEvent *event)
159 {
160     switch (event->any.type) {
161     case ET_TouchBegin:
162     case ET_TouchUpdate:
163     case ET_TouchEnd:
164         return TRUE;
165     default:
166         break;
167     }
168     return FALSE;
169 }
170 
171 /**
172  * @return the device matching the deviceid of the device set in the event, or
173  * NULL if the event is not an XInput event.
174  */
175 DeviceIntPtr
XIGetDevice(xEvent * xE)176 XIGetDevice(xEvent *xE)
177 {
178     DeviceIntPtr pDev = NULL;
179 
180     if (xE->u.u.type == DeviceButtonPress ||
181         xE->u.u.type == DeviceButtonRelease ||
182         xE->u.u.type == DeviceMotionNotify ||
183         xE->u.u.type == ProximityIn ||
184         xE->u.u.type == ProximityOut || xE->u.u.type == DevicePropertyNotify) {
185         int rc;
186         int id;
187 
188         id = ((deviceKeyButtonPointer *) xE)->deviceid & ~MORE_EVENTS;
189 
190         rc = dixLookupDevice(&pDev, id, serverClient, DixUnknownAccess);
191         if (rc != Success)
192             ErrorF("[dix] XIGetDevice failed on XACE restrictions (%d)\n", rc);
193     }
194     return pDev;
195 }
196 
197 /**
198  * Copy the device->key into master->key and send a mapping notify to the
199  * clients if appropriate.
200  * master->key needs to be allocated by the caller.
201  *
202  * Device is the slave device. If it is attached to a master device, we may
203  * need to send a mapping notify to the client because it causes the MD
204  * to change state.
205  *
206  * Mapping notify needs to be sent in the following cases:
207  *      - different slave device on same master
208  *      - different master
209  *
210  * XXX: They way how the code is we also send a map notify if the slave device
211  * stays the same, but the master changes. This isn't really necessary though.
212  *
213  * XXX: this gives you funny behaviour with the ClientPointer. When a
214  * MappingNotify is sent to the client, the client usually responds with a
215  * GetKeyboardMapping. This will retrieve the ClientPointer's keyboard
216  * mapping, regardless of which keyboard sent the last mapping notify request.
217  * So depending on the CP setting, your keyboard may change layout in each
218  * app...
219  *
220  * This code is basically the old SwitchCoreKeyboard.
221  */
222 
223 void
CopyKeyClass(DeviceIntPtr device,DeviceIntPtr master)224 CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
225 {
226     KeyClassPtr mk = master->key;
227 
228     if (device == master)
229         return;
230 
231     mk->sourceid = device->id;
232 
233     if (!XkbDeviceApplyKeymap(master, device->key->xkbInfo->desc))
234         FatalError("Couldn't pivot keymap from device to core!\n");
235 }
236 
237 /**
238  * Copies the feedback classes from device "from" into device "to". Classes
239  * are duplicated (not just flipping the pointers). All feedback classes are
240  * linked lists, the full list is duplicated.
241  */
242 static void
DeepCopyFeedbackClasses(DeviceIntPtr from,DeviceIntPtr to)243 DeepCopyFeedbackClasses(DeviceIntPtr from, DeviceIntPtr to)
244 {
245     ClassesPtr classes;
246 
247     if (from->intfeed) {
248         IntegerFeedbackPtr *i, it;
249 
250         if (!to->intfeed) {
251             classes = to->unused_classes;
252             to->intfeed = classes->intfeed;
253             classes->intfeed = NULL;
254         }
255 
256         i = &to->intfeed;
257         for (it = from->intfeed; it; it = it->next) {
258             if (!(*i)) {
259                 *i = calloc(1, sizeof(IntegerFeedbackClassRec));
260                 if (!(*i)) {
261                     ErrorF("[Xi] Cannot alloc memory for class copy.");
262                     return;
263                 }
264             }
265             (*i)->CtrlProc = it->CtrlProc;
266             (*i)->ctrl = it->ctrl;
267 
268             i = &(*i)->next;
269         }
270     }
271     else if (to->intfeed && !from->intfeed) {
272         classes = to->unused_classes;
273         classes->intfeed = to->intfeed;
274         to->intfeed = NULL;
275     }
276 
277     if (from->stringfeed) {
278         StringFeedbackPtr *s, it;
279 
280         if (!to->stringfeed) {
281             classes = to->unused_classes;
282             to->stringfeed = classes->stringfeed;
283             classes->stringfeed = NULL;
284         }
285 
286         s = &to->stringfeed;
287         for (it = from->stringfeed; it; it = it->next) {
288             if (!(*s)) {
289                 *s = calloc(1, sizeof(StringFeedbackClassRec));
290                 if (!(*s)) {
291                     ErrorF("[Xi] Cannot alloc memory for class copy.");
292                     return;
293                 }
294             }
295             (*s)->CtrlProc = it->CtrlProc;
296             (*s)->ctrl = it->ctrl;
297 
298             s = &(*s)->next;
299         }
300     }
301     else if (to->stringfeed && !from->stringfeed) {
302         classes = to->unused_classes;
303         classes->stringfeed = to->stringfeed;
304         to->stringfeed = NULL;
305     }
306 
307     if (from->bell) {
308         BellFeedbackPtr *b, it;
309 
310         if (!to->bell) {
311             classes = to->unused_classes;
312             to->bell = classes->bell;
313             classes->bell = NULL;
314         }
315 
316         b = &to->bell;
317         for (it = from->bell; it; it = it->next) {
318             if (!(*b)) {
319                 *b = calloc(1, sizeof(BellFeedbackClassRec));
320                 if (!(*b)) {
321                     ErrorF("[Xi] Cannot alloc memory for class copy.");
322                     return;
323                 }
324             }
325             (*b)->BellProc = it->BellProc;
326             (*b)->CtrlProc = it->CtrlProc;
327             (*b)->ctrl = it->ctrl;
328 
329             b = &(*b)->next;
330         }
331     }
332     else if (to->bell && !from->bell) {
333         classes = to->unused_classes;
334         classes->bell = to->bell;
335         to->bell = NULL;
336     }
337 
338     if (from->leds) {
339         LedFeedbackPtr *l, it;
340 
341         if (!to->leds) {
342             classes = to->unused_classes;
343             to->leds = classes->leds;
344             classes->leds = NULL;
345         }
346 
347         l = &to->leds;
348         for (it = from->leds; it; it = it->next) {
349             if (!(*l)) {
350                 *l = calloc(1, sizeof(LedFeedbackClassRec));
351                 if (!(*l)) {
352                     ErrorF("[Xi] Cannot alloc memory for class copy.");
353                     return;
354                 }
355             }
356             (*l)->CtrlProc = it->CtrlProc;
357             (*l)->ctrl = it->ctrl;
358             if ((*l)->xkb_sli)
359                 XkbFreeSrvLedInfo((*l)->xkb_sli);
360             (*l)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, NULL, *l);
361 
362             l = &(*l)->next;
363         }
364     }
365     else if (to->leds && !from->leds) {
366         classes = to->unused_classes;
367         classes->leds = to->leds;
368         to->leds = NULL;
369     }
370 }
371 
372 static void
DeepCopyKeyboardClasses(DeviceIntPtr from,DeviceIntPtr to)373 DeepCopyKeyboardClasses(DeviceIntPtr from, DeviceIntPtr to)
374 {
375     ClassesPtr classes;
376 
377     /* XkbInitDevice (->XkbInitIndicatorMap->XkbFindSrvLedInfo) relies on the
378      * kbdfeed to be set up properly, so let's do the feedback classes first.
379      */
380     if (from->kbdfeed) {
381         KbdFeedbackPtr *k, it;
382 
383         if (!to->kbdfeed) {
384             classes = to->unused_classes;
385 
386             to->kbdfeed = classes->kbdfeed;
387             if (!to->kbdfeed)
388                 InitKeyboardDeviceStruct(to, NULL, NULL, NULL);
389             classes->kbdfeed = NULL;
390         }
391 
392         k = &to->kbdfeed;
393         for (it = from->kbdfeed; it; it = it->next) {
394             if (!(*k)) {
395                 *k = calloc(1, sizeof(KbdFeedbackClassRec));
396                 if (!*k) {
397                     ErrorF("[Xi] Cannot alloc memory for class copy.");
398                     return;
399                 }
400             }
401             (*k)->BellProc = it->BellProc;
402             (*k)->CtrlProc = it->CtrlProc;
403             (*k)->ctrl = it->ctrl;
404             if ((*k)->xkb_sli)
405                 XkbFreeSrvLedInfo((*k)->xkb_sli);
406             (*k)->xkb_sli = XkbCopySrvLedInfo(from, it->xkb_sli, *k, NULL);
407 
408             k = &(*k)->next;
409         }
410     }
411     else if (to->kbdfeed && !from->kbdfeed) {
412         classes = to->unused_classes;
413         classes->kbdfeed = to->kbdfeed;
414         to->kbdfeed = NULL;
415     }
416 
417     if (from->key) {
418         if (!to->key) {
419             classes = to->unused_classes;
420             to->key = classes->key;
421             if (!to->key)
422                 InitKeyboardDeviceStruct(to, NULL, NULL, NULL);
423             else
424                 classes->key = NULL;
425         }
426 
427         CopyKeyClass(from, to);
428     }
429     else if (to->key && !from->key) {
430         classes = to->unused_classes;
431         classes->key = to->key;
432         to->key = NULL;
433     }
434 
435     /* If a SrvLedInfoPtr's flags are XkbSLI_IsDefault, the names and maps
436      * pointer point into the xkbInfo->desc struct.  XkbCopySrvLedInfo
437      * didn't update the pointers so we need to do it manually here.
438      */
439     if (to->kbdfeed) {
440         KbdFeedbackPtr k;
441 
442         for (k = to->kbdfeed; k; k = k->next) {
443             if (!k->xkb_sli)
444                 continue;
445             if (k->xkb_sli->flags & XkbSLI_IsDefault) {
446                 k->xkb_sli->names = to->key->xkbInfo->desc->names->indicators;
447                 k->xkb_sli->maps = to->key->xkbInfo->desc->indicators->maps;
448             }
449         }
450     }
451 
452     /* We can't just copy over the focus class. When an app sets the focus,
453      * it'll do so on the master device. Copying the SDs focus means losing
454      * the focus.
455      * So we only copy the focus class if the device didn't have one,
456      * otherwise we leave it as it is.
457      */
458     if (from->focus) {
459         if (!to->focus) {
460             WindowPtr *oldTrace;
461 
462             classes = to->unused_classes;
463             to->focus = classes->focus;
464             if (!to->focus) {
465                 to->focus = calloc(1, sizeof(FocusClassRec));
466                 if (!to->focus)
467                     FatalError("[Xi] no memory for class shift.\n");
468             }
469             else
470                 classes->focus = NULL;
471 
472             oldTrace = to->focus->trace;
473             memcpy(to->focus, from->focus, sizeof(FocusClassRec));
474             to->focus->trace = reallocarray(oldTrace,
475                                             to->focus->traceSize,
476                                             sizeof(WindowPtr));
477             if (!to->focus->trace && to->focus->traceSize)
478                 FatalError("[Xi] no memory for trace.\n");
479             memcpy(to->focus->trace, from->focus->trace,
480                    from->focus->traceSize * sizeof(WindowPtr));
481             to->focus->sourceid = from->id;
482         }
483     }
484     else if (to->focus) {
485         classes = to->unused_classes;
486         classes->focus = to->focus;
487         to->focus = NULL;
488     }
489 
490 }
491 
492 /* FIXME: this should really be shared with the InitValuatorAxisClassRec and
493  * similar */
494 static void
DeepCopyPointerClasses(DeviceIntPtr from,DeviceIntPtr to)495 DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
496 {
497     ClassesPtr classes;
498 
499     /* Feedback classes must be copied first */
500     if (from->ptrfeed) {
501         PtrFeedbackPtr *p, it;
502 
503         if (!to->ptrfeed) {
504             classes = to->unused_classes;
505             to->ptrfeed = classes->ptrfeed;
506             classes->ptrfeed = NULL;
507         }
508 
509         p = &to->ptrfeed;
510         for (it = from->ptrfeed; it; it = it->next) {
511             if (!(*p)) {
512                 *p = calloc(1, sizeof(PtrFeedbackClassRec));
513                 if (!*p) {
514                     ErrorF("[Xi] Cannot alloc memory for class copy.");
515                     return;
516                 }
517             }
518             (*p)->CtrlProc = it->CtrlProc;
519             (*p)->ctrl = it->ctrl;
520 
521             p = &(*p)->next;
522         }
523     }
524     else if (to->ptrfeed && !from->ptrfeed) {
525         classes = to->unused_classes;
526         classes->ptrfeed = to->ptrfeed;
527         to->ptrfeed = NULL;
528     }
529 
530     if (from->valuator) {
531         ValuatorClassPtr v;
532 
533         if (!to->valuator) {
534             classes = to->unused_classes;
535             to->valuator = classes->valuator;
536             if (to->valuator)
537                 classes->valuator = NULL;
538         }
539 
540         v = AllocValuatorClass(to->valuator, from->valuator->numAxes);
541 
542         if (!v)
543             FatalError("[Xi] no memory for class shift.\n");
544 
545         to->valuator = v;
546         memcpy(v->axes, from->valuator->axes, v->numAxes * sizeof(AxisInfo));
547 
548         v->sourceid = from->id;
549     }
550     else if (to->valuator && !from->valuator) {
551         classes = to->unused_classes;
552         classes->valuator = to->valuator;
553         to->valuator = NULL;
554     }
555 
556     if (from->button) {
557         if (!to->button) {
558             classes = to->unused_classes;
559             to->button = classes->button;
560             if (!to->button) {
561                 to->button = calloc(1, sizeof(ButtonClassRec));
562                 if (!to->button)
563                     FatalError("[Xi] no memory for class shift.\n");
564             }
565             else
566                 classes->button = NULL;
567         }
568 
569         if (from->button->xkb_acts) {
570             if (!to->button->xkb_acts) {
571                 to->button->xkb_acts = calloc(1, sizeof(XkbAction));
572                 if (!to->button->xkb_acts)
573                     FatalError("[Xi] not enough memory for xkb_acts.\n");
574             }
575             memcpy(to->button->xkb_acts, from->button->xkb_acts,
576                    sizeof(XkbAction));
577         }
578         else
579             free(to->button->xkb_acts);
580 
581         memcpy(to->button->labels, from->button->labels,
582                from->button->numButtons * sizeof(Atom));
583         to->button->sourceid = from->id;
584     }
585     else if (to->button && !from->button) {
586         classes = to->unused_classes;
587         classes->button = to->button;
588         to->button = NULL;
589     }
590 
591     if (from->proximity) {
592         if (!to->proximity) {
593             classes = to->unused_classes;
594             to->proximity = classes->proximity;
595             if (!to->proximity) {
596                 to->proximity = calloc(1, sizeof(ProximityClassRec));
597                 if (!to->proximity)
598                     FatalError("[Xi] no memory for class shift.\n");
599             }
600             else
601                 classes->proximity = NULL;
602         }
603         memcpy(to->proximity, from->proximity, sizeof(ProximityClassRec));
604         to->proximity->sourceid = from->id;
605     }
606     else if (to->proximity) {
607         classes = to->unused_classes;
608         classes->proximity = to->proximity;
609         to->proximity = NULL;
610     }
611 
612     if (from->touch) {
613         TouchClassPtr t, f;
614 
615         if (!to->touch) {
616             classes = to->unused_classes;
617             to->touch = classes->touch;
618             if (!to->touch) {
619                 int i;
620 
621                 to->touch = calloc(1, sizeof(TouchClassRec));
622                 if (!to->touch)
623                     FatalError("[Xi] no memory for class shift.\n");
624                 to->touch->num_touches = from->touch->num_touches;
625                 to->touch->touches = calloc(to->touch->num_touches,
626                                             sizeof(TouchPointInfoRec));
627                 for (i = 0; i < to->touch->num_touches; i++)
628                     TouchInitTouchPoint(to->touch, to->valuator, i);
629                 if (!to->touch)
630                     FatalError("[Xi] no memory for class shift.\n");
631             }
632             else
633                 classes->touch = NULL;
634         }
635 
636         t = to->touch;
637         f = from->touch;
638         t->sourceid = f->sourceid;
639         t->max_touches = f->max_touches;
640         t->mode = f->mode;
641         t->buttonsDown = f->buttonsDown;
642         t->state = f->state;
643         t->motionMask = f->motionMask;
644         /* to->touches and to->num_touches are separate on the master,
645          * don't copy */
646     }
647     /* Don't remove touch class if from->touch is non-existent. The to device
648      * may have an active touch grab, so we need to keep the touch class record
649      * around. */
650 }
651 
652 /**
653  * Copies the CONTENT of the classes of device from into the classes in device
654  * to. From and to are identical after finishing.
655  *
656  * If to does not have classes from currently has, the classes are stored in
657  * to's devPrivates system. Later, we recover it again from there if needed.
658  * Saves a few memory allocations.
659  */
660 void
DeepCopyDeviceClasses(DeviceIntPtr from,DeviceIntPtr to,DeviceChangedEvent * dce)661 DeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to,
662                       DeviceChangedEvent *dce)
663 {
664     input_lock();
665 
666     /* generic feedback classes, not tied to pointer and/or keyboard */
667     DeepCopyFeedbackClasses(from, to);
668 
669     if ((dce->flags & DEVCHANGE_KEYBOARD_EVENT))
670         DeepCopyKeyboardClasses(from, to);
671     if ((dce->flags & DEVCHANGE_POINTER_EVENT))
672         DeepCopyPointerClasses(from, to);
673 
674     input_unlock();
675 }
676 
677 /**
678  * Send an XI2 DeviceChangedEvent to all interested clients.
679  */
680 void
XISendDeviceChangedEvent(DeviceIntPtr device,DeviceChangedEvent * dce)681 XISendDeviceChangedEvent(DeviceIntPtr device, DeviceChangedEvent *dce)
682 {
683     xXIDeviceChangedEvent *dcce;
684     int rc;
685 
686     rc = EventToXI2((InternalEvent *) dce, (xEvent **) &dcce);
687     if (rc != Success) {
688         ErrorF("[Xi] event conversion from DCE failed with code %d\n", rc);
689         return;
690     }
691 
692     /* we don't actually swap if there's a NullClient, swapping is done
693      * later when event is delivered. */
694     SendEventToAllWindows(device, XI_DeviceChangedMask, (xEvent *) dcce, 1);
695     free(dcce);
696 }
697 
698 static void
ChangeMasterDeviceClasses(DeviceIntPtr device,DeviceChangedEvent * dce)699 ChangeMasterDeviceClasses(DeviceIntPtr device, DeviceChangedEvent *dce)
700 {
701     DeviceIntPtr slave;
702     int rc;
703 
704     /* For now, we don't have devices that change physically. */
705     if (!IsMaster(device))
706         return;
707 
708     rc = dixLookupDevice(&slave, dce->sourceid, serverClient, DixReadAccess);
709 
710     if (rc != Success)
711         return;                 /* Device has disappeared */
712 
713     if (IsMaster(slave))
714         return;
715 
716     if (IsFloating(slave))
717         return;                 /* set floating since the event */
718 
719     if (GetMaster(slave, MASTER_ATTACHED)->id != dce->masterid)
720         return;                 /* not our slave anymore, don't care */
721 
722     /* FIXME: we probably need to send a DCE for the new slave now */
723 
724     device->public.devicePrivate = slave->public.devicePrivate;
725 
726     /* FIXME: the classes may have changed since we generated the event. */
727     DeepCopyDeviceClasses(slave, device, dce);
728     dce->deviceid = device->id;
729     XISendDeviceChangedEvent(device, dce);
730 }
731 
732 /**
733  * Add state and motionMask to the filter for this event. The protocol
734  * supports some extra masks for motion when a button is down:
735  * ButtonXMotionMask and the DeviceButtonMotionMask to trigger only when at
736  * least one button (or that specific button is down). These masks need to
737  * be added to the filters for core/XI motion events.
738  *
739  * @param device The device to update the mask for
740  * @param state The current button state mask
741  * @param motion_mask The motion mask (DeviceButtonMotionMask or 0)
742  */
743 static void
UpdateDeviceMotionMask(DeviceIntPtr device,unsigned short state,Mask motion_mask)744 UpdateDeviceMotionMask(DeviceIntPtr device, unsigned short state,
745                        Mask motion_mask)
746 {
747     Mask mask;
748 
749     mask = PointerMotionMask | state | motion_mask;
750     SetMaskForEvent(device->id, mask, DeviceMotionNotify);
751     SetMaskForEvent(device->id, mask, MotionNotify);
752 }
753 
754 static void
IncreaseButtonCount(DeviceIntPtr dev,int key,CARD8 * buttons_down,Mask * motion_mask,unsigned short * state)755 IncreaseButtonCount(DeviceIntPtr dev, int key, CARD8 *buttons_down,
756                     Mask *motion_mask, unsigned short *state)
757 {
758     if (dev->valuator)
759         dev->valuator->motionHintWindow = NullWindow;
760 
761     (*buttons_down)++;
762     *motion_mask = DeviceButtonMotionMask;
763     if (dev->button->map[key] <= 5)
764         *state |= (Button1Mask >> 1) << dev->button->map[key];
765 }
766 
767 static void
DecreaseButtonCount(DeviceIntPtr dev,int key,CARD8 * buttons_down,Mask * motion_mask,unsigned short * state)768 DecreaseButtonCount(DeviceIntPtr dev, int key, CARD8 *buttons_down,
769                     Mask *motion_mask, unsigned short *state)
770 {
771     if (dev->valuator)
772         dev->valuator->motionHintWindow = NullWindow;
773 
774     if (*buttons_down >= 1 && !--(*buttons_down))
775         *motion_mask = 0;
776     if (dev->button->map[key] <= 5)
777         *state &= ~((Button1Mask >> 1) << dev->button->map[key]);
778 }
779 
780 /**
781  * Update the device state according to the data in the event.
782  *
783  * return values are
784  *   DEFAULT ... process as normal
785  *   DONT_PROCESS ... return immediately from caller
786  */
787 #define DEFAULT 0
788 #define DONT_PROCESS 1
789 int
UpdateDeviceState(DeviceIntPtr device,DeviceEvent * event)790 UpdateDeviceState(DeviceIntPtr device, DeviceEvent *event)
791 {
792     int i;
793     int key = 0, last_valuator;
794 
795     KeyClassPtr k = NULL;
796     ButtonClassPtr b = NULL;
797     ValuatorClassPtr v = NULL;
798     TouchClassPtr t = NULL;
799 
800     /* This event is always the first we get, before the actual events with
801      * the data. However, the way how the DDX is set up, "device" will
802      * actually be the slave device that caused the event.
803      */
804     switch (event->type) {
805     case ET_DeviceChanged:
806         ChangeMasterDeviceClasses(device, (DeviceChangedEvent *) event);
807         return DONT_PROCESS;    /* event has been sent already */
808     case ET_Motion:
809     case ET_ButtonPress:
810     case ET_ButtonRelease:
811     case ET_KeyPress:
812     case ET_KeyRelease:
813     case ET_ProximityIn:
814     case ET_ProximityOut:
815     case ET_TouchBegin:
816     case ET_TouchUpdate:
817     case ET_TouchEnd:
818         break;
819     default:
820         /* other events don't update the device */
821         return DEFAULT;
822     }
823 
824     k = device->key;
825     v = device->valuator;
826     b = device->button;
827     t = device->touch;
828 
829     key = event->detail.key;
830 
831     /* Update device axis */
832     /* Check valuators first */
833     last_valuator = -1;
834     for (i = 0; i < MAX_VALUATORS; i++) {
835         if (BitIsOn(&event->valuators.mask, i)) {
836             if (!v) {
837                 ErrorF("[Xi] Valuators reported for non-valuator device '%s'. "
838                        "Ignoring event.\n", device->name);
839                 return DONT_PROCESS;
840             }
841             else if (v->numAxes < i) {
842                 ErrorF("[Xi] Too many valuators reported for device '%s'. "
843                        "Ignoring event.\n", device->name);
844                 return DONT_PROCESS;
845             }
846             last_valuator = i;
847         }
848     }
849 
850     for (i = 0; i <= last_valuator && i < v->numAxes; i++) {
851         /* XXX: Relative/Absolute mode */
852         if (BitIsOn(&event->valuators.mask, i))
853             v->axisVal[i] = event->valuators.data[i];
854     }
855 
856     if (event->type == ET_KeyPress) {
857         if (!k)
858             return DONT_PROCESS;
859 
860         /* don't allow ddx to generate multiple downs, but repeats are okay */
861         if (key_is_down(device, key, KEY_PROCESSED) && !event->key_repeat)
862             return DONT_PROCESS;
863 
864         if (device->valuator)
865             device->valuator->motionHintWindow = NullWindow;
866         set_key_down(device, key, KEY_PROCESSED);
867     }
868     else if (event->type == ET_KeyRelease) {
869         if (!k)
870             return DONT_PROCESS;
871 
872         if (!key_is_down(device, key, KEY_PROCESSED))   /* guard against duplicates */
873             return DONT_PROCESS;
874         if (device->valuator)
875             device->valuator->motionHintWindow = NullWindow;
876         set_key_up(device, key, KEY_PROCESSED);
877     }
878     else if (event->type == ET_ButtonPress) {
879         if (!b)
880             return DONT_PROCESS;
881 
882         if (button_is_down(device, key, BUTTON_PROCESSED))
883             return DONT_PROCESS;
884 
885         set_button_down(device, key, BUTTON_PROCESSED);
886 
887         if (!b->map[key])
888             return DONT_PROCESS;
889 
890         IncreaseButtonCount(device, key, &b->buttonsDown, &b->motionMask,
891                             &b->state);
892         UpdateDeviceMotionMask(device, b->state, b->motionMask);
893     }
894     else if (event->type == ET_ButtonRelease) {
895         if (!b)
896             return DONT_PROCESS;
897 
898         if (!button_is_down(device, key, BUTTON_PROCESSED))
899             return DONT_PROCESS;
900         if (IsMaster(device)) {
901             DeviceIntPtr sd;
902 
903             /*
904              * Leave the button down if any slave has the
905              * button still down. Note that this depends on the
906              * event being delivered through the slave first
907              */
908             for (sd = inputInfo.devices; sd; sd = sd->next) {
909                 if (IsMaster(sd) || GetMaster(sd, MASTER_POINTER) != device)
910                     continue;
911                 if (!sd->button)
912                     continue;
913                 for (i = 1; i <= sd->button->numButtons; i++)
914                     if (sd->button->map[i] == key &&
915                         button_is_down(sd, i, BUTTON_PROCESSED))
916                         return DONT_PROCESS;
917             }
918         }
919         set_button_up(device, key, BUTTON_PROCESSED);
920         if (!b->map[key])
921             return DONT_PROCESS;
922 
923         DecreaseButtonCount(device, key, &b->buttonsDown, &b->motionMask,
924                             &b->state);
925         UpdateDeviceMotionMask(device, b->state, b->motionMask);
926     }
927     else if (event->type == ET_ProximityIn)
928         device->proximity->in_proximity = TRUE;
929     else if (event->type == ET_ProximityOut)
930         device->proximity->in_proximity = FALSE;
931     else if (event->type == ET_TouchBegin) {
932         BUG_RETURN_VAL(!b || !v, DONT_PROCESS);
933         BUG_RETURN_VAL(!t, DONT_PROCESS);
934 
935         if (!b->map[key])
936             return DONT_PROCESS;
937 
938         if (!(event->flags & TOUCH_POINTER_EMULATED) ||
939             (event->flags & TOUCH_REPLAYING))
940             return DONT_PROCESS;
941 
942         IncreaseButtonCount(device, key, &t->buttonsDown, &t->motionMask,
943                             &t->state);
944         UpdateDeviceMotionMask(device, t->state, DeviceButtonMotionMask);
945     }
946     else if (event->type == ET_TouchEnd) {
947         BUG_RETURN_VAL(!b || !v, DONT_PROCESS);
948         BUG_RETURN_VAL(!t, DONT_PROCESS);
949 
950         if (t->buttonsDown <= 0 || !b->map[key])
951             return DONT_PROCESS;
952 
953         if (!(event->flags & TOUCH_POINTER_EMULATED))
954             return DONT_PROCESS;
955 
956         DecreaseButtonCount(device, key, &t->buttonsDown, &t->motionMask,
957                             &t->state);
958         UpdateDeviceMotionMask(device, t->state, DeviceButtonMotionMask);
959     }
960 
961     return DEFAULT;
962 }
963 
964 /**
965  * A client that does not have the TouchOwnership mask set may not receive a
966  * TouchBegin event if there is at least one grab active.
967  *
968  * @return TRUE if the client selected for ownership events on the given
969  * window for this device, FALSE otherwise
970  */
971 static inline Bool
TouchClientWantsOwnershipEvents(ClientPtr client,DeviceIntPtr dev,WindowPtr win)972 TouchClientWantsOwnershipEvents(ClientPtr client, DeviceIntPtr dev,
973                                 WindowPtr win)
974 {
975     InputClients *iclient;
976 
977     nt_list_for_each_entry(iclient, wOtherInputMasks(win)->inputClients, next) {
978         if (rClient(iclient) != client)
979             continue;
980 
981         return xi2mask_isset(iclient->xi2mask, dev, XI_TouchOwnership);
982     }
983 
984     return FALSE;
985 }
986 
987 static void
TouchSendOwnershipEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,int reason,XID resource)988 TouchSendOwnershipEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, int reason,
989                         XID resource)
990 {
991     int nev, i;
992     InternalEvent *tel = InitEventList(GetMaximumEventsNum());
993 
994     nev = GetTouchOwnershipEvents(tel, dev, ti, reason, resource, 0);
995     for (i = 0; i < nev; i++)
996         mieqProcessDeviceEvent(dev, tel + i, NULL);
997 
998     FreeEventList(tel, GetMaximumEventsNum());
999 }
1000 
1001 /**
1002  * Attempts to deliver a touch event to the given client.
1003  */
1004 static Bool
DeliverOneTouchEvent(ClientPtr client,DeviceIntPtr dev,TouchPointInfoPtr ti,GrabPtr grab,WindowPtr win,InternalEvent * ev)1005 DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
1006                      GrabPtr grab, WindowPtr win, InternalEvent *ev)
1007 {
1008     int err;
1009     xEvent *xi2;
1010     Mask filter;
1011     Window child = DeepestSpriteWin(&ti->sprite)->drawable.id;
1012 
1013     /* FIXME: owner event handling */
1014 
1015     /* If the client does not have the ownership mask set and is not
1016      * the current owner of the touch, only pretend we delivered */
1017     if (!grab && ti->num_grabs != 0 &&
1018         !TouchClientWantsOwnershipEvents(client, dev, win))
1019         return TRUE;
1020 
1021     /* If we fail here, we're going to leave a client hanging. */
1022     err = EventToXI2(ev, &xi2);
1023     if (err != Success)
1024         FatalError("[Xi] %s: XI2 conversion failed in %s"
1025                    " (%d)\n", dev->name, __func__, err);
1026 
1027     FixUpEventFromWindow(&ti->sprite, xi2, win, child, FALSE);
1028     filter = GetEventFilter(dev, xi2);
1029     if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) != Success)
1030         return FALSE;
1031     err = TryClientEvents(client, dev, xi2, 1, filter, filter, NullGrab);
1032     free(xi2);
1033 
1034     /* Returning the value from TryClientEvents isn't useful, since all our
1035      * resource-gone cleanups will update the delivery list anyway. */
1036     return TRUE;
1037 }
1038 
1039 static void
ActivateEarlyAccept(DeviceIntPtr dev,TouchPointInfoPtr ti)1040 ActivateEarlyAccept(DeviceIntPtr dev, TouchPointInfoPtr ti)
1041 {
1042     ClientPtr client;
1043     XID error;
1044     GrabPtr grab = ti->listeners[0].grab;
1045 
1046     BUG_RETURN(ti->listeners[0].type != LISTENER_GRAB &&
1047                ti->listeners[0].type != LISTENER_POINTER_GRAB);
1048     BUG_RETURN(!grab);
1049 
1050     client = rClient(grab);
1051 
1052     if (TouchAcceptReject(client, dev, XIAcceptTouch, ti->client_id,
1053                           ti->listeners[0].window->drawable.id, &error) != Success)
1054         ErrorF("[Xi] Failed to accept touch grab after early acceptance.\n");
1055 }
1056 
1057 /**
1058  * Find the oldest touch that still has a pointer emulation client.
1059  *
1060  * Pointer emulation can only be performed for the oldest touch. Otherwise, the
1061  * order of events seen by the client will be wrong. This function helps us find
1062  * the next touch to be emulated.
1063  *
1064  * @param dev The device to find touches for.
1065  */
1066 static TouchPointInfoPtr
FindOldestPointerEmulatedTouch(DeviceIntPtr dev)1067 FindOldestPointerEmulatedTouch(DeviceIntPtr dev)
1068 {
1069     TouchPointInfoPtr oldest = NULL;
1070     int i;
1071 
1072     for (i = 0; i < dev->touch->num_touches; i++) {
1073         TouchPointInfoPtr ti = dev->touch->touches + i;
1074         int j;
1075 
1076         if (!ti->active || !ti->emulate_pointer)
1077             continue;
1078 
1079         for (j = 0; j < ti->num_listeners; j++) {
1080             if (ti->listeners[j].type == LISTENER_POINTER_GRAB ||
1081                 ti->listeners[j].type == LISTENER_POINTER_REGULAR)
1082                 break;
1083         }
1084         if (j == ti->num_listeners)
1085             continue;
1086 
1087         if (!oldest) {
1088             oldest = ti;
1089             continue;
1090         }
1091 
1092         if (oldest->client_id - ti->client_id < UINT_MAX / 2)
1093             oldest = ti;
1094     }
1095 
1096     return oldest;
1097 }
1098 
1099 /**
1100  * If the current owner has rejected the event, deliver the
1101  * TouchOwnership/TouchBegin to the next item in the sprite stack.
1102  */
1103 static void
TouchPuntToNextOwner(DeviceIntPtr dev,TouchPointInfoPtr ti,TouchOwnershipEvent * ev)1104 TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
1105                      TouchOwnershipEvent *ev)
1106 {
1107     TouchListener *listener = &ti->listeners[0]; /* new owner */
1108     int accepted_early = listener->state == LISTENER_EARLY_ACCEPT;
1109 
1110     /* Deliver the ownership */
1111     if (listener->state == LISTENER_AWAITING_OWNER || accepted_early)
1112         DeliverTouchEvents(dev, ti, (InternalEvent *) ev,
1113                            listener->listener);
1114     else if (listener->state == LISTENER_AWAITING_BEGIN) {
1115         /* We can't punt to a pointer listener unless all older pointer
1116          * emulated touches have been seen already. */
1117         if ((listener->type == LISTENER_POINTER_GRAB ||
1118              listener->type == LISTENER_POINTER_REGULAR) &&
1119             ti != FindOldestPointerEmulatedTouch(dev))
1120             return;
1121 
1122         TouchEventHistoryReplay(ti, dev, listener->listener);
1123     }
1124 
1125     /* New owner has Begin/Update but not end. If touch is pending_finish,
1126      * emulate the TouchEnd now */
1127     if (ti->pending_finish) {
1128         TouchEmitTouchEnd(dev, ti, 0, 0);
1129 
1130         /* If the last owner is not a touch grab, finalise the touch, we
1131            won't get more correspondence on this.
1132          */
1133         if (ti->num_listeners == 1 &&
1134             (ti->num_grabs == 0 ||
1135              listener->grab->grabtype != XI2 ||
1136              !xi2mask_isset(listener->grab->xi2mask, dev, XI_TouchBegin))) {
1137             TouchEndTouch(dev, ti);
1138             return;
1139         }
1140     }
1141 
1142     if (accepted_early)
1143         ActivateEarlyAccept(dev, ti);
1144 }
1145 
1146 /**
1147  * Check the oldest touch to see if it needs to be replayed to its pointer
1148  * owner.
1149  *
1150  * Touch event propagation is paused if it hits a pointer listener while an
1151  * older touch with a pointer listener is waiting on accept or reject. This
1152  * function will restart propagation of a paused touch if needed.
1153  *
1154  * @param dev The device to check touches for.
1155  */
1156 static void
CheckOldestTouch(DeviceIntPtr dev)1157 CheckOldestTouch(DeviceIntPtr dev)
1158 {
1159     TouchPointInfoPtr oldest = FindOldestPointerEmulatedTouch(dev);
1160 
1161     if (oldest && oldest->listeners[0].state == LISTENER_AWAITING_BEGIN)
1162         TouchPuntToNextOwner(dev, oldest, NULL);
1163 }
1164 
1165 /**
1166  * Process a touch rejection.
1167  *
1168  * @param sourcedev The source device of the touch sequence.
1169  * @param ti The touchpoint info record.
1170  * @param resource The resource of the client rejecting the touch.
1171  * @param ev TouchOwnership event to send. Set to NULL if no event should be
1172  *        sent.
1173  */
1174 void
TouchRejected(DeviceIntPtr sourcedev,TouchPointInfoPtr ti,XID resource,TouchOwnershipEvent * ev)1175 TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource,
1176               TouchOwnershipEvent *ev)
1177 {
1178     Bool was_owner = (resource == ti->listeners[0].listener);
1179     int i;
1180 
1181     /* Send a TouchEnd event to the resource being removed, but only if they
1182      * haven't received one yet already */
1183     for (i = 0; i < ti->num_listeners; i++) {
1184         if (ti->listeners[i].listener == resource) {
1185             if (ti->listeners[i].state != LISTENER_HAS_END)
1186                 TouchEmitTouchEnd(sourcedev, ti, TOUCH_REJECT, resource);
1187             break;
1188         }
1189     }
1190 
1191     /* Remove the resource from the listener list, updating
1192      * ti->num_listeners, as well as ti->num_grabs if it was a grab. */
1193     TouchRemoveListener(ti, resource);
1194 
1195     /* If the current owner was removed and there are further listeners, deliver
1196      * the TouchOwnership or TouchBegin event to the new owner. */
1197     if (ev && ti->num_listeners > 0 && was_owner)
1198         TouchPuntToNextOwner(sourcedev, ti, ev);
1199     else if (ti->num_listeners == 0)
1200         TouchEndTouch(sourcedev, ti);
1201 
1202     CheckOldestTouch(sourcedev);
1203 }
1204 
1205 /**
1206  * Processes a TouchOwnership event, indicating a grab has accepted the touch
1207  * it currently owns, or a grab or selection has been removed.  Will generate
1208  * and send TouchEnd events to all clients removed from the delivery list, as
1209  * well as possibly sending the new TouchOwnership event.  May end the
1210  * touchpoint if it is pending finish.
1211  */
1212 static void
ProcessTouchOwnershipEvent(TouchOwnershipEvent * ev,DeviceIntPtr dev)1213 ProcessTouchOwnershipEvent(TouchOwnershipEvent *ev,
1214                            DeviceIntPtr dev)
1215 {
1216     TouchPointInfoPtr ti = TouchFindByClientID(dev, ev->touchid);
1217 
1218     if (!ti) {
1219         DebugF("[Xi] %s: Failed to get event %d for touchpoint %d\n",
1220                dev->name, ev->type, ev->touchid);
1221         return;
1222     }
1223 
1224     if (ev->reason == XIRejectTouch)
1225         TouchRejected(dev, ti, ev->resource, ev);
1226     else if (ev->reason == XIAcceptTouch) {
1227         int i;
1228 
1229 
1230         /* For pointer-emulated listeners that ungrabbed the active grab,
1231          * the state was forced to LISTENER_HAS_END. Still go
1232          * through the motions of ending the touch if the listener has
1233          * already seen the end. This ensures that the touch record is ended in
1234          * the server.
1235          */
1236         if (ti->listeners[0].state == LISTENER_HAS_END)
1237             TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[0].listener);
1238 
1239         /* The touch owner has accepted the touch.  Send TouchEnd events to
1240          * everyone else, and truncate the list of listeners. */
1241         for (i = 1; i < ti->num_listeners; i++)
1242             TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[i].listener);
1243 
1244         while (ti->num_listeners > 1)
1245             TouchRemoveListener(ti, ti->listeners[1].listener);
1246         /* Owner accepted after receiving end */
1247         if (ti->listeners[0].state == LISTENER_HAS_END)
1248             TouchEndTouch(dev, ti);
1249         else
1250             ti->listeners[0].state = LISTENER_HAS_ACCEPTED;
1251     }
1252     else {  /* this is the very first ownership event for a grab */
1253         DeliverTouchEvents(dev, ti, (InternalEvent *) ev, ev->resource);
1254     }
1255 }
1256 
1257 /**
1258  * Copy the event's valuator information into the touchpoint, we may need
1259  * this for emulated TouchEnd events.
1260  */
1261 static void
TouchCopyValuatorData(DeviceEvent * ev,TouchPointInfoPtr ti)1262 TouchCopyValuatorData(DeviceEvent *ev, TouchPointInfoPtr ti)
1263 {
1264     int i;
1265 
1266     for (i = 0; i < ARRAY_SIZE(ev->valuators.data); i++)
1267         if (BitIsOn(ev->valuators.mask, i))
1268             valuator_mask_set_double(ti->valuators, i, ev->valuators.data[i]);
1269 }
1270 
1271 /**
1272  * Given a touch event and a potential listener, retrieve info needed for
1273  * processing the event.
1274  *
1275  * @param dev The device generating the touch event.
1276  * @param ti The touch point info record for the touch event.
1277  * @param ev The touch event to process.
1278  * @param listener The touch event listener that may receive the touch event.
1279  * @param[out] client The client that should receive the touch event.
1280  * @param[out] win The window to deliver the event on.
1281  * @param[out] grab The grab to deliver the event through, if any.
1282  * @param[out] mask The XI 2.x event mask of the grab or selection, if any.
1283  * @return TRUE if an event should be delivered to the listener, FALSE
1284  *         otherwise.
1285  */
1286 static Bool
RetrieveTouchDeliveryData(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,TouchListener * listener,ClientPtr * client,WindowPtr * win,GrabPtr * grab,XI2Mask ** mask)1287 RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
1288                           InternalEvent *ev, TouchListener * listener,
1289                           ClientPtr *client, WindowPtr *win, GrabPtr *grab,
1290                           XI2Mask **mask)
1291 {
1292     int rc;
1293     InputClients *iclients = NULL;
1294     *mask = NULL;
1295     *grab = NULL;
1296 
1297     if (listener->type == LISTENER_GRAB ||
1298         listener->type == LISTENER_POINTER_GRAB) {
1299         *grab = listener->grab;
1300 
1301         BUG_RETURN_VAL(!*grab, FALSE);
1302     }
1303     else if (ti->emulate_pointer && dev->deviceGrab.grab &&
1304              !dev->deviceGrab.fromPassiveGrab) {
1305         /* There may be an active pointer grab on the device */
1306         *grab = dev->deviceGrab.grab;
1307     }
1308 
1309     if (*grab) {
1310         *client = rClient(*grab);
1311         *win = (*grab)->window;
1312         *mask = (*grab)->xi2mask;
1313     }
1314     else {
1315         rc = dixLookupResourceByType((void **) win, listener->listener,
1316                                      listener->resource_type,
1317                                      serverClient, DixSendAccess);
1318         if (rc != Success)
1319             return FALSE;
1320 
1321         if (listener->level == XI2) {
1322             int evtype;
1323 
1324             if (ti->emulate_pointer &&
1325                 listener->type == LISTENER_POINTER_REGULAR)
1326                 evtype = GetXI2Type(TouchGetPointerEventType(ev));
1327             else
1328                 evtype = GetXI2Type(ev->any.type);
1329 
1330             nt_list_for_each_entry(iclients,
1331                                    wOtherInputMasks(*win)->inputClients, next)
1332                 if (xi2mask_isset(iclients->xi2mask, dev, evtype))
1333                 break;
1334 
1335             BUG_RETURN_VAL(!iclients, FALSE);
1336 
1337             *mask = iclients->xi2mask;
1338             *client = rClient(iclients);
1339         }
1340         else if (listener->level == XI) {
1341             int xi_type = GetXIType(TouchGetPointerEventType(ev));
1342             Mask xi_filter = event_get_filter_from_type(dev, xi_type);
1343 
1344             nt_list_for_each_entry(iclients,
1345                                    wOtherInputMasks(*win)->inputClients, next)
1346                 if (iclients->mask[dev->id] & xi_filter)
1347                 break;
1348             BUG_RETURN_VAL(!iclients, FALSE);
1349 
1350             *client = rClient(iclients);
1351         }
1352         else {
1353             int coretype = GetCoreType(TouchGetPointerEventType(ev));
1354             Mask core_filter = event_get_filter_from_type(dev, coretype);
1355             OtherClients *oclients;
1356 
1357             /* all others */
1358             nt_list_for_each_entry(oclients,
1359                                    (OtherClients *) wOtherClients(*win), next)
1360                 if (oclients->mask & core_filter)
1361                     break;
1362 
1363             /* if owner selected, oclients is NULL */
1364             *client = oclients ? rClient(oclients) : wClient(*win);
1365         }
1366     }
1367 
1368     return TRUE;
1369 }
1370 
1371 static int
DeliverTouchEmulatedEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,TouchListener * listener,ClientPtr client,WindowPtr win,GrabPtr grab,XI2Mask * xi2mask)1372 DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
1373                           InternalEvent *ev, TouchListener * listener,
1374                           ClientPtr client, WindowPtr win, GrabPtr grab,
1375                           XI2Mask *xi2mask)
1376 {
1377     InternalEvent motion, button;
1378     InternalEvent *ptrev = &motion;
1379     int nevents;
1380     DeviceIntPtr kbd;
1381 
1382     /* We don't deliver pointer events to non-owners */
1383     if (!TouchResourceIsOwner(ti, listener->listener))
1384         return !Success;
1385 
1386     if (!ti->emulate_pointer)
1387         return !Success;
1388 
1389     nevents = TouchConvertToPointerEvent(ev, &motion, &button);
1390     BUG_RETURN_VAL(nevents == 0, BadValue);
1391 
1392     if (nevents > 1)
1393         ptrev = &button;
1394 
1395     kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
1396     event_set_state(dev, kbd, &ptrev->device_event);
1397     ptrev->device_event.corestate = event_get_corestate(dev, kbd);
1398 
1399     if (grab) {
1400         /* this side-steps the usual activation mechanisms, but... */
1401         if (ev->any.type == ET_TouchBegin && !dev->deviceGrab.grab)
1402             ActivatePassiveGrab(dev, grab, ptrev, ev);  /* also delivers the event */
1403         else {
1404             int deliveries = 0;
1405 
1406             /* 'grab' is the passive grab, but if the grab isn't active,
1407              * don't deliver */
1408             if (!dev->deviceGrab.grab)
1409                 return !Success;
1410 
1411             if (grab->ownerEvents) {
1412                 WindowPtr focus = NullWindow;
1413                 WindowPtr sprite_win = DeepestSpriteWin(dev->spriteInfo->sprite);
1414 
1415                 deliveries = DeliverDeviceEvents(sprite_win, ptrev, grab, focus, dev);
1416             }
1417 
1418             if (!deliveries)
1419                 deliveries = DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype);
1420 
1421             /* We must accept the touch sequence once a pointer listener has
1422              * received one event past ButtonPress. */
1423             if (deliveries && ev->any.type != ET_TouchBegin &&
1424                 !(ev->device_event.flags & TOUCH_CLIENT_ID))
1425                 TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
1426 
1427             if (ev->any.type == ET_TouchEnd &&
1428                 ti->num_listeners == 1 &&
1429                 !dev->button->buttonsDown &&
1430                 dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) {
1431                 (*dev->deviceGrab.DeactivateGrab) (dev);
1432                 CheckOldestTouch(dev);
1433                 return Success;
1434             }
1435         }
1436     }
1437     else {
1438         GrabPtr devgrab = dev->deviceGrab.grab;
1439         WindowPtr sprite_win = DeepestSpriteWin(dev->spriteInfo->sprite);
1440 
1441         DeliverDeviceEvents(sprite_win, ptrev, grab, win, dev);
1442         /* FIXME: bad hack
1443          * Implicit passive grab activated in response to this event. Store
1444          * the event.
1445          */
1446         if (!devgrab && dev->deviceGrab.grab && dev->deviceGrab.implicitGrab) {
1447             TouchListener *l;
1448             GrabPtr g;
1449 
1450             devgrab = dev->deviceGrab.grab;
1451             g = AllocGrab(devgrab);
1452             BUG_WARN(!g);
1453 
1454             *dev->deviceGrab.sync.event = ev->device_event;
1455 
1456             /* The listener array has a sequence of grabs and then one event
1457              * selection. Implicit grab activation occurs through delivering an
1458              * event selection. Thus, we update the last listener in the array.
1459              */
1460             l = &ti->listeners[ti->num_listeners - 1];
1461             l->listener = g->resource;
1462             l->grab = g;
1463             //l->resource_type = RT_NONE;
1464 
1465             if (devgrab->grabtype != XI2 || devgrab->type != XI_TouchBegin)
1466                 l->type = LISTENER_POINTER_GRAB;
1467             else
1468                 l->type = LISTENER_GRAB;
1469         }
1470 
1471     }
1472     if (ev->any.type == ET_TouchBegin)
1473         listener->state = LISTENER_IS_OWNER;
1474     else if (ev->any.type == ET_TouchEnd)
1475         listener->state = LISTENER_HAS_END;
1476 
1477     return Success;
1478 }
1479 
1480 static void
DeliverEmulatedMotionEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev)1481 DeliverEmulatedMotionEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
1482                            InternalEvent *ev)
1483 {
1484     DeviceEvent motion;
1485 
1486     if (ti->num_listeners) {
1487         ClientPtr client;
1488         WindowPtr win;
1489         GrabPtr grab;
1490         XI2Mask *mask;
1491 
1492         if (ti->listeners[0].type != LISTENER_POINTER_REGULAR &&
1493             ti->listeners[0].type != LISTENER_POINTER_GRAB)
1494             return;
1495 
1496         motion = ev->device_event;
1497         motion.type = ET_TouchUpdate;
1498         motion.detail.button = 0;
1499 
1500         if (!RetrieveTouchDeliveryData(dev, ti, (InternalEvent*)&motion,
1501                                        &ti->listeners[0], &client, &win, &grab,
1502                                        &mask))
1503             return;
1504 
1505         DeliverTouchEmulatedEvent(dev, ti, (InternalEvent*)&motion, &ti->listeners[0], client,
1506                                   win, grab, mask);
1507     }
1508     else {
1509         InternalEvent button;
1510         int converted;
1511 
1512         converted = TouchConvertToPointerEvent(ev, (InternalEvent*)&motion, &button);
1513 
1514         BUG_WARN(converted == 0);
1515         if (converted)
1516             ProcessOtherEvent((InternalEvent*)&motion, dev);
1517     }
1518 }
1519 
1520 /**
1521  * Processes and delivers a TouchBegin, TouchUpdate, or a
1522  * TouchEnd event.
1523  *
1524  * Due to having rather different delivery semantics (see the Xi 2.2 protocol
1525  * spec for more information), this implements its own grab and event-selection
1526  * delivery logic.
1527  */
1528 static void
ProcessTouchEvent(InternalEvent * ev,DeviceIntPtr dev)1529 ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
1530 {
1531     TouchClassPtr t = dev->touch;
1532     TouchPointInfoPtr ti;
1533     uint32_t touchid;
1534     int type = ev->any.type;
1535     int emulate_pointer = ! !(ev->device_event.flags & TOUCH_POINTER_EMULATED);
1536     DeviceIntPtr kbd;
1537 
1538     if (!t)
1539         return;
1540 
1541     touchid = ev->device_event.touchid;
1542 
1543     if (type == ET_TouchBegin && !(ev->device_event.flags & TOUCH_REPLAYING)) {
1544         ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
1545                              emulate_pointer);
1546     }
1547     else
1548         ti = TouchFindByClientID(dev, touchid);
1549 
1550     /* Active pointer grab */
1551     if (emulate_pointer && dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab &&
1552         (dev->deviceGrab.grab->grabtype == CORE ||
1553          dev->deviceGrab.grab->grabtype == XI ||
1554          !xi2mask_isset(dev->deviceGrab.grab->xi2mask, dev, XI_TouchBegin)))
1555     {
1556         /* Active pointer grab on touch point and we get a TouchEnd - claim this
1557          * touchpoint accepted, otherwise clients waiting for ownership will
1558          * wait on this touchpoint until this client ungrabs, or the cows come
1559          * home, whichever is earlier */
1560         if (ti && type == ET_TouchEnd)
1561             TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
1562         else if (!ti && type != ET_TouchBegin) {
1563             /* Under the following circumstances we create a new touch record for an
1564              * existing touch:
1565              *
1566              * - The touch may be pointer emulated
1567              * - An explicit grab is active on the device
1568              * - The grab is a pointer grab
1569              *
1570              * This allows for an explicit grab to receive pointer events for an already
1571              * active touch.
1572              */
1573             ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
1574                                  emulate_pointer);
1575             if (!ti) {
1576                 DebugF("[Xi] %s: Failed to create new dix record for explicitly "
1577                        "grabbed touchpoint %d\n",
1578                        dev->name, touchid);
1579                 return;
1580             }
1581 
1582             TouchBuildSprite(dev, ti, ev);
1583             TouchSetupListeners(dev, ti, ev);
1584         }
1585     }
1586 
1587     if (!ti) {
1588         DebugF("[Xi] %s: Failed to get event %d for touchpoint %d\n",
1589                dev->name, type, touchid);
1590         goto out;
1591     }
1592 
1593     /* if emulate_pointer is set, emulate the motion event right
1594      * here, so we can ignore it for button event emulation. TouchUpdate
1595      * events which _only_ emulate motion just work normally */
1596     if (emulate_pointer && ev->any.type != ET_TouchUpdate)
1597         DeliverEmulatedMotionEvent(dev, ti, ev);
1598 
1599     if (emulate_pointer && IsMaster(dev))
1600         CheckMotion(&ev->device_event, dev);
1601 
1602     kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
1603     event_set_state(NULL, kbd, &ev->device_event);
1604     ev->device_event.corestate = event_get_corestate(NULL, kbd);
1605 
1606     /* Make sure we have a valid window trace for event delivery; must be
1607      * called after event type mutation. Touch end events are always processed
1608      * in order to end touch records. */
1609     /* FIXME: check this */
1610     if ((type == ET_TouchBegin &&
1611          !(ev->device_event.flags & TOUCH_REPLAYING) &&
1612          !TouchBuildSprite(dev, ti, ev)) ||
1613         (type != ET_TouchEnd && ti->sprite.spriteTraceGood == 0))
1614         return;
1615 
1616     TouchCopyValuatorData(&ev->device_event, ti);
1617     /* WARNING: the event type may change to TouchUpdate in
1618      * DeliverTouchEvents if a TouchEnd was delivered to a grabbing
1619      * owner */
1620     DeliverTouchEvents(dev, ti, ev, ev->device_event.resource);
1621     if (ev->any.type == ET_TouchEnd)
1622         TouchEndTouch(dev, ti);
1623 
1624  out:
1625     if (emulate_pointer)
1626         UpdateDeviceState(dev, &ev->device_event);
1627 }
1628 
1629 static void
ProcessBarrierEvent(InternalEvent * e,DeviceIntPtr dev)1630 ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
1631 {
1632     Mask filter;
1633     WindowPtr pWin;
1634     BarrierEvent *be = &e->barrier_event;
1635     xEvent *ev;
1636     int rc;
1637     GrabPtr grab = dev->deviceGrab.grab;
1638 
1639     if (!IsMaster(dev))
1640         return;
1641 
1642     if (dixLookupWindow(&pWin, be->window, serverClient, DixReadAccess) != Success)
1643         return;
1644 
1645     if (grab)
1646         be->flags |= XIBarrierDeviceIsGrabbed;
1647 
1648     rc = EventToXI2(e, &ev);
1649     if (rc != Success) {
1650         ErrorF("[Xi] event conversion from %s failed with code %d\n", __func__, rc);
1651         return;
1652     }
1653 
1654     /* A client has a grab, deliver to this client if the grab_window is the
1655        barrier window.
1656 
1657        Otherwise, deliver normally to the client.
1658      */
1659     if (grab &&
1660         CLIENT_ID(be->barrierid) == CLIENT_ID(grab->resource) &&
1661         grab->window->drawable.id == be->window) {
1662         DeliverGrabbedEvent(e, dev, FALSE);
1663     } else {
1664         filter = GetEventFilter(dev, ev);
1665 
1666         DeliverEventsToWindow(dev, pWin, ev, 1,
1667                               filter, NullGrab);
1668     }
1669     free(ev);
1670 }
1671 
1672 /**
1673  * Process DeviceEvents and DeviceChangedEvents.
1674  */
1675 static void
ProcessDeviceEvent(InternalEvent * ev,DeviceIntPtr device)1676 ProcessDeviceEvent(InternalEvent *ev, DeviceIntPtr device)
1677 {
1678     GrabPtr grab;
1679     Bool deactivateDeviceGrab = FALSE;
1680     int key = 0, rootX, rootY;
1681     ButtonClassPtr b;
1682     int ret = 0;
1683     int corestate;
1684     DeviceIntPtr mouse = NULL, kbd = NULL;
1685     DeviceEvent *event = &ev->device_event;
1686 
1687     if (IsPointerDevice(device)) {
1688         kbd = GetMaster(device, KEYBOARD_OR_FLOAT);
1689         mouse = device;
1690         if (!kbd->key)          /* can happen with floating SDs */
1691             kbd = NULL;
1692     }
1693     else {
1694         mouse = GetMaster(device, POINTER_OR_FLOAT);
1695         kbd = device;
1696         if (!mouse->valuator || !mouse->button) /* may be float. SDs */
1697             mouse = NULL;
1698     }
1699 
1700     corestate = event_get_corestate(mouse, kbd);
1701     event_set_state(mouse, kbd, event);
1702 
1703     ret = UpdateDeviceState(device, event);
1704     if (ret == DONT_PROCESS)
1705         return;
1706 
1707     b = device->button;
1708 
1709     if (IsMaster(device) || IsFloating(device))
1710         CheckMotion(event, device);
1711 
1712     switch (event->type) {
1713     case ET_Motion:
1714     case ET_ButtonPress:
1715     case ET_ButtonRelease:
1716     case ET_KeyPress:
1717     case ET_KeyRelease:
1718     case ET_ProximityIn:
1719     case ET_ProximityOut:
1720         GetSpritePosition(device, &rootX, &rootY);
1721         event->root_x = rootX;
1722         event->root_y = rootY;
1723         NoticeEventTime((InternalEvent *) event, device);
1724         event->corestate = corestate;
1725         key = event->detail.key;
1726         break;
1727     default:
1728         break;
1729     }
1730 
1731     /* send KeyPress and KeyRelease events to XACE plugins */
1732     if (XaceHookIsSet(XACE_KEY_AVAIL) &&
1733             (event->type == ET_KeyPress || event->type == ET_KeyRelease)) {
1734         xEvent *core;
1735         int count;
1736 
1737         if (EventToCore(ev, &core, &count) == Success && count > 0) {
1738             XaceHook(XACE_KEY_AVAIL, core, device, 0);
1739             free(core);
1740         }
1741     }
1742 
1743     if (DeviceEventCallback && !syncEvents.playingEvents) {
1744         DeviceEventInfoRec eventinfo;
1745         SpritePtr pSprite = device->spriteInfo->sprite;
1746 
1747         /* see comment in EnqueueEvents regarding the next three lines */
1748         if (ev->any.type == ET_Motion)
1749             ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id;
1750 
1751         eventinfo.device = device;
1752         eventinfo.event = ev;
1753         CallCallbacks(&DeviceEventCallback, (void *) &eventinfo);
1754     }
1755 
1756     grab = device->deviceGrab.grab;
1757 
1758     switch (event->type) {
1759     case ET_KeyPress:
1760         /* Don't deliver focus events (e.g. from KeymapNotify when running
1761          * nested) to clients. */
1762         if (event->source_type == EVENT_SOURCE_FOCUS)
1763             return;
1764         if (!grab && CheckDeviceGrabs(device, event, 0))
1765             return;
1766         break;
1767     case ET_KeyRelease:
1768         if (grab && device->deviceGrab.fromPassiveGrab &&
1769             (key == device->deviceGrab.activatingKey) &&
1770             GrabIsKeyboardGrab(device->deviceGrab.grab))
1771             deactivateDeviceGrab = TRUE;
1772         break;
1773     case ET_ButtonPress:
1774         if (b->map[key] == 0)   /* there's no button 0 */
1775             return;
1776         event->detail.button = b->map[key];
1777         if (!grab && CheckDeviceGrabs(device, event, 0)) {
1778             /* if a passive grab was activated, the event has been sent
1779              * already */
1780             return;
1781         }
1782         break;
1783     case ET_ButtonRelease:
1784         if (b->map[key] == 0)   /* there's no button 0 */
1785             return;
1786         event->detail.button = b->map[key];
1787         if (grab && !b->buttonsDown &&
1788             device->deviceGrab.fromPassiveGrab &&
1789             GrabIsPointerGrab(device->deviceGrab.grab))
1790             deactivateDeviceGrab = TRUE;
1791     default:
1792         break;
1793     }
1794 
1795     /* Don't deliver focus events (e.g. from KeymapNotify when running
1796      * nested) to clients. */
1797     if (event->source_type != EVENT_SOURCE_FOCUS) {
1798         if (grab)
1799             DeliverGrabbedEvent((InternalEvent *) event, device,
1800                                 deactivateDeviceGrab);
1801         else if (device->focus && !IsPointerEvent(ev))
1802             DeliverFocusedEvent(device, (InternalEvent *) event,
1803                                 GetSpriteWindow(device));
1804         else
1805             DeliverDeviceEvents(GetSpriteWindow(device), (InternalEvent *) event,
1806                                 NullGrab, NullWindow, device);
1807     }
1808 
1809     if (deactivateDeviceGrab == TRUE) {
1810         (*device->deviceGrab.DeactivateGrab) (device);
1811 
1812         if (!IsMaster (device) && !IsFloating (device)) {
1813             int flags, num_events = 0;
1814             InternalEvent dce;
1815 
1816             flags = (IsPointerDevice (device)) ?
1817                 DEVCHANGE_POINTER_EVENT : DEVCHANGE_KEYBOARD_EVENT;
1818             UpdateFromMaster (&dce, device, flags, &num_events);
1819             BUG_WARN(num_events > 1);
1820 
1821             if (num_events == 1)
1822                 ChangeMasterDeviceClasses(GetMaster (device, MASTER_ATTACHED),
1823                                           &dce.changed_event);
1824         }
1825 
1826     }
1827 
1828     event->detail.key = key;
1829 }
1830 
1831 /**
1832  * Main device event processing function.
1833  * Called from when processing the events from the event queue.
1834  *
1835  */
1836 void
ProcessOtherEvent(InternalEvent * ev,DeviceIntPtr device)1837 ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
1838 {
1839     verify_internal_event(ev);
1840 
1841     switch (ev->any.type) {
1842     case ET_RawKeyPress:
1843     case ET_RawKeyRelease:
1844     case ET_RawButtonPress:
1845     case ET_RawButtonRelease:
1846     case ET_RawMotion:
1847     case ET_RawTouchBegin:
1848     case ET_RawTouchUpdate:
1849     case ET_RawTouchEnd:
1850         DeliverRawEvent(&ev->raw_event, device);
1851         break;
1852     case ET_TouchBegin:
1853     case ET_TouchUpdate:
1854     case ET_TouchEnd:
1855         ProcessTouchEvent(ev, device);
1856         break;
1857     case ET_TouchOwnership:
1858         /* TouchOwnership events are handled separately from the rest, as they
1859          * have more complex semantics. */
1860         ProcessTouchOwnershipEvent(&ev->touch_ownership_event, device);
1861         break;
1862     case ET_BarrierHit:
1863     case ET_BarrierLeave:
1864         ProcessBarrierEvent(ev, device);
1865         break;
1866     default:
1867         ProcessDeviceEvent(ev, device);
1868         break;
1869     }
1870 }
1871 
1872 static int
DeliverTouchBeginEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,TouchListener * listener,ClientPtr client,WindowPtr win,GrabPtr grab,XI2Mask * xi2mask)1873 DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
1874                        InternalEvent *ev, TouchListener * listener,
1875                        ClientPtr client, WindowPtr win, GrabPtr grab,
1876                        XI2Mask *xi2mask)
1877 {
1878     enum TouchListenerState state;
1879     int rc = Success;
1880     Bool has_ownershipmask;
1881 
1882     if (listener->type == LISTENER_POINTER_REGULAR ||
1883         listener->type == LISTENER_POINTER_GRAB) {
1884         rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
1885                                        grab, xi2mask);
1886         if (rc == Success) {
1887             listener->state = LISTENER_IS_OWNER;
1888             /* async grabs cannot replay, so automatically accept this touch */
1889             if (listener->type == LISTENER_POINTER_GRAB &&
1890                 dev->deviceGrab.grab &&
1891                 dev->deviceGrab.fromPassiveGrab &&
1892                 dev->deviceGrab.grab->pointerMode == GrabModeAsync)
1893                 ActivateEarlyAccept(dev, ti);
1894         }
1895         goto out;
1896     }
1897 
1898     has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
1899 
1900     if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
1901         rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
1902     if (!TouchResourceIsOwner(ti, listener->listener)) {
1903         if (has_ownershipmask)
1904             state = LISTENER_AWAITING_OWNER;
1905         else
1906             state = LISTENER_AWAITING_BEGIN;
1907     }
1908     else {
1909         if (has_ownershipmask)
1910             TouchSendOwnershipEvent(dev, ti, 0, listener->listener);
1911 
1912         if (listener->type == LISTENER_REGULAR)
1913             state = LISTENER_HAS_ACCEPTED;
1914         else
1915             state = LISTENER_IS_OWNER;
1916     }
1917     listener->state = state;
1918 
1919  out:
1920     return rc;
1921 }
1922 
1923 static int
DeliverTouchEndEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,TouchListener * listener,ClientPtr client,WindowPtr win,GrabPtr grab,XI2Mask * xi2mask)1924 DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
1925                      TouchListener * listener, ClientPtr client,
1926                      WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
1927 {
1928     int rc = Success;
1929 
1930     if (listener->type == LISTENER_POINTER_REGULAR ||
1931         listener->type == LISTENER_POINTER_GRAB) {
1932         /* Note: If the active grab was ungrabbed, we already changed the
1933          * state to LISTENER_HAS_END but still get here. So we mustn't
1934          * actually send the event.
1935          * This is part two of the hack in DeactivatePointerGrab
1936          */
1937         if (listener->state != LISTENER_HAS_END) {
1938             rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
1939                                            grab, xi2mask);
1940 
1941              /* Once we send a TouchEnd to a legacy listener, we're already well
1942               * past the accepting/rejecting stage (can only happen on
1943               * GrabModeSync + replay. This listener now gets the end event,
1944               * and we can continue.
1945               */
1946             if (rc == Success)
1947                 listener->state = LISTENER_HAS_END;
1948         }
1949         goto out;
1950     }
1951 
1952     /* A client is waiting for the begin, don't give it a TouchEnd */
1953     if (listener->state == LISTENER_AWAITING_BEGIN) {
1954         listener->state = LISTENER_HAS_END;
1955         goto out;
1956     }
1957 
1958     /* Event in response to reject */
1959     if (ev->device_event.flags & TOUCH_REJECT ||
1960         (ev->device_event.flags & TOUCH_ACCEPT && !TouchResourceIsOwner(ti, listener->listener))) {
1961         /* Touch has been rejected, or accepted by its owner which is not this listener */
1962         if (listener->state != LISTENER_HAS_END)
1963             rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
1964         listener->state = LISTENER_HAS_END;
1965     }
1966     else if (TouchResourceIsOwner(ti, listener->listener)) {
1967         Bool normal_end = !(ev->device_event.flags & TOUCH_ACCEPT);
1968 
1969         /* FIXME: what about early acceptance */
1970         if (normal_end && listener->state != LISTENER_HAS_END)
1971             rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
1972 
1973         if ((ti->num_listeners > 1 ||
1974              (ti->num_grabs > 0 && listener->state != LISTENER_HAS_ACCEPTED)) &&
1975             (ev->device_event.flags & (TOUCH_ACCEPT | TOUCH_REJECT)) == 0) {
1976             ev->any.type = ET_TouchUpdate;
1977             ev->device_event.flags |= TOUCH_PENDING_END;
1978             ti->pending_finish = TRUE;
1979         }
1980 
1981         if (normal_end)
1982             listener->state = LISTENER_HAS_END;
1983     }
1984 
1985  out:
1986     return rc;
1987 }
1988 
1989 static int
DeliverTouchEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,TouchListener * listener,ClientPtr client,WindowPtr win,GrabPtr grab,XI2Mask * xi2mask)1990 DeliverTouchEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
1991                   TouchListener * listener, ClientPtr client,
1992                   WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
1993 {
1994     Bool has_ownershipmask = FALSE;
1995     int rc = Success;
1996 
1997     if (xi2mask)
1998         has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
1999 
2000     if (ev->any.type == ET_TouchOwnership) {
2001         ev->touch_ownership_event.deviceid = dev->id;
2002         if (!TouchResourceIsOwner(ti, listener->listener))
2003             goto out;
2004         rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
2005         listener->state = LISTENER_IS_OWNER;
2006     }
2007     else
2008         ev->device_event.deviceid = dev->id;
2009 
2010     if (ev->any.type == ET_TouchBegin) {
2011         rc = DeliverTouchBeginEvent(dev, ti, ev, listener, client, win, grab,
2012                                     xi2mask);
2013     }
2014     else if (ev->any.type == ET_TouchUpdate) {
2015         if (listener->type == LISTENER_POINTER_REGULAR ||
2016             listener->type == LISTENER_POINTER_GRAB)
2017             DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win, grab,
2018                                       xi2mask);
2019         else if (TouchResourceIsOwner(ti, listener->listener) ||
2020                  has_ownershipmask)
2021             rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
2022     }
2023     else if (ev->any.type == ET_TouchEnd)
2024         rc = DeliverTouchEndEvent(dev, ti, ev, listener, client, win, grab,
2025                                   xi2mask);
2026 
2027  out:
2028     return rc;
2029 }
2030 
2031 /**
2032  * Delivers a touch events to all interested clients.  For TouchBegin events,
2033  * will update ti->listeners, ti->num_listeners, and ti->num_grabs.
2034  * May also mutate ev (type and flags) upon successful delivery.  If
2035  * @resource is non-zero, will only attempt delivery to the owner of that
2036  * resource.
2037  *
2038  * @return TRUE if the event was delivered at least once, FALSE otherwise
2039  */
2040 void
DeliverTouchEvents(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,XID resource)2041 DeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
2042                    InternalEvent *ev, XID resource)
2043 {
2044     int i;
2045 
2046     if (ev->any.type == ET_TouchBegin &&
2047         !(ev->device_event.flags & (TOUCH_CLIENT_ID | TOUCH_REPLAYING)))
2048         TouchSetupListeners(dev, ti, ev);
2049 
2050     TouchEventHistoryPush(ti, &ev->device_event);
2051 
2052     for (i = 0; i < ti->num_listeners; i++) {
2053         GrabPtr grab = NULL;
2054         ClientPtr client;
2055         WindowPtr win;
2056         XI2Mask *mask;
2057         TouchListener *listener = &ti->listeners[i];
2058 
2059         if (resource && listener->listener != resource)
2060             continue;
2061 
2062         if (!RetrieveTouchDeliveryData(dev, ti, ev, listener, &client, &win,
2063                                        &grab, &mask))
2064             continue;
2065 
2066         DeliverTouchEvent(dev, ti, ev, listener, client, win, grab, mask);
2067     }
2068 }
2069 
2070 int
InitProximityClassDeviceStruct(DeviceIntPtr dev)2071 InitProximityClassDeviceStruct(DeviceIntPtr dev)
2072 {
2073     ProximityClassPtr proxc;
2074 
2075     BUG_RETURN_VAL(dev == NULL, FALSE);
2076     BUG_RETURN_VAL(dev->proximity != NULL, FALSE);
2077 
2078     proxc = (ProximityClassPtr) malloc(sizeof(ProximityClassRec));
2079     if (!proxc)
2080         return FALSE;
2081     proxc->sourceid = dev->id;
2082     proxc->in_proximity = TRUE;
2083     dev->proximity = proxc;
2084     return TRUE;
2085 }
2086 
2087 /**
2088  * Initialise the device's valuators. The memory must already be allocated,
2089  * this function merely inits the matching axis (specified through axnum) to
2090  * sane values.
2091  *
2092  * It is a condition that (minval < maxval).
2093  *
2094  * @see InitValuatorClassDeviceStruct
2095  */
2096 Bool
InitValuatorAxisStruct(DeviceIntPtr dev,int axnum,Atom label,int minval,int maxval,int resolution,int min_res,int max_res,int mode)2097 InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval,
2098                        int maxval, int resolution, int min_res, int max_res,
2099                        int mode)
2100 {
2101     AxisInfoPtr ax;
2102 
2103     BUG_RETURN_VAL(dev == NULL, FALSE);
2104     BUG_RETURN_VAL(dev->valuator == NULL, FALSE);
2105     BUG_RETURN_VAL(axnum >= dev->valuator->numAxes, FALSE);
2106     BUG_RETURN_VAL(minval > maxval && mode == Absolute, FALSE);
2107 
2108     ax = dev->valuator->axes + axnum;
2109 
2110     ax->min_value = minval;
2111     ax->max_value = maxval;
2112     ax->resolution = resolution;
2113     ax->min_resolution = min_res;
2114     ax->max_resolution = max_res;
2115     ax->label = label;
2116     ax->mode = mode;
2117 
2118     if (mode & OutOfProximity)
2119         dev->proximity->in_proximity = FALSE;
2120 
2121     return SetScrollValuator(dev, axnum, SCROLL_TYPE_NONE, 0, SCROLL_FLAG_NONE);
2122 }
2123 
2124 /**
2125  * Set the given axis number as a scrolling valuator.
2126  */
2127 Bool
SetScrollValuator(DeviceIntPtr dev,int axnum,enum ScrollType type,double increment,int flags)2128 SetScrollValuator(DeviceIntPtr dev, int axnum, enum ScrollType type,
2129                   double increment, int flags)
2130 {
2131     AxisInfoPtr ax;
2132     int *current_ax;
2133     InternalEvent dce;
2134     DeviceIntPtr master;
2135 
2136     BUG_RETURN_VAL(dev == NULL, FALSE);
2137     BUG_RETURN_VAL(dev->valuator == NULL, FALSE);
2138     BUG_RETURN_VAL(axnum >= dev->valuator->numAxes, FALSE);
2139 
2140     switch (type) {
2141     case SCROLL_TYPE_VERTICAL:
2142         current_ax = &dev->valuator->v_scroll_axis;
2143         break;
2144     case SCROLL_TYPE_HORIZONTAL:
2145         current_ax = &dev->valuator->h_scroll_axis;
2146         break;
2147     case SCROLL_TYPE_NONE:
2148         ax = &dev->valuator->axes[axnum];
2149         ax->scroll.type = type;
2150         return TRUE;
2151     default:
2152         return FALSE;
2153     }
2154 
2155     if (increment == 0.0)
2156         return FALSE;
2157 
2158     if (*current_ax != -1 && axnum != *current_ax) {
2159         ax = &dev->valuator->axes[*current_ax];
2160         if (ax->scroll.type == type &&
2161             (flags & SCROLL_FLAG_PREFERRED) &&
2162             (ax->scroll.flags & SCROLL_FLAG_PREFERRED))
2163             return FALSE;
2164     }
2165     *current_ax = axnum;
2166 
2167     ax = &dev->valuator->axes[axnum];
2168     ax->scroll.type = type;
2169     ax->scroll.increment = increment;
2170     ax->scroll.flags = flags;
2171 
2172     master = GetMaster(dev, MASTER_ATTACHED);
2173     CreateClassesChangedEvent(&dce, master, dev,
2174                               DEVCHANGE_POINTER_EVENT |
2175                               DEVCHANGE_DEVICE_CHANGE);
2176     XISendDeviceChangedEvent(dev, &dce.changed_event);
2177 
2178     /* if the current slave is us, update the master. If not, we'll update
2179      * whenever the next slave switch happens anyway. CMDC sends the event
2180      * for us */
2181     if (master && master->lastSlave == dev)
2182         ChangeMasterDeviceClasses(master, &dce.changed_event);
2183 
2184     return TRUE;
2185 }
2186 
2187 int
CheckGrabValues(ClientPtr client,GrabParameters * param)2188 CheckGrabValues(ClientPtr client, GrabParameters *param)
2189 {
2190     if (param->grabtype != CORE &&
2191         param->grabtype != XI && param->grabtype != XI2) {
2192         ErrorF("[Xi] grabtype is invalid. This is a bug.\n");
2193         return BadImplementation;
2194     }
2195 
2196     if ((param->this_device_mode != GrabModeSync) &&
2197         (param->this_device_mode != GrabModeAsync) &&
2198         (param->this_device_mode != XIGrabModeTouch)) {
2199         client->errorValue = param->this_device_mode;
2200         return BadValue;
2201     }
2202     if ((param->other_devices_mode != GrabModeSync) &&
2203         (param->other_devices_mode != GrabModeAsync) &&
2204         (param->other_devices_mode != XIGrabModeTouch)) {
2205         client->errorValue = param->other_devices_mode;
2206         return BadValue;
2207     }
2208 
2209     if (param->modifiers != AnyModifier &&
2210         param->modifiers != XIAnyModifier &&
2211         (param->modifiers & ~AllModifiersMask)) {
2212         client->errorValue = param->modifiers;
2213         return BadValue;
2214     }
2215 
2216     if ((param->ownerEvents != xFalse) && (param->ownerEvents != xTrue)) {
2217         client->errorValue = param->ownerEvents;
2218         return BadValue;
2219     }
2220     return Success;
2221 }
2222 
2223 int
GrabButton(ClientPtr client,DeviceIntPtr dev,DeviceIntPtr modifier_device,int button,GrabParameters * param,enum InputLevel grabtype,GrabMask * mask)2224 GrabButton(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device,
2225            int button, GrabParameters *param, enum InputLevel grabtype,
2226            GrabMask *mask)
2227 {
2228     WindowPtr pWin, confineTo;
2229     CursorPtr cursor;
2230     GrabPtr grab;
2231     int rc, type = -1;
2232     Mask access_mode = DixGrabAccess;
2233 
2234     rc = CheckGrabValues(client, param);
2235     if (rc != Success)
2236         return rc;
2237     if (param->confineTo == None)
2238         confineTo = NullWindow;
2239     else {
2240         rc = dixLookupWindow(&confineTo, param->confineTo, client,
2241                              DixSetAttrAccess);
2242         if (rc != Success)
2243             return rc;
2244     }
2245     if (param->cursor == None)
2246         cursor = NullCursor;
2247     else {
2248         rc = dixLookupResourceByType((void **) &cursor, param->cursor,
2249                                      RT_CURSOR, client, DixUseAccess);
2250         if (rc != Success) {
2251             client->errorValue = param->cursor;
2252             return rc;
2253         }
2254         access_mode |= DixForceAccess;
2255     }
2256     if (param->this_device_mode == GrabModeSync ||
2257         param->other_devices_mode == GrabModeSync)
2258         access_mode |= DixFreezeAccess;
2259     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
2260     if (rc != Success)
2261         return rc;
2262     rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
2263     if (rc != Success)
2264         return rc;
2265 
2266     if (grabtype == XI)
2267         type = DeviceButtonPress;
2268     else if (grabtype == XI2)
2269         type = XI_ButtonPress;
2270 
2271     grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype,
2272                       mask, param, type, button, confineTo, cursor);
2273     if (!grab)
2274         return BadAlloc;
2275     return AddPassiveGrabToList(client, grab);
2276 }
2277 
2278 /**
2279  * Grab the given key.
2280  */
2281 int
GrabKey(ClientPtr client,DeviceIntPtr dev,DeviceIntPtr modifier_device,int key,GrabParameters * param,enum InputLevel grabtype,GrabMask * mask)2282 GrabKey(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device,
2283         int key, GrabParameters *param, enum InputLevel grabtype,
2284         GrabMask *mask)
2285 {
2286     WindowPtr pWin;
2287     GrabPtr grab;
2288     KeyClassPtr k = dev->key;
2289     Mask access_mode = DixGrabAccess;
2290     int rc, type = -1;
2291 
2292     rc = CheckGrabValues(client, param);
2293     if (rc != Success)
2294         return rc;
2295     if ((dev->id != XIAllDevices && dev->id != XIAllMasterDevices) && k == NULL)
2296         return BadMatch;
2297     if (grabtype == XI) {
2298         if ((key > k->xkbInfo->desc->max_key_code ||
2299              key < k->xkbInfo->desc->min_key_code)
2300             && (key != AnyKey)) {
2301             client->errorValue = key;
2302             return BadValue;
2303         }
2304         type = DeviceKeyPress;
2305     }
2306     else if (grabtype == XI2)
2307         type = XI_KeyPress;
2308 
2309     rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
2310     if (rc != Success)
2311         return rc;
2312     if (param->this_device_mode == GrabModeSync ||
2313         param->other_devices_mode == GrabModeSync)
2314         access_mode |= DixFreezeAccess;
2315     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
2316     if (rc != Success)
2317         return rc;
2318 
2319     grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype,
2320                       mask, param, type, key, NULL, NULL);
2321     if (!grab)
2322         return BadAlloc;
2323     return AddPassiveGrabToList(client, grab);
2324 }
2325 
2326 /* Enter/FocusIn grab */
2327 int
GrabWindow(ClientPtr client,DeviceIntPtr dev,int type,GrabParameters * param,GrabMask * mask)2328 GrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
2329            GrabParameters *param, GrabMask *mask)
2330 {
2331     WindowPtr pWin;
2332     CursorPtr cursor;
2333     GrabPtr grab;
2334     Mask access_mode = DixGrabAccess;
2335     int rc;
2336 
2337     rc = CheckGrabValues(client, param);
2338     if (rc != Success)
2339         return rc;
2340 
2341     rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
2342     if (rc != Success)
2343         return rc;
2344     if (param->cursor == None)
2345         cursor = NullCursor;
2346     else {
2347         rc = dixLookupResourceByType((void **) &cursor, param->cursor,
2348                                      RT_CURSOR, client, DixUseAccess);
2349         if (rc != Success) {
2350             client->errorValue = param->cursor;
2351             return rc;
2352         }
2353         access_mode |= DixForceAccess;
2354     }
2355     if (param->this_device_mode == GrabModeSync ||
2356         param->other_devices_mode == GrabModeSync)
2357         access_mode |= DixFreezeAccess;
2358     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
2359     if (rc != Success)
2360         return rc;
2361 
2362     grab = CreateGrab(client->index, dev, dev, pWin, XI2,
2363                       mask, param,
2364                       (type == XIGrabtypeEnter) ? XI_Enter : XI_FocusIn, 0,
2365                       NULL, cursor);
2366 
2367     if (!grab)
2368         return BadAlloc;
2369 
2370     return AddPassiveGrabToList(client, grab);
2371 }
2372 
2373 /* Touch grab */
2374 int
GrabTouch(ClientPtr client,DeviceIntPtr dev,DeviceIntPtr mod_dev,GrabParameters * param,GrabMask * mask)2375 GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
2376           GrabParameters *param, GrabMask *mask)
2377 {
2378     WindowPtr pWin;
2379     GrabPtr grab;
2380     int rc;
2381 
2382     rc = CheckGrabValues(client, param);
2383     if (rc != Success)
2384         return rc;
2385 
2386     rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
2387     if (rc != Success)
2388         return rc;
2389     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGrabAccess);
2390     if (rc != Success)
2391         return rc;
2392 
2393     grab = CreateGrab(client->index, dev, mod_dev, pWin, XI2,
2394                       mask, param, XI_TouchBegin, 0, NullWindow, NullCursor);
2395     if (!grab)
2396         return BadAlloc;
2397 
2398     return AddPassiveGrabToList(client, grab);
2399 }
2400 
2401 int
SelectForWindow(DeviceIntPtr dev,WindowPtr pWin,ClientPtr client,Mask mask,Mask exclusivemasks)2402 SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client,
2403                 Mask mask, Mask exclusivemasks)
2404 {
2405     int mskidx = dev->id;
2406     int i, ret;
2407     Mask check;
2408     InputClientsPtr others;
2409 
2410     check = (mask & exclusivemasks);
2411     if (wOtherInputMasks(pWin)) {
2412         if (check & wOtherInputMasks(pWin)->inputEvents[mskidx]) {
2413             /* It is illegal for two different clients to select on any of
2414              * the events for maskcheck. However, it is OK, for some client
2415              * to continue selecting on one of those events.
2416              */
2417             for (others = wOtherInputMasks(pWin)->inputClients; others;
2418                  others = others->next) {
2419                 if (!SameClient(others, client) && (check &
2420                                                     others->mask[mskidx]))
2421                     return BadAccess;
2422             }
2423         }
2424         for (others = wOtherInputMasks(pWin)->inputClients; others;
2425              others = others->next) {
2426             if (SameClient(others, client)) {
2427                 check = others->mask[mskidx];
2428                 others->mask[mskidx] = mask;
2429                 if (mask == 0) {
2430                     for (i = 0; i < EMASKSIZE; i++)
2431                         if (i != mskidx && others->mask[i] != 0)
2432                             break;
2433                     if (i == EMASKSIZE) {
2434                         RecalculateDeviceDeliverableEvents(pWin);
2435                         if (ShouldFreeInputMasks(pWin, FALSE))
2436                             FreeResource(others->resource, RT_NONE);
2437                         return Success;
2438                     }
2439                 }
2440                 goto maskSet;
2441             }
2442         }
2443     }
2444     check = 0;
2445     if ((ret = AddExtensionClient(pWin, client, mask, mskidx)) != Success)
2446         return ret;
2447  maskSet:
2448     if (dev->valuator)
2449         if ((dev->valuator->motionHintWindow == pWin) &&
2450             (mask & DevicePointerMotionHintMask) &&
2451             !(check & DevicePointerMotionHintMask) && !dev->deviceGrab.grab)
2452             dev->valuator->motionHintWindow = NullWindow;
2453     RecalculateDeviceDeliverableEvents(pWin);
2454     return Success;
2455 }
2456 
2457 static void
FreeInputClient(InputClientsPtr * other)2458 FreeInputClient(InputClientsPtr * other)
2459 {
2460     xi2mask_free(&(*other)->xi2mask);
2461     free(*other);
2462     *other = NULL;
2463 }
2464 
2465 static InputClientsPtr
AllocInputClient(void)2466 AllocInputClient(void)
2467 {
2468     return calloc(1, sizeof(InputClients));
2469 }
2470 
2471 int
AddExtensionClient(WindowPtr pWin,ClientPtr client,Mask mask,int mskidx)2472 AddExtensionClient(WindowPtr pWin, ClientPtr client, Mask mask, int mskidx)
2473 {
2474     InputClientsPtr others;
2475 
2476     if (!pWin->optional && !MakeWindowOptional(pWin))
2477         return BadAlloc;
2478     others = AllocInputClient();
2479     if (!others)
2480         return BadAlloc;
2481     if (!pWin->optional->inputMasks && !MakeInputMasks(pWin))
2482         goto bail;
2483     others->xi2mask = xi2mask_new();
2484     if (!others->xi2mask)
2485         goto bail;
2486     others->mask[mskidx] = mask;
2487     others->resource = FakeClientID(client->index);
2488     others->next = pWin->optional->inputMasks->inputClients;
2489     pWin->optional->inputMasks->inputClients = others;
2490     if (!AddResource(others->resource, RT_INPUTCLIENT, (void *) pWin))
2491         goto bail;
2492     return Success;
2493 
2494  bail:
2495     FreeInputClient(&others);
2496     return BadAlloc;
2497 }
2498 
2499 static Bool
MakeInputMasks(WindowPtr pWin)2500 MakeInputMasks(WindowPtr pWin)
2501 {
2502     struct _OtherInputMasks *imasks;
2503 
2504     imasks = calloc(1, sizeof(struct _OtherInputMasks));
2505     if (!imasks)
2506         return FALSE;
2507     imasks->xi2mask = xi2mask_new();
2508     if (!imasks->xi2mask) {
2509         free(imasks);
2510         return FALSE;
2511     }
2512     pWin->optional->inputMasks = imasks;
2513     return TRUE;
2514 }
2515 
2516 static void
FreeInputMask(OtherInputMasks ** imask)2517 FreeInputMask(OtherInputMasks ** imask)
2518 {
2519     xi2mask_free(&(*imask)->xi2mask);
2520     free(*imask);
2521     *imask = NULL;
2522 }
2523 
2524 #define XIPropagateMask (KeyPressMask | \
2525                          KeyReleaseMask | \
2526                          ButtonPressMask | \
2527                          ButtonReleaseMask | \
2528                          PointerMotionMask)
2529 
2530 void
RecalculateDeviceDeliverableEvents(WindowPtr pWin)2531 RecalculateDeviceDeliverableEvents(WindowPtr pWin)
2532 {
2533     InputClientsPtr others;
2534     struct _OtherInputMasks *inputMasks;        /* default: NULL */
2535     WindowPtr pChild, tmp;
2536     int i;
2537 
2538     pChild = pWin;
2539     while (1) {
2540         if ((inputMasks = wOtherInputMasks(pChild)) != 0) {
2541             xi2mask_zero(inputMasks->xi2mask, -1);
2542             for (others = inputMasks->inputClients; others;
2543                  others = others->next) {
2544                 for (i = 0; i < EMASKSIZE; i++)
2545                     inputMasks->inputEvents[i] |= others->mask[i];
2546                 xi2mask_merge(inputMasks->xi2mask, others->xi2mask);
2547             }
2548             for (i = 0; i < EMASKSIZE; i++)
2549                 inputMasks->deliverableEvents[i] = inputMasks->inputEvents[i];
2550             for (tmp = pChild->parent; tmp; tmp = tmp->parent)
2551                 if (wOtherInputMasks(tmp))
2552                     for (i = 0; i < EMASKSIZE; i++)
2553                         inputMasks->deliverableEvents[i] |=
2554                             (wOtherInputMasks(tmp)->deliverableEvents[i]
2555                              & ~inputMasks->dontPropagateMask[i] &
2556                              XIPropagateMask);
2557         }
2558         if (pChild->firstChild) {
2559             pChild = pChild->firstChild;
2560             continue;
2561         }
2562         while (!pChild->nextSib && (pChild != pWin))
2563             pChild = pChild->parent;
2564         if (pChild == pWin)
2565             break;
2566         pChild = pChild->nextSib;
2567     }
2568 }
2569 
2570 int
InputClientGone(WindowPtr pWin,XID id)2571 InputClientGone(WindowPtr pWin, XID id)
2572 {
2573     InputClientsPtr other, prev;
2574 
2575     if (!wOtherInputMasks(pWin))
2576         return Success;
2577     prev = 0;
2578     for (other = wOtherInputMasks(pWin)->inputClients; other;
2579          other = other->next) {
2580         if (other->resource == id) {
2581             if (prev) {
2582                 prev->next = other->next;
2583                 FreeInputClient(&other);
2584             }
2585             else if (!(other->next)) {
2586                 if (ShouldFreeInputMasks(pWin, TRUE)) {
2587                     OtherInputMasks *mask = wOtherInputMasks(pWin);
2588 
2589                     mask->inputClients = other->next;
2590                     FreeInputMask(&mask);
2591                     pWin->optional->inputMasks = (OtherInputMasks *) NULL;
2592                     CheckWindowOptionalNeed(pWin);
2593                     FreeInputClient(&other);
2594                 }
2595                 else {
2596                     other->resource = FakeClientID(0);
2597                     if (!AddResource(other->resource, RT_INPUTCLIENT,
2598                                      (void *) pWin))
2599                         return BadAlloc;
2600                 }
2601             }
2602             else {
2603                 wOtherInputMasks(pWin)->inputClients = other->next;
2604                 FreeInputClient(&other);
2605             }
2606             RecalculateDeviceDeliverableEvents(pWin);
2607             return Success;
2608         }
2609         prev = other;
2610     }
2611     FatalError("client not on device event list");
2612 }
2613 
2614 /**
2615  * Search for window in each touch trace for each device. Remove the window
2616  * and all its subwindows from the trace when found. The initial window
2617  * order is preserved.
2618  */
2619 void
WindowGone(WindowPtr win)2620 WindowGone(WindowPtr win)
2621 {
2622     DeviceIntPtr dev;
2623 
2624     for (dev = inputInfo.devices; dev; dev = dev->next) {
2625         TouchClassPtr t = dev->touch;
2626         int i;
2627 
2628         if (!t)
2629             continue;
2630 
2631         for (i = 0; i < t->num_touches; i++) {
2632             SpritePtr sprite = &t->touches[i].sprite;
2633             int j;
2634 
2635             for (j = 0; j < sprite->spriteTraceGood; j++) {
2636                 if (sprite->spriteTrace[j] == win) {
2637                     sprite->spriteTraceGood = j;
2638                     break;
2639                 }
2640             }
2641         }
2642     }
2643 }
2644 
2645 int
SendEvent(ClientPtr client,DeviceIntPtr d,Window dest,Bool propagate,xEvent * ev,Mask mask,int count)2646 SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate,
2647           xEvent *ev, Mask mask, int count)
2648 {
2649     WindowPtr pWin;
2650     WindowPtr effectiveFocus = NullWindow;      /* only set if dest==InputFocus */
2651     WindowPtr spriteWin = GetSpriteWindow(d);
2652 
2653     if (dest == PointerWindow)
2654         pWin = spriteWin;
2655     else if (dest == InputFocus) {
2656         WindowPtr inputFocus;
2657 
2658         if (!d->focus)
2659             inputFocus = spriteWin;
2660         else
2661             inputFocus = d->focus->win;
2662 
2663         if (inputFocus == FollowKeyboardWin)
2664             inputFocus = inputInfo.keyboard->focus->win;
2665 
2666         if (inputFocus == NoneWin)
2667             return Success;
2668 
2669         /* If the input focus is PointerRootWin, send the event to where
2670          * the pointer is if possible, then perhaps propagate up to root. */
2671         if (inputFocus == PointerRootWin)
2672             inputFocus = GetCurrentRootWindow(d);
2673 
2674         if (IsParent(inputFocus, spriteWin)) {
2675             effectiveFocus = inputFocus;
2676             pWin = spriteWin;
2677         }
2678         else
2679             effectiveFocus = pWin = inputFocus;
2680     }
2681     else
2682         dixLookupWindow(&pWin, dest, client, DixSendAccess);
2683     if (!pWin)
2684         return BadWindow;
2685     if ((propagate != xFalse) && (propagate != xTrue)) {
2686         client->errorValue = propagate;
2687         return BadValue;
2688     }
2689     ev->u.u.type |= 0x80;
2690     if (propagate) {
2691         for (; pWin; pWin = pWin->parent) {
2692             if (DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab))
2693                 return Success;
2694             if (pWin == effectiveFocus)
2695                 return Success;
2696             if (wOtherInputMasks(pWin))
2697                 mask &= ~wOtherInputMasks(pWin)->dontPropagateMask[d->id];
2698             if (!mask)
2699                 break;
2700         }
2701     }
2702     else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, ev, count))
2703         DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab);
2704     return Success;
2705 }
2706 
2707 int
SetButtonMapping(ClientPtr client,DeviceIntPtr dev,int nElts,BYTE * map)2708 SetButtonMapping(ClientPtr client, DeviceIntPtr dev, int nElts, BYTE * map)
2709 {
2710     int i;
2711     ButtonClassPtr b = dev->button;
2712 
2713     if (b == NULL)
2714         return BadMatch;
2715 
2716     if (nElts != b->numButtons) {
2717         client->errorValue = nElts;
2718         return BadValue;
2719     }
2720     if (BadDeviceMap(&map[0], nElts, 1, 255, &client->errorValue))
2721         return BadValue;
2722     for (i = 0; i < nElts; i++)
2723         if ((b->map[i + 1] != map[i]) && BitIsOn(b->down, i + 1))
2724             return MappingBusy;
2725     for (i = 0; i < nElts; i++)
2726         b->map[i + 1] = map[i];
2727     return Success;
2728 }
2729 
2730 int
ChangeKeyMapping(ClientPtr client,DeviceIntPtr dev,unsigned len,int type,KeyCode firstKeyCode,CARD8 keyCodes,CARD8 keySymsPerKeyCode,KeySym * map)2731 ChangeKeyMapping(ClientPtr client,
2732                  DeviceIntPtr dev,
2733                  unsigned len,
2734                  int type,
2735                  KeyCode firstKeyCode,
2736                  CARD8 keyCodes, CARD8 keySymsPerKeyCode, KeySym * map)
2737 {
2738     KeySymsRec keysyms;
2739     KeyClassPtr k = dev->key;
2740 
2741     if (k == NULL)
2742         return BadMatch;
2743 
2744     if (len != (keyCodes * keySymsPerKeyCode))
2745         return BadLength;
2746 
2747     if ((firstKeyCode < k->xkbInfo->desc->min_key_code) ||
2748         (firstKeyCode + keyCodes - 1 > k->xkbInfo->desc->max_key_code)) {
2749         client->errorValue = firstKeyCode;
2750         return BadValue;
2751     }
2752     if (keySymsPerKeyCode == 0) {
2753         client->errorValue = 0;
2754         return BadValue;
2755     }
2756     keysyms.minKeyCode = firstKeyCode;
2757     keysyms.maxKeyCode = firstKeyCode + keyCodes - 1;
2758     keysyms.mapWidth = keySymsPerKeyCode;
2759     keysyms.map = map;
2760 
2761     XkbApplyMappingChange(dev, &keysyms, firstKeyCode, keyCodes, NULL,
2762                           serverClient);
2763 
2764     return Success;
2765 }
2766 
2767 static void
DeleteDeviceFromAnyExtEvents(WindowPtr pWin,DeviceIntPtr dev)2768 DeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev)
2769 {
2770     WindowPtr parent;
2771 
2772     /* Deactivate any grabs performed on this window, before making
2773      * any input focus changes.
2774      * Deactivating a device grab should cause focus events. */
2775 
2776     if (dev->deviceGrab.grab && (dev->deviceGrab.grab->window == pWin))
2777         (*dev->deviceGrab.DeactivateGrab) (dev);
2778 
2779     /* If the focus window is a root window (ie. has no parent)
2780      * then don't delete the focus from it. */
2781 
2782     if (dev->focus && (pWin == dev->focus->win) && (pWin->parent != NullWindow)) {
2783         int focusEventMode = NotifyNormal;
2784 
2785         /* If a grab is in progress, then alter the mode of focus events. */
2786 
2787         if (dev->deviceGrab.grab)
2788             focusEventMode = NotifyWhileGrabbed;
2789 
2790         switch (dev->focus->revert) {
2791         case RevertToNone:
2792             if (!ActivateFocusInGrab(dev, pWin, NoneWin))
2793                 DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
2794             dev->focus->win = NoneWin;
2795             dev->focus->traceGood = 0;
2796             break;
2797         case RevertToParent:
2798             parent = pWin;
2799             do {
2800                 parent = parent->parent;
2801                 dev->focus->traceGood--;
2802             }
2803             while (!parent->realized);
2804             if (!ActivateFocusInGrab(dev, pWin, parent))
2805                 DoFocusEvents(dev, pWin, parent, focusEventMode);
2806             dev->focus->win = parent;
2807             dev->focus->revert = RevertToNone;
2808             break;
2809         case RevertToPointerRoot:
2810             if (!ActivateFocusInGrab(dev, pWin, PointerRootWin))
2811                 DoFocusEvents(dev, pWin, PointerRootWin, focusEventMode);
2812             dev->focus->win = PointerRootWin;
2813             dev->focus->traceGood = 0;
2814             break;
2815         case RevertToFollowKeyboard:
2816         {
2817             DeviceIntPtr kbd = GetMaster(dev, MASTER_KEYBOARD);
2818 
2819             if (!kbd || (kbd == dev && kbd != inputInfo.keyboard))
2820                 kbd = inputInfo.keyboard;
2821             if (kbd->focus->win) {
2822                 if (!ActivateFocusInGrab(dev, pWin, kbd->focus->win))
2823                     DoFocusEvents(dev, pWin, kbd->focus->win, focusEventMode);
2824                 dev->focus->win = FollowKeyboardWin;
2825                 dev->focus->traceGood = 0;
2826             }
2827             else {
2828                 if (!ActivateFocusInGrab(dev, pWin, NoneWin))
2829                     DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
2830                 dev->focus->win = NoneWin;
2831                 dev->focus->traceGood = 0;
2832             }
2833         }
2834             break;
2835         }
2836     }
2837 
2838     if (dev->valuator)
2839         if (dev->valuator->motionHintWindow == pWin)
2840             dev->valuator->motionHintWindow = NullWindow;
2841 }
2842 
2843 void
DeleteWindowFromAnyExtEvents(WindowPtr pWin,Bool freeResources)2844 DeleteWindowFromAnyExtEvents(WindowPtr pWin, Bool freeResources)
2845 {
2846     int i;
2847     DeviceIntPtr dev;
2848     InputClientsPtr ic;
2849     struct _OtherInputMasks *inputMasks;
2850 
2851     for (dev = inputInfo.devices; dev; dev = dev->next) {
2852         DeleteDeviceFromAnyExtEvents(pWin, dev);
2853     }
2854 
2855     for (dev = inputInfo.off_devices; dev; dev = dev->next)
2856         DeleteDeviceFromAnyExtEvents(pWin, dev);
2857 
2858     if (freeResources)
2859         while ((inputMasks = wOtherInputMasks(pWin)) != 0) {
2860             ic = inputMasks->inputClients;
2861             for (i = 0; i < EMASKSIZE; i++)
2862                 inputMasks->dontPropagateMask[i] = 0;
2863             FreeResource(ic->resource, RT_NONE);
2864         }
2865 }
2866 
2867 int
MaybeSendDeviceMotionNotifyHint(deviceKeyButtonPointer * pEvents,Mask mask)2868 MaybeSendDeviceMotionNotifyHint(deviceKeyButtonPointer *pEvents, Mask mask)
2869 {
2870     DeviceIntPtr dev;
2871 
2872     dixLookupDevice(&dev, pEvents->deviceid & DEVICE_BITS, serverClient,
2873                     DixReadAccess);
2874     if (!dev)
2875         return 0;
2876 
2877     if (pEvents->type == DeviceMotionNotify) {
2878         if (mask & DevicePointerMotionHintMask) {
2879             if (WID(dev->valuator->motionHintWindow) == pEvents->event) {
2880                 return 1;       /* don't send, but pretend we did */
2881             }
2882             pEvents->detail = NotifyHint;
2883         }
2884         else {
2885             pEvents->detail = NotifyNormal;
2886         }
2887     }
2888     return 0;
2889 }
2890 
2891 void
CheckDeviceGrabAndHintWindow(WindowPtr pWin,int type,deviceKeyButtonPointer * xE,GrabPtr grab,ClientPtr client,Mask deliveryMask)2892 CheckDeviceGrabAndHintWindow(WindowPtr pWin, int type,
2893                              deviceKeyButtonPointer *xE, GrabPtr grab,
2894                              ClientPtr client, Mask deliveryMask)
2895 {
2896     DeviceIntPtr dev;
2897 
2898     dixLookupDevice(&dev, xE->deviceid & DEVICE_BITS, serverClient,
2899                     DixGrabAccess);
2900     if (!dev)
2901         return;
2902 
2903     if (type == DeviceMotionNotify)
2904         dev->valuator->motionHintWindow = pWin;
2905     else if ((type == DeviceButtonPress) && (!grab) &&
2906              (deliveryMask & DeviceButtonGrabMask)) {
2907         GrabPtr tempGrab;
2908 
2909         tempGrab = AllocGrab(NULL);
2910         if (!tempGrab)
2911             return;
2912 
2913         tempGrab->device = dev;
2914         tempGrab->resource = client->clientAsMask;
2915         tempGrab->window = pWin;
2916         tempGrab->ownerEvents =
2917             (deliveryMask & DeviceOwnerGrabButtonMask) ? TRUE : FALSE;
2918         tempGrab->eventMask = deliveryMask;
2919         tempGrab->keyboardMode = GrabModeAsync;
2920         tempGrab->pointerMode = GrabModeAsync;
2921         tempGrab->confineTo = NullWindow;
2922         tempGrab->cursor = NullCursor;
2923         tempGrab->next = NULL;
2924         (*dev->deviceGrab.ActivateGrab) (dev, tempGrab, currentTime, TRUE);
2925         FreeGrab(tempGrab);
2926     }
2927 }
2928 
2929 static Mask
DeviceEventMaskForClient(DeviceIntPtr dev,WindowPtr pWin,ClientPtr client)2930 DeviceEventMaskForClient(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client)
2931 {
2932     InputClientsPtr other;
2933 
2934     if (!wOtherInputMasks(pWin))
2935         return 0;
2936     for (other = wOtherInputMasks(pWin)->inputClients; other;
2937          other = other->next) {
2938         if (SameClient(other, client))
2939             return other->mask[dev->id];
2940     }
2941     return 0;
2942 }
2943 
2944 void
MaybeStopDeviceHint(DeviceIntPtr dev,ClientPtr client)2945 MaybeStopDeviceHint(DeviceIntPtr dev, ClientPtr client)
2946 {
2947     WindowPtr pWin;
2948     GrabPtr grab = dev->deviceGrab.grab;
2949 
2950     pWin = dev->valuator->motionHintWindow;
2951 
2952     if ((grab && SameClient(grab, client) &&
2953          ((grab->eventMask & DevicePointerMotionHintMask) ||
2954           (grab->ownerEvents &&
2955            (DeviceEventMaskForClient(dev, pWin, client) &
2956             DevicePointerMotionHintMask)))) ||
2957         (!grab &&
2958          (DeviceEventMaskForClient(dev, pWin, client) &
2959           DevicePointerMotionHintMask)))
2960         dev->valuator->motionHintWindow = NullWindow;
2961 }
2962 
2963 int
DeviceEventSuppressForWindow(WindowPtr pWin,ClientPtr client,Mask mask,int maskndx)2964 DeviceEventSuppressForWindow(WindowPtr pWin, ClientPtr client, Mask mask,
2965                              int maskndx)
2966 {
2967     struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
2968 
2969     if (mask & ~XIPropagateMask) {
2970         client->errorValue = mask;
2971         return BadValue;
2972     }
2973 
2974     if (mask == 0) {
2975         if (inputMasks)
2976             inputMasks->dontPropagateMask[maskndx] = mask;
2977     }
2978     else {
2979         if (!inputMasks)
2980             AddExtensionClient(pWin, client, 0, 0);
2981         inputMasks = wOtherInputMasks(pWin);
2982         inputMasks->dontPropagateMask[maskndx] = mask;
2983     }
2984     RecalculateDeviceDeliverableEvents(pWin);
2985     if (ShouldFreeInputMasks(pWin, FALSE))
2986         FreeResource(inputMasks->inputClients->resource, RT_NONE);
2987     return Success;
2988 }
2989 
2990 Bool
ShouldFreeInputMasks(WindowPtr pWin,Bool ignoreSelectedEvents)2991 ShouldFreeInputMasks(WindowPtr pWin, Bool ignoreSelectedEvents)
2992 {
2993     int i;
2994     Mask allInputEventMasks = 0;
2995     struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
2996 
2997     for (i = 0; i < EMASKSIZE; i++)
2998         allInputEventMasks |= inputMasks->dontPropagateMask[i];
2999     if (!ignoreSelectedEvents)
3000         for (i = 0; i < EMASKSIZE; i++)
3001             allInputEventMasks |= inputMasks->inputEvents[i];
3002     if (allInputEventMasks == 0)
3003         return TRUE;
3004     else
3005         return FALSE;
3006 }
3007 
3008 /***********************************************************************
3009  *
3010  * Walk through the window tree, finding all clients that want to know
3011  * about the Event.
3012  *
3013  */
3014 
3015 static void
FindInterestedChildren(DeviceIntPtr dev,WindowPtr p1,Mask mask,xEvent * ev,int count)3016 FindInterestedChildren(DeviceIntPtr dev, WindowPtr p1, Mask mask,
3017                        xEvent *ev, int count)
3018 {
3019     WindowPtr p2;
3020 
3021     while (p1) {
3022         p2 = p1->firstChild;
3023         DeliverEventsToWindow(dev, p1, ev, count, mask, NullGrab);
3024         FindInterestedChildren(dev, p2, mask, ev, count);
3025         p1 = p1->nextSib;
3026     }
3027 }
3028 
3029 /***********************************************************************
3030  *
3031  * Send an event to interested clients in all windows on all screens.
3032  *
3033  */
3034 
3035 void
SendEventToAllWindows(DeviceIntPtr dev,Mask mask,xEvent * ev,int count)3036 SendEventToAllWindows(DeviceIntPtr dev, Mask mask, xEvent *ev, int count)
3037 {
3038     int i;
3039     WindowPtr pWin, p1;
3040 
3041     for (i = 0; i < screenInfo.numScreens; i++) {
3042         pWin = screenInfo.screens[i]->root;
3043         if (!pWin)
3044             continue;
3045         DeliverEventsToWindow(dev, pWin, ev, count, mask, NullGrab);
3046         p1 = pWin->firstChild;
3047         FindInterestedChildren(dev, p1, mask, ev, count);
3048     }
3049 }
3050 
3051 /**
3052  * Set the XI2 mask for the given client on the given window.
3053  * @param dev The device to set the mask for.
3054  * @param win The window to set the mask on.
3055  * @param client The client setting the mask.
3056  * @param len Number of bytes in mask.
3057  * @param mask Event mask in the form of (1 << eventtype)
3058  */
3059 int
XISetEventMask(DeviceIntPtr dev,WindowPtr win,ClientPtr client,unsigned int len,unsigned char * mask)3060 XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client,
3061                unsigned int len, unsigned char *mask)
3062 {
3063     OtherInputMasks *masks;
3064     InputClientsPtr others = NULL;
3065 
3066     masks = wOtherInputMasks(win);
3067     if (masks) {
3068         for (others = wOtherInputMasks(win)->inputClients; others;
3069              others = others->next) {
3070             if (SameClient(others, client)) {
3071                 xi2mask_zero(others->xi2mask, dev->id);
3072                 break;
3073             }
3074         }
3075     }
3076 
3077     if (len && !others) {
3078         if (AddExtensionClient(win, client, 0, 0) != Success)
3079             return BadAlloc;
3080         others = wOtherInputMasks(win)->inputClients;
3081     }
3082 
3083     if (others) {
3084         xi2mask_zero(others->xi2mask, dev->id);
3085         len = min(len, xi2mask_mask_size(others->xi2mask));
3086     }
3087 
3088     if (len) {
3089         xi2mask_set_one_mask(others->xi2mask, dev->id, mask, len);
3090     }
3091 
3092     RecalculateDeviceDeliverableEvents(win);
3093 
3094     return Success;
3095 }
3096