xref: /OK3568_Linux_fs/external/xserver/Xi/exevents.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 currenly 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 = DevicePointerMotionMask | state | motion_mask;
750     SetMaskForEvent(device->id, mask, DeviceMotionNotify);
751     mask = PointerMotionMask | state | motion_mask;
752     SetMaskForEvent(device->id, mask, MotionNotify);
753 }
754 
755 static void
IncreaseButtonCount(DeviceIntPtr dev,int key,CARD8 * buttons_down,Mask * motion_mask,unsigned short * state)756 IncreaseButtonCount(DeviceIntPtr dev, int key, CARD8 *buttons_down,
757                     Mask *motion_mask, unsigned short *state)
758 {
759     if (dev->valuator)
760         dev->valuator->motionHintWindow = NullWindow;
761 
762     (*buttons_down)++;
763     *motion_mask = DeviceButtonMotionMask;
764     if (dev->button->map[key] <= 5)
765         *state |= (Button1Mask >> 1) << dev->button->map[key];
766 }
767 
768 static void
DecreaseButtonCount(DeviceIntPtr dev,int key,CARD8 * buttons_down,Mask * motion_mask,unsigned short * state)769 DecreaseButtonCount(DeviceIntPtr dev, int key, CARD8 *buttons_down,
770                     Mask *motion_mask, unsigned short *state)
771 {
772     if (dev->valuator)
773         dev->valuator->motionHintWindow = NullWindow;
774 
775     if (*buttons_down >= 1 && !--(*buttons_down))
776         *motion_mask = 0;
777     if (dev->button->map[key] <= 5)
778         *state &= ~((Button1Mask >> 1) << dev->button->map[key]);
779 }
780 
781 /**
782  * Update the device state according to the data in the event.
783  *
784  * return values are
785  *   DEFAULT ... process as normal
786  *   DONT_PROCESS ... return immediately from caller
787  */
788 #define DEFAULT 0
789 #define DONT_PROCESS 1
790 int
UpdateDeviceState(DeviceIntPtr device,DeviceEvent * event)791 UpdateDeviceState(DeviceIntPtr device, DeviceEvent *event)
792 {
793     int i;
794     int key = 0, last_valuator;
795 
796     KeyClassPtr k = NULL;
797     ButtonClassPtr b = NULL;
798     ValuatorClassPtr v = NULL;
799     TouchClassPtr t = NULL;
800 
801     /* This event is always the first we get, before the actual events with
802      * the data. However, the way how the DDX is set up, "device" will
803      * actually be the slave device that caused the event.
804      */
805     switch (event->type) {
806     case ET_DeviceChanged:
807         ChangeMasterDeviceClasses(device, (DeviceChangedEvent *) event);
808         return DONT_PROCESS;    /* event has been sent already */
809     case ET_Motion:
810     case ET_ButtonPress:
811     case ET_ButtonRelease:
812     case ET_KeyPress:
813     case ET_KeyRelease:
814     case ET_ProximityIn:
815     case ET_ProximityOut:
816     case ET_TouchBegin:
817     case ET_TouchUpdate:
818     case ET_TouchEnd:
819         break;
820     default:
821         /* other events don't update the device */
822         return DEFAULT;
823     }
824 
825     k = device->key;
826     v = device->valuator;
827     b = device->button;
828     t = device->touch;
829 
830     key = event->detail.key;
831 
832     /* Update device axis */
833     /* Check valuators first */
834     last_valuator = -1;
835     for (i = 0; i < MAX_VALUATORS; i++) {
836         if (BitIsOn(&event->valuators.mask, i)) {
837             if (!v) {
838                 ErrorF("[Xi] Valuators reported for non-valuator device '%s'. "
839                        "Ignoring event.\n", device->name);
840                 return DONT_PROCESS;
841             }
842             else if (v->numAxes < i) {
843                 ErrorF("[Xi] Too many valuators reported for device '%s'. "
844                        "Ignoring event.\n", device->name);
845                 return DONT_PROCESS;
846             }
847             last_valuator = i;
848         }
849     }
850 
851     for (i = 0; i <= last_valuator && i < v->numAxes; i++) {
852         /* XXX: Relative/Absolute mode */
853         if (BitIsOn(&event->valuators.mask, i))
854             v->axisVal[i] = event->valuators.data[i];
855     }
856 
857     if (event->type == ET_KeyPress) {
858         if (!k)
859             return DONT_PROCESS;
860 
861         /* don't allow ddx to generate multiple downs, but repeats are okay */
862         if (key_is_down(device, key, KEY_PROCESSED) && !event->key_repeat)
863             return DONT_PROCESS;
864 
865         if (device->valuator)
866             device->valuator->motionHintWindow = NullWindow;
867         set_key_down(device, key, KEY_PROCESSED);
868     }
869     else if (event->type == ET_KeyRelease) {
870         if (!k)
871             return DONT_PROCESS;
872 
873         if (!key_is_down(device, key, KEY_PROCESSED))   /* guard against duplicates */
874             return DONT_PROCESS;
875         if (device->valuator)
876             device->valuator->motionHintWindow = NullWindow;
877         set_key_up(device, key, KEY_PROCESSED);
878     }
879     else if (event->type == ET_ButtonPress) {
880         if (!b)
881             return DONT_PROCESS;
882 
883         if (button_is_down(device, key, BUTTON_PROCESSED))
884             return DONT_PROCESS;
885 
886         set_button_down(device, key, BUTTON_PROCESSED);
887 
888         if (!b->map[key])
889             return DONT_PROCESS;
890 
891         IncreaseButtonCount(device, key, &b->buttonsDown, &b->motionMask,
892                             &b->state);
893         UpdateDeviceMotionMask(device, b->state, b->motionMask);
894     }
895     else if (event->type == ET_ButtonRelease) {
896         if (!b)
897             return DONT_PROCESS;
898 
899         if (!button_is_down(device, key, BUTTON_PROCESSED))
900             return DONT_PROCESS;
901         if (IsMaster(device)) {
902             DeviceIntPtr sd;
903 
904             /*
905              * Leave the button down if any slave has the
906              * button still down. Note that this depends on the
907              * event being delivered through the slave first
908              */
909             for (sd = inputInfo.devices; sd; sd = sd->next) {
910                 if (IsMaster(sd) || GetMaster(sd, MASTER_POINTER) != device)
911                     continue;
912                 if (!sd->button)
913                     continue;
914                 for (i = 1; i <= sd->button->numButtons; i++)
915                     if (sd->button->map[i] == key &&
916                         button_is_down(sd, i, BUTTON_PROCESSED))
917                         return DONT_PROCESS;
918             }
919         }
920         set_button_up(device, key, BUTTON_PROCESSED);
921         if (!b->map[key])
922             return DONT_PROCESS;
923 
924         DecreaseButtonCount(device, key, &b->buttonsDown, &b->motionMask,
925                             &b->state);
926         UpdateDeviceMotionMask(device, b->state, b->motionMask);
927     }
928     else if (event->type == ET_ProximityIn)
929         device->proximity->in_proximity = TRUE;
930     else if (event->type == ET_ProximityOut)
931         device->proximity->in_proximity = FALSE;
932     else if (event->type == ET_TouchBegin) {
933         BUG_RETURN_VAL(!b || !v, DONT_PROCESS);
934         BUG_RETURN_VAL(!t, DONT_PROCESS);
935 
936         if (!b->map[key])
937             return DONT_PROCESS;
938 
939         if (!(event->flags & TOUCH_POINTER_EMULATED) ||
940             (event->flags & TOUCH_REPLAYING))
941             return DONT_PROCESS;
942 
943         IncreaseButtonCount(device, key, &t->buttonsDown, &t->motionMask,
944                             &t->state);
945         UpdateDeviceMotionMask(device, t->state, DeviceButtonMotionMask);
946     }
947     else if (event->type == ET_TouchEnd) {
948         BUG_RETURN_VAL(!b || !v, DONT_PROCESS);
949         BUG_RETURN_VAL(!t, DONT_PROCESS);
950 
951         if (t->buttonsDown <= 0 || !b->map[key])
952             return DONT_PROCESS;
953 
954         if (!(event->flags & TOUCH_POINTER_EMULATED))
955             return DONT_PROCESS;
956 
957         DecreaseButtonCount(device, key, &t->buttonsDown, &t->motionMask,
958                             &t->state);
959         UpdateDeviceMotionMask(device, t->state, DeviceButtonMotionMask);
960     }
961 
962     return DEFAULT;
963 }
964 
965 /**
966  * A client that does not have the TouchOwnership mask set may not receive a
967  * TouchBegin event if there is at least one grab active.
968  *
969  * @return TRUE if the client selected for ownership events on the given
970  * window for this device, FALSE otherwise
971  */
972 static inline Bool
TouchClientWantsOwnershipEvents(ClientPtr client,DeviceIntPtr dev,WindowPtr win)973 TouchClientWantsOwnershipEvents(ClientPtr client, DeviceIntPtr dev,
974                                 WindowPtr win)
975 {
976     InputClients *iclient;
977 
978     nt_list_for_each_entry(iclient, wOtherInputMasks(win)->inputClients, next) {
979         if (rClient(iclient) != client)
980             continue;
981 
982         return xi2mask_isset(iclient->xi2mask, dev, XI_TouchOwnership);
983     }
984 
985     return FALSE;
986 }
987 
988 static void
TouchSendOwnershipEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,int reason,XID resource)989 TouchSendOwnershipEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, int reason,
990                         XID resource)
991 {
992     int nev, i;
993     InternalEvent *tel = InitEventList(GetMaximumEventsNum());
994 
995     nev = GetTouchOwnershipEvents(tel, dev, ti, reason, resource, 0);
996     for (i = 0; i < nev; i++)
997         mieqProcessDeviceEvent(dev, tel + i, NULL);
998 
999     FreeEventList(tel, GetMaximumEventsNum());
1000 }
1001 
1002 /**
1003  * Attempts to deliver a touch event to the given client.
1004  */
1005 static Bool
DeliverOneTouchEvent(ClientPtr client,DeviceIntPtr dev,TouchPointInfoPtr ti,GrabPtr grab,WindowPtr win,InternalEvent * ev)1006 DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
1007                      GrabPtr grab, WindowPtr win, InternalEvent *ev)
1008 {
1009     int err;
1010     xEvent *xi2;
1011     Mask filter;
1012     Window child = DeepestSpriteWin(&ti->sprite)->drawable.id;
1013 
1014     /* FIXME: owner event handling */
1015 
1016     /* If the client does not have the ownership mask set and is not
1017      * the current owner of the touch, only pretend we delivered */
1018     if (!grab && ti->num_grabs != 0 &&
1019         !TouchClientWantsOwnershipEvents(client, dev, win))
1020         return TRUE;
1021 
1022     /* If we fail here, we're going to leave a client hanging. */
1023     err = EventToXI2(ev, &xi2);
1024     if (err != Success)
1025         FatalError("[Xi] %s: XI2 conversion failed in %s"
1026                    " (%d)\n", dev->name, __func__, err);
1027 
1028     FixUpEventFromWindow(&ti->sprite, xi2, win, child, FALSE);
1029     filter = GetEventFilter(dev, xi2);
1030     if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) != Success)
1031         return FALSE;
1032     err = TryClientEvents(client, dev, xi2, 1, filter, filter, NullGrab);
1033     free(xi2);
1034 
1035     if (ev->any.type == ET_TouchUpdate && ti->pending_finish) {
1036         ev->any.type = ET_TouchEnd;
1037         DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
1038     }
1039 
1040     /* Returning the value from TryClientEvents isn't useful, since all our
1041      * resource-gone cleanups will update the delivery list anyway. */
1042     return TRUE;
1043 }
1044 
1045 static void
ActivateEarlyAccept(DeviceIntPtr dev,TouchPointInfoPtr ti)1046 ActivateEarlyAccept(DeviceIntPtr dev, TouchPointInfoPtr ti)
1047 {
1048     ClientPtr client;
1049     XID error;
1050     GrabPtr grab = ti->listeners[0].grab;
1051 
1052     BUG_RETURN(ti->listeners[0].type != LISTENER_GRAB &&
1053                ti->listeners[0].type != LISTENER_POINTER_GRAB);
1054     BUG_RETURN(!grab);
1055 
1056     client = rClient(grab);
1057 
1058     if (TouchAcceptReject(client, dev, XIAcceptTouch, ti->client_id,
1059                           ti->listeners[0].window->drawable.id, &error) != Success)
1060         ErrorF("[Xi] Failed to accept touch grab after early acceptance.\n");
1061 }
1062 
1063 /**
1064  * Find the oldest touch that still has a pointer emulation client.
1065  *
1066  * Pointer emulation can only be performed for the oldest touch. Otherwise, the
1067  * order of events seen by the client will be wrong. This function helps us find
1068  * the next touch to be emulated.
1069  *
1070  * @param dev The device to find touches for.
1071  */
1072 static TouchPointInfoPtr
FindOldestPointerEmulatedTouch(DeviceIntPtr dev)1073 FindOldestPointerEmulatedTouch(DeviceIntPtr dev)
1074 {
1075     TouchPointInfoPtr oldest = NULL;
1076     int i;
1077 
1078     for (i = 0; i < dev->touch->num_touches; i++) {
1079         TouchPointInfoPtr ti = dev->touch->touches + i;
1080         int j;
1081 
1082         if (!ti->active || !ti->emulate_pointer)
1083             continue;
1084 
1085         for (j = 0; j < ti->num_listeners; j++) {
1086             if (ti->listeners[j].type == LISTENER_POINTER_GRAB ||
1087                 ti->listeners[j].type == LISTENER_POINTER_REGULAR)
1088                 break;
1089         }
1090         if (j == ti->num_listeners)
1091             continue;
1092 
1093         if (!oldest) {
1094             oldest = ti;
1095             continue;
1096         }
1097 
1098         if (oldest->client_id - ti->client_id < UINT_MAX / 2)
1099             oldest = ti;
1100     }
1101 
1102     return oldest;
1103 }
1104 
1105 /**
1106  * If the current owner has rejected the event, deliver the
1107  * TouchOwnership/TouchBegin to the next item in the sprite stack.
1108  */
1109 static void
TouchPuntToNextOwner(DeviceIntPtr dev,TouchPointInfoPtr ti,TouchOwnershipEvent * ev)1110 TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
1111                      TouchOwnershipEvent *ev)
1112 {
1113     TouchListener *listener = &ti->listeners[0]; /* new owner */
1114     int accepted_early = listener->state == LISTENER_EARLY_ACCEPT;
1115 
1116     /* Deliver the ownership */
1117     if (listener->state == LISTENER_AWAITING_OWNER || accepted_early)
1118         DeliverTouchEvents(dev, ti, (InternalEvent *) ev,
1119                            listener->listener);
1120     else if (listener->state == LISTENER_AWAITING_BEGIN) {
1121         /* We can't punt to a pointer listener unless all older pointer
1122          * emulated touches have been seen already. */
1123         if ((listener->type == LISTENER_POINTER_GRAB ||
1124              listener->type == LISTENER_POINTER_REGULAR) &&
1125             ti != FindOldestPointerEmulatedTouch(dev))
1126             return;
1127 
1128         TouchEventHistoryReplay(ti, dev, listener->listener);
1129     }
1130 
1131     /* New owner has Begin/Update but not end. If touch is pending_finish,
1132      * emulate the TouchEnd now */
1133     if (ti->pending_finish) {
1134         TouchEmitTouchEnd(dev, ti, 0, 0);
1135 
1136         /* If the last owner is not a touch grab, finalise the touch, we
1137            won't get more correspondence on this.
1138          */
1139         if (ti->num_listeners == 1 &&
1140             (ti->num_grabs == 0 ||
1141              listener->grab->grabtype != XI2 ||
1142              !xi2mask_isset(listener->grab->xi2mask, dev, XI_TouchBegin))) {
1143             TouchEndTouch(dev, ti);
1144             return;
1145         }
1146     }
1147 
1148     if (accepted_early)
1149         ActivateEarlyAccept(dev, ti);
1150 }
1151 
1152 /**
1153  * Check the oldest touch to see if it needs to be replayed to its pointer
1154  * owner.
1155  *
1156  * Touch event propagation is paused if it hits a pointer listener while an
1157  * older touch with a pointer listener is waiting on accept or reject. This
1158  * function will restart propagation of a paused touch if needed.
1159  *
1160  * @param dev The device to check touches for.
1161  */
1162 static void
CheckOldestTouch(DeviceIntPtr dev)1163 CheckOldestTouch(DeviceIntPtr dev)
1164 {
1165     TouchPointInfoPtr oldest = FindOldestPointerEmulatedTouch(dev);
1166 
1167     if (oldest && oldest->listeners[0].state == LISTENER_AWAITING_BEGIN)
1168         TouchPuntToNextOwner(dev, oldest, NULL);
1169 }
1170 
1171 /**
1172  * Process a touch rejection.
1173  *
1174  * @param sourcedev The source device of the touch sequence.
1175  * @param ti The touchpoint info record.
1176  * @param resource The resource of the client rejecting the touch.
1177  * @param ev TouchOwnership event to send. Set to NULL if no event should be
1178  *        sent.
1179  */
1180 void
TouchRejected(DeviceIntPtr sourcedev,TouchPointInfoPtr ti,XID resource,TouchOwnershipEvent * ev)1181 TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource,
1182               TouchOwnershipEvent *ev)
1183 {
1184     Bool was_owner = (resource == ti->listeners[0].listener);
1185     int i;
1186 
1187     /* Send a TouchEnd event to the resource being removed, but only if they
1188      * haven't received one yet already */
1189     for (i = 0; i < ti->num_listeners; i++) {
1190         if (ti->listeners[i].listener == resource) {
1191             if (ti->listeners[i].state != LISTENER_HAS_END)
1192                 TouchEmitTouchEnd(sourcedev, ti, TOUCH_REJECT, resource);
1193             break;
1194         }
1195     }
1196 
1197     /* Remove the resource from the listener list, updating
1198      * ti->num_listeners, as well as ti->num_grabs if it was a grab. */
1199     TouchRemoveListener(ti, resource);
1200 
1201     /* If the current owner was removed and there are further listeners, deliver
1202      * the TouchOwnership or TouchBegin event to the new owner. */
1203     if (ev && ti->num_listeners > 0 && was_owner)
1204         TouchPuntToNextOwner(sourcedev, ti, ev);
1205     else if (ti->num_listeners == 0)
1206         TouchEndTouch(sourcedev, ti);
1207 
1208     CheckOldestTouch(sourcedev);
1209 }
1210 
1211 /**
1212  * Processes a TouchOwnership event, indicating a grab has accepted the touch
1213  * it currently owns, or a grab or selection has been removed.  Will generate
1214  * and send TouchEnd events to all clients removed from the delivery list, as
1215  * well as possibly sending the new TouchOwnership event.  May end the
1216  * touchpoint if it is pending finish.
1217  */
1218 static void
ProcessTouchOwnershipEvent(TouchOwnershipEvent * ev,DeviceIntPtr dev)1219 ProcessTouchOwnershipEvent(TouchOwnershipEvent *ev,
1220                            DeviceIntPtr dev)
1221 {
1222     TouchPointInfoPtr ti = TouchFindByClientID(dev, ev->touchid);
1223 
1224     if (!ti) {
1225         DebugF("[Xi] %s: Failed to get event %d for touchpoint %d\n",
1226                dev->name, ev->type, ev->touchid);
1227         return;
1228     }
1229 
1230     if (ev->reason == XIRejectTouch)
1231         TouchRejected(dev, ti, ev->resource, ev);
1232     else if (ev->reason == XIAcceptTouch) {
1233         int i;
1234 
1235 
1236         /* For pointer-emulated listeners that ungrabbed the active grab,
1237          * the state was forced to LISTENER_HAS_END. Still go
1238          * through the motions of ending the touch if the listener has
1239          * already seen the end. This ensures that the touch record is ended in
1240          * the server.
1241          */
1242         if (ti->listeners[0].state == LISTENER_HAS_END)
1243             TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[0].listener);
1244 
1245         /* The touch owner has accepted the touch.  Send TouchEnd events to
1246          * everyone else, and truncate the list of listeners. */
1247         for (i = 1; i < ti->num_listeners; i++)
1248             TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[i].listener);
1249 
1250         while (ti->num_listeners > 1)
1251             TouchRemoveListener(ti, ti->listeners[1].listener);
1252         /* Owner accepted after receiving end */
1253         if (ti->listeners[0].state == LISTENER_HAS_END)
1254             TouchEndTouch(dev, ti);
1255         else
1256             ti->listeners[0].state = LISTENER_HAS_ACCEPTED;
1257     }
1258     else {  /* this is the very first ownership event for a grab */
1259         DeliverTouchEvents(dev, ti, (InternalEvent *) ev, ev->resource);
1260     }
1261 }
1262 
1263 /**
1264  * Copy the event's valuator information into the touchpoint, we may need
1265  * this for emulated TouchEnd events.
1266  */
1267 static void
TouchCopyValuatorData(DeviceEvent * ev,TouchPointInfoPtr ti)1268 TouchCopyValuatorData(DeviceEvent *ev, TouchPointInfoPtr ti)
1269 {
1270     int i;
1271 
1272     for (i = 0; i < ARRAY_SIZE(ev->valuators.data); i++)
1273         if (BitIsOn(ev->valuators.mask, i))
1274             valuator_mask_set_double(ti->valuators, i, ev->valuators.data[i]);
1275 }
1276 
1277 /**
1278  * Given a touch event and a potential listener, retrieve info needed for
1279  * processing the event.
1280  *
1281  * @param dev The device generating the touch event.
1282  * @param ti The touch point info record for the touch event.
1283  * @param ev The touch event to process.
1284  * @param listener The touch event listener that may receive the touch event.
1285  * @param[out] client The client that should receive the touch event.
1286  * @param[out] win The window to deliver the event on.
1287  * @param[out] grab The grab to deliver the event through, if any.
1288  * @param[out] mask The XI 2.x event mask of the grab or selection, if any.
1289  * @return TRUE if an event should be delivered to the listener, FALSE
1290  *         otherwise.
1291  */
1292 static Bool
RetrieveTouchDeliveryData(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,TouchListener * listener,ClientPtr * client,WindowPtr * win,GrabPtr * grab,XI2Mask ** mask)1293 RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
1294                           InternalEvent *ev, TouchListener * listener,
1295                           ClientPtr *client, WindowPtr *win, GrabPtr *grab,
1296                           XI2Mask **mask)
1297 {
1298     int rc;
1299     InputClients *iclients = NULL;
1300     *mask = NULL;
1301 
1302     if (listener->type == LISTENER_GRAB ||
1303         listener->type == LISTENER_POINTER_GRAB) {
1304         *grab = listener->grab;
1305 
1306         BUG_RETURN_VAL(!*grab, FALSE);
1307 
1308         *client = rClient(*grab);
1309         *win = (*grab)->window;
1310         *mask = (*grab)->xi2mask;
1311     }
1312     else {
1313         rc = dixLookupResourceByType((void **) win, listener->listener,
1314                                      listener->resource_type,
1315                                      serverClient, DixSendAccess);
1316         if (rc != Success)
1317             return FALSE;
1318 
1319         if (listener->level == XI2) {
1320             int evtype;
1321 
1322             if (ti->emulate_pointer &&
1323                 listener->type == LISTENER_POINTER_REGULAR)
1324                 evtype = GetXI2Type(TouchGetPointerEventType(ev));
1325             else
1326                 evtype = GetXI2Type(ev->any.type);
1327 
1328             nt_list_for_each_entry(iclients,
1329                                    wOtherInputMasks(*win)->inputClients, next)
1330                 if (xi2mask_isset(iclients->xi2mask, dev, evtype))
1331                 break;
1332 
1333             BUG_RETURN_VAL(!iclients, FALSE);
1334 
1335             *mask = iclients->xi2mask;
1336             *client = rClient(iclients);
1337         }
1338         else if (listener->level == XI) {
1339             int xi_type = GetXIType(TouchGetPointerEventType(ev));
1340             Mask xi_filter = event_get_filter_from_type(dev, xi_type);
1341 
1342             nt_list_for_each_entry(iclients,
1343                                    wOtherInputMasks(*win)->inputClients, next)
1344                 if (iclients->mask[dev->id] & xi_filter)
1345                 break;
1346             BUG_RETURN_VAL(!iclients, FALSE);
1347 
1348             *client = rClient(iclients);
1349         }
1350         else {
1351             int coretype = GetCoreType(TouchGetPointerEventType(ev));
1352             Mask core_filter = event_get_filter_from_type(dev, coretype);
1353             OtherClients *oclients;
1354 
1355             /* all others */
1356             nt_list_for_each_entry(oclients,
1357                                    (OtherClients *) wOtherClients(*win), next)
1358                 if (oclients->mask & core_filter)
1359                     break;
1360 
1361             /* if owner selected, oclients is NULL */
1362             *client = oclients ? rClient(oclients) : wClient(*win);
1363         }
1364 
1365         *grab = NULL;
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     /* There may be a pointer grab on the device */
1383     if (!grab) {
1384         grab = dev->deviceGrab.grab;
1385         if (grab) {
1386             win = grab->window;
1387             xi2mask = grab->xi2mask;
1388             client = rClient(grab);
1389         }
1390     }
1391 
1392     /* We don't deliver pointer events to non-owners */
1393     if (!TouchResourceIsOwner(ti, listener->listener))
1394         return !Success;
1395 
1396     if (!ti->emulate_pointer)
1397         return !Success;
1398 
1399     nevents = TouchConvertToPointerEvent(ev, &motion, &button);
1400     BUG_RETURN_VAL(nevents == 0, BadValue);
1401 
1402     if (nevents > 1)
1403         ptrev = &button;
1404 
1405     kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
1406     event_set_state(dev, kbd, &ptrev->device_event);
1407     ptrev->device_event.corestate = event_get_corestate(dev, kbd);
1408 
1409     if (grab) {
1410         /* this side-steps the usual activation mechanisms, but... */
1411         if (ev->any.type == ET_TouchBegin && !dev->deviceGrab.grab)
1412             ActivatePassiveGrab(dev, grab, ptrev, ev);  /* also delivers the event */
1413         else {
1414             int deliveries = 0;
1415 
1416             /* 'grab' is the passive grab, but if the grab isn't active,
1417              * don't deliver */
1418             if (!dev->deviceGrab.grab)
1419                 return !Success;
1420 
1421             if (grab->ownerEvents) {
1422                 WindowPtr focus = NullWindow;
1423                 WindowPtr sprite_win = DeepestSpriteWin(dev->spriteInfo->sprite);
1424 
1425                 deliveries = DeliverDeviceEvents(sprite_win, ptrev, grab, focus, dev);
1426             }
1427 
1428             if (!deliveries)
1429                 deliveries = DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype);
1430 
1431             /* We must accept the touch sequence once a pointer listener has
1432              * received one event past ButtonPress. */
1433             if (deliveries && ev->any.type != ET_TouchBegin &&
1434                 !(ev->device_event.flags & TOUCH_CLIENT_ID))
1435                 TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
1436 
1437             if (ev->any.type == ET_TouchEnd &&
1438                 ti->num_listeners == 1 &&
1439                 !dev->button->buttonsDown &&
1440                 dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) {
1441                 (*dev->deviceGrab.DeactivateGrab) (dev);
1442                 CheckOldestTouch(dev);
1443                 return Success;
1444             }
1445         }
1446     }
1447     else {
1448         GrabPtr devgrab = dev->deviceGrab.grab;
1449         WindowPtr sprite_win = DeepestSpriteWin(dev->spriteInfo->sprite);
1450 
1451         DeliverDeviceEvents(sprite_win, ptrev, grab, win, dev);
1452         /* FIXME: bad hack
1453          * Implicit passive grab activated in response to this event. Store
1454          * the event.
1455          */
1456         if (!devgrab && dev->deviceGrab.grab && dev->deviceGrab.implicitGrab) {
1457             TouchListener *l;
1458             GrabPtr g;
1459 
1460             devgrab = dev->deviceGrab.grab;
1461             g = AllocGrab(devgrab);
1462             BUG_WARN(!g);
1463 
1464             *dev->deviceGrab.sync.event = ev->device_event;
1465 
1466             /* The listener array has a sequence of grabs and then one event
1467              * selection. Implicit grab activation occurs through delivering an
1468              * event selection. Thus, we update the last listener in the array.
1469              */
1470             l = &ti->listeners[ti->num_listeners - 1];
1471             l->listener = g->resource;
1472             l->grab = g;
1473             //l->resource_type = RT_NONE;
1474 
1475             if (devgrab->grabtype != XI2 || devgrab->type != XI_TouchBegin)
1476                 l->type = LISTENER_POINTER_GRAB;
1477             else
1478                 l->type = LISTENER_GRAB;
1479         }
1480 
1481     }
1482     if (ev->any.type == ET_TouchBegin)
1483         listener->state = LISTENER_IS_OWNER;
1484     else if (ev->any.type == ET_TouchEnd)
1485         listener->state = LISTENER_HAS_END;
1486 
1487     return Success;
1488 }
1489 
1490 static void
DeliverEmulatedMotionEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev)1491 DeliverEmulatedMotionEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
1492                            InternalEvent *ev)
1493 {
1494     DeviceEvent motion;
1495 
1496     if (ti->num_listeners) {
1497         ClientPtr client;
1498         WindowPtr win;
1499         GrabPtr grab;
1500         XI2Mask *mask;
1501 
1502         if (ti->listeners[0].type != LISTENER_POINTER_REGULAR &&
1503             ti->listeners[0].type != LISTENER_POINTER_GRAB)
1504             return;
1505 
1506         motion = ev->device_event;
1507         motion.type = ET_TouchUpdate;
1508         motion.detail.button = 0;
1509 
1510         if (!RetrieveTouchDeliveryData(dev, ti, (InternalEvent*)&motion,
1511                                        &ti->listeners[0], &client, &win, &grab,
1512                                        &mask))
1513             return;
1514 
1515         DeliverTouchEmulatedEvent(dev, ti, (InternalEvent*)&motion, &ti->listeners[0], client,
1516                                   win, grab, mask);
1517     }
1518     else {
1519         InternalEvent button;
1520         int converted;
1521 
1522         converted = TouchConvertToPointerEvent(ev, (InternalEvent*)&motion, &button);
1523 
1524         BUG_WARN(converted == 0);
1525         if (converted)
1526             ProcessOtherEvent((InternalEvent*)&motion, dev);
1527     }
1528 }
1529 
1530 /**
1531  * Processes and delivers a TouchBegin, TouchUpdate, or a
1532  * TouchEnd event.
1533  *
1534  * Due to having rather different delivery semantics (see the Xi 2.2 protocol
1535  * spec for more information), this implements its own grab and event-selection
1536  * delivery logic.
1537  */
1538 static void
ProcessTouchEvent(InternalEvent * ev,DeviceIntPtr dev)1539 ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
1540 {
1541     TouchClassPtr t = dev->touch;
1542     TouchPointInfoPtr ti;
1543     uint32_t touchid;
1544     int type = ev->any.type;
1545     int emulate_pointer = ! !(ev->device_event.flags & TOUCH_POINTER_EMULATED);
1546     DeviceIntPtr kbd;
1547 
1548     if (!t)
1549         return;
1550 
1551     touchid = ev->device_event.touchid;
1552 
1553     if (type == ET_TouchBegin && !(ev->device_event.flags & TOUCH_REPLAYING)) {
1554         ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
1555                              emulate_pointer);
1556     }
1557     else
1558         ti = TouchFindByClientID(dev, touchid);
1559 
1560     /* Active pointer grab */
1561     if (emulate_pointer && dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab &&
1562         (dev->deviceGrab.grab->grabtype == CORE ||
1563          dev->deviceGrab.grab->grabtype == XI ||
1564          !xi2mask_isset(dev->deviceGrab.grab->xi2mask, dev, XI_TouchBegin)))
1565     {
1566         /* Active pointer grab on touch point and we get a TouchEnd - claim this
1567          * touchpoint accepted, otherwise clients waiting for ownership will
1568          * wait on this touchpoint until this client ungrabs, or the cows come
1569          * home, whichever is earlier */
1570         if (ti && type == ET_TouchEnd)
1571             TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
1572         else if (!ti && type != ET_TouchBegin) {
1573             /* Under the following circumstances we create a new touch record for an
1574              * existing touch:
1575              *
1576              * - The touch may be pointer emulated
1577              * - An explicit grab is active on the device
1578              * - The grab is a pointer grab
1579              *
1580              * This allows for an explicit grab to receive pointer events for an already
1581              * active touch.
1582              */
1583             ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
1584                                  emulate_pointer);
1585             if (!ti) {
1586                 DebugF("[Xi] %s: Failed to create new dix record for explicitly "
1587                        "grabbed touchpoint %d\n",
1588                        dev->name, touchid);
1589                 return;
1590             }
1591 
1592             TouchBuildSprite(dev, ti, ev);
1593             TouchSetupListeners(dev, ti, ev);
1594         }
1595     }
1596 
1597     if (!ti) {
1598         DebugF("[Xi] %s: Failed to get event %d for touchpoint %d\n",
1599                dev->name, type, touchid);
1600         goto out;
1601     }
1602 
1603     /* if emulate_pointer is set, emulate the motion event right
1604      * here, so we can ignore it for button event emulation. TouchUpdate
1605      * events which _only_ emulate motion just work normally */
1606     if (emulate_pointer && ev->any.type != ET_TouchUpdate)
1607         DeliverEmulatedMotionEvent(dev, ti, ev);
1608 
1609     if (emulate_pointer && IsMaster(dev))
1610         CheckMotion(&ev->device_event, dev);
1611 
1612     kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
1613     event_set_state(NULL, kbd, &ev->device_event);
1614     ev->device_event.corestate = event_get_corestate(NULL, kbd);
1615 
1616     /* Make sure we have a valid window trace for event delivery; must be
1617      * called after event type mutation. Touch end events are always processed
1618      * in order to end touch records. */
1619     /* FIXME: check this */
1620     if ((type == ET_TouchBegin &&
1621          !(ev->device_event.flags & TOUCH_REPLAYING) &&
1622          !TouchBuildSprite(dev, ti, ev)) ||
1623         (type != ET_TouchEnd && ti->sprite.spriteTraceGood == 0))
1624         return;
1625 
1626     TouchCopyValuatorData(&ev->device_event, ti);
1627     /* WARNING: the event type may change to TouchUpdate in
1628      * DeliverTouchEvents if a TouchEnd was delivered to a grabbing
1629      * owner */
1630     DeliverTouchEvents(dev, ti, ev, ev->device_event.resource);
1631     if (ev->any.type == ET_TouchEnd)
1632         TouchEndTouch(dev, ti);
1633 
1634  out:
1635     if (emulate_pointer)
1636         UpdateDeviceState(dev, &ev->device_event);
1637 }
1638 
1639 static void
ProcessBarrierEvent(InternalEvent * e,DeviceIntPtr dev)1640 ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
1641 {
1642     Mask filter;
1643     WindowPtr pWin;
1644     BarrierEvent *be = &e->barrier_event;
1645     xEvent *ev;
1646     int rc;
1647     GrabPtr grab = dev->deviceGrab.grab;
1648 
1649     if (!IsMaster(dev))
1650         return;
1651 
1652     if (dixLookupWindow(&pWin, be->window, serverClient, DixReadAccess) != Success)
1653         return;
1654 
1655     if (grab)
1656         be->flags |= XIBarrierDeviceIsGrabbed;
1657 
1658     rc = EventToXI2(e, &ev);
1659     if (rc != Success) {
1660         ErrorF("[Xi] event conversion from %s failed with code %d\n", __func__, rc);
1661         return;
1662     }
1663 
1664     /* A client has a grab, deliver to this client if the grab_window is the
1665        barrier window.
1666 
1667        Otherwise, deliver normally to the client.
1668      */
1669     if (grab &&
1670         CLIENT_ID(be->barrierid) == CLIENT_ID(grab->resource) &&
1671         grab->window->drawable.id == be->window) {
1672         DeliverGrabbedEvent(e, dev, FALSE);
1673     } else {
1674         filter = GetEventFilter(dev, ev);
1675 
1676         DeliverEventsToWindow(dev, pWin, ev, 1,
1677                               filter, NullGrab);
1678     }
1679     free(ev);
1680 }
1681 
1682 /**
1683  * Process DeviceEvents and DeviceChangedEvents.
1684  */
1685 static void
ProcessDeviceEvent(InternalEvent * ev,DeviceIntPtr device)1686 ProcessDeviceEvent(InternalEvent *ev, DeviceIntPtr device)
1687 {
1688     GrabPtr grab;
1689     Bool deactivateDeviceGrab = FALSE;
1690     int key = 0, rootX, rootY;
1691     ButtonClassPtr b;
1692     int ret = 0;
1693     int corestate;
1694     DeviceIntPtr mouse = NULL, kbd = NULL;
1695     DeviceEvent *event = &ev->device_event;
1696 
1697     if (IsPointerDevice(device)) {
1698         kbd = GetMaster(device, KEYBOARD_OR_FLOAT);
1699         mouse = device;
1700         if (!kbd->key)          /* can happen with floating SDs */
1701             kbd = NULL;
1702     }
1703     else {
1704         mouse = GetMaster(device, POINTER_OR_FLOAT);
1705         kbd = device;
1706         if (!mouse->valuator || !mouse->button) /* may be float. SDs */
1707             mouse = NULL;
1708     }
1709 
1710     corestate = event_get_corestate(mouse, kbd);
1711     event_set_state(mouse, kbd, event);
1712 
1713     ret = UpdateDeviceState(device, event);
1714     if (ret == DONT_PROCESS)
1715         return;
1716 
1717     b = device->button;
1718 
1719     if (IsMaster(device) || IsFloating(device))
1720         CheckMotion(event, device);
1721 
1722     switch (event->type) {
1723     case ET_Motion:
1724     case ET_ButtonPress:
1725     case ET_ButtonRelease:
1726     case ET_KeyPress:
1727     case ET_KeyRelease:
1728     case ET_ProximityIn:
1729     case ET_ProximityOut:
1730         GetSpritePosition(device, &rootX, &rootY);
1731         event->root_x = rootX;
1732         event->root_y = rootY;
1733         NoticeEventTime((InternalEvent *) event, device);
1734         event->corestate = corestate;
1735         key = event->detail.key;
1736         break;
1737     default:
1738         break;
1739     }
1740 
1741     /* send KeyPress and KeyRelease events to XACE plugins */
1742     if (XaceHookIsSet(XACE_KEY_AVAIL) &&
1743             (event->type == ET_KeyPress || event->type == ET_KeyRelease)) {
1744         xEvent *core;
1745         int count;
1746 
1747         if (EventToCore(ev, &core, &count) == Success && count > 0) {
1748             XaceHook(XACE_KEY_AVAIL, core, device, 0);
1749             free(core);
1750         }
1751     }
1752 
1753     if (DeviceEventCallback && !syncEvents.playingEvents) {
1754         DeviceEventInfoRec eventinfo;
1755         SpritePtr pSprite = device->spriteInfo->sprite;
1756 
1757         /* see comment in EnqueueEvents regarding the next three lines */
1758         if (ev->any.type == ET_Motion)
1759             ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id;
1760 
1761         eventinfo.device = device;
1762         eventinfo.event = ev;
1763         CallCallbacks(&DeviceEventCallback, (void *) &eventinfo);
1764     }
1765 
1766     grab = device->deviceGrab.grab;
1767 
1768     switch (event->type) {
1769     case ET_KeyPress:
1770         /* Don't deliver focus events (e.g. from KeymapNotify when running
1771          * nested) to clients. */
1772         if (event->source_type == EVENT_SOURCE_FOCUS)
1773             return;
1774         if (!grab && CheckDeviceGrabs(device, event, 0))
1775             return;
1776         break;
1777     case ET_KeyRelease:
1778         if (grab && device->deviceGrab.fromPassiveGrab &&
1779             (key == device->deviceGrab.activatingKey) &&
1780             GrabIsKeyboardGrab(device->deviceGrab.grab))
1781             deactivateDeviceGrab = TRUE;
1782         break;
1783     case ET_ButtonPress:
1784         if (b->map[key] == 0)   /* there's no button 0 */
1785             return;
1786         event->detail.button = b->map[key];
1787         if (!grab && CheckDeviceGrabs(device, event, 0)) {
1788             /* if a passive grab was activated, the event has been sent
1789              * already */
1790             return;
1791         }
1792         break;
1793     case ET_ButtonRelease:
1794         if (b->map[key] == 0)   /* there's no button 0 */
1795             return;
1796         event->detail.button = b->map[key];
1797         if (grab && !b->buttonsDown &&
1798             device->deviceGrab.fromPassiveGrab &&
1799             GrabIsPointerGrab(device->deviceGrab.grab))
1800             deactivateDeviceGrab = TRUE;
1801     default:
1802         break;
1803     }
1804 
1805     /* Don't deliver focus events (e.g. from KeymapNotify when running
1806      * nested) to clients. */
1807     if (event->source_type != EVENT_SOURCE_FOCUS) {
1808         if (grab)
1809             DeliverGrabbedEvent((InternalEvent *) event, device,
1810                                 deactivateDeviceGrab);
1811         else if (device->focus && !IsPointerEvent(ev))
1812             DeliverFocusedEvent(device, (InternalEvent *) event,
1813                                 GetSpriteWindow(device));
1814         else
1815             DeliverDeviceEvents(GetSpriteWindow(device), (InternalEvent *) event,
1816                                 NullGrab, NullWindow, device);
1817     }
1818 
1819     if (deactivateDeviceGrab == TRUE) {
1820         (*device->deviceGrab.DeactivateGrab) (device);
1821 
1822         if (!IsMaster (device) && !IsFloating (device)) {
1823             int flags, num_events = 0;
1824             InternalEvent dce;
1825 
1826             flags = (IsPointerDevice (device)) ?
1827                 DEVCHANGE_POINTER_EVENT : DEVCHANGE_KEYBOARD_EVENT;
1828             UpdateFromMaster (&dce, device, flags, &num_events);
1829             BUG_WARN(num_events > 1);
1830 
1831             if (num_events == 1)
1832                 ChangeMasterDeviceClasses(GetMaster (device, MASTER_ATTACHED),
1833                                           &dce.changed_event);
1834         }
1835 
1836     }
1837 
1838     event->detail.key = key;
1839 }
1840 
1841 /**
1842  * Main device event processing function.
1843  * Called from when processing the events from the event queue.
1844  *
1845  */
1846 void
ProcessOtherEvent(InternalEvent * ev,DeviceIntPtr device)1847 ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
1848 {
1849     verify_internal_event(ev);
1850 
1851     switch (ev->any.type) {
1852     case ET_RawKeyPress:
1853     case ET_RawKeyRelease:
1854     case ET_RawButtonPress:
1855     case ET_RawButtonRelease:
1856     case ET_RawMotion:
1857     case ET_RawTouchBegin:
1858     case ET_RawTouchUpdate:
1859     case ET_RawTouchEnd:
1860         DeliverRawEvent(&ev->raw_event, device);
1861         break;
1862     case ET_TouchBegin:
1863     case ET_TouchUpdate:
1864     case ET_TouchEnd:
1865         ProcessTouchEvent(ev, device);
1866         break;
1867     case ET_TouchOwnership:
1868         /* TouchOwnership events are handled separately from the rest, as they
1869          * have more complex semantics. */
1870         ProcessTouchOwnershipEvent(&ev->touch_ownership_event, device);
1871         break;
1872     case ET_BarrierHit:
1873     case ET_BarrierLeave:
1874         ProcessBarrierEvent(ev, device);
1875         break;
1876     default:
1877         ProcessDeviceEvent(ev, device);
1878         break;
1879     }
1880 }
1881 
1882 static int
DeliverTouchBeginEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,TouchListener * listener,ClientPtr client,WindowPtr win,GrabPtr grab,XI2Mask * xi2mask)1883 DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
1884                        InternalEvent *ev, TouchListener * listener,
1885                        ClientPtr client, WindowPtr win, GrabPtr grab,
1886                        XI2Mask *xi2mask)
1887 {
1888     enum TouchListenerState state;
1889     int rc = Success;
1890     Bool has_ownershipmask;
1891 
1892     if (listener->type == LISTENER_POINTER_REGULAR ||
1893         listener->type == LISTENER_POINTER_GRAB) {
1894         rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
1895                                        grab, xi2mask);
1896         if (rc == Success) {
1897             listener->state = LISTENER_IS_OWNER;
1898             /* async grabs cannot replay, so automatically accept this touch */
1899             if (listener->type == LISTENER_POINTER_GRAB &&
1900                 dev->deviceGrab.grab &&
1901                 dev->deviceGrab.fromPassiveGrab &&
1902                 dev->deviceGrab.grab->pointerMode == GrabModeAsync)
1903                 ActivateEarlyAccept(dev, ti);
1904         }
1905         goto out;
1906     }
1907 
1908     has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
1909 
1910     if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
1911         rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
1912     if (!TouchResourceIsOwner(ti, listener->listener)) {
1913         if (has_ownershipmask)
1914             state = LISTENER_AWAITING_OWNER;
1915         else
1916             state = LISTENER_AWAITING_BEGIN;
1917     }
1918     else {
1919         if (has_ownershipmask)
1920             TouchSendOwnershipEvent(dev, ti, 0, listener->listener);
1921 
1922         if (listener->type == LISTENER_REGULAR)
1923             state = LISTENER_HAS_ACCEPTED;
1924         else
1925             state = LISTENER_IS_OWNER;
1926     }
1927     listener->state = state;
1928 
1929  out:
1930     return rc;
1931 }
1932 
1933 static int
DeliverTouchEndEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,TouchListener * listener,ClientPtr client,WindowPtr win,GrabPtr grab,XI2Mask * xi2mask)1934 DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
1935                      TouchListener * listener, ClientPtr client,
1936                      WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
1937 {
1938     int rc = Success;
1939 
1940     if (listener->type == LISTENER_POINTER_REGULAR ||
1941         listener->type == LISTENER_POINTER_GRAB) {
1942         /* Note: If the active grab was ungrabbed, we already changed the
1943          * state to LISTENER_HAS_END but still get here. So we mustn't
1944          * actually send the event.
1945          * This is part two of the hack in DeactivatePointerGrab
1946          */
1947         if (listener->state != LISTENER_HAS_END) {
1948             rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
1949                                            grab, xi2mask);
1950 
1951              /* Once we send a TouchEnd to a legacy listener, we're already well
1952               * past the accepting/rejecting stage (can only happen on
1953               * GrabModeSync + replay. This listener now gets the end event,
1954               * and we can continue.
1955               */
1956             if (rc == Success)
1957                 listener->state = LISTENER_HAS_END;
1958         }
1959         goto out;
1960     }
1961 
1962     /* A client is waiting for the begin, don't give it a TouchEnd */
1963     if (listener->state == LISTENER_AWAITING_BEGIN) {
1964         listener->state = LISTENER_HAS_END;
1965         goto out;
1966     }
1967 
1968     /* Event in response to reject */
1969     if (ev->device_event.flags & TOUCH_REJECT ||
1970         (ev->device_event.flags & TOUCH_ACCEPT && !TouchResourceIsOwner(ti, listener->listener))) {
1971         /* Touch has been rejected, or accepted by its owner which is not this listener */
1972         if (listener->state != LISTENER_HAS_END)
1973             rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
1974         listener->state = LISTENER_HAS_END;
1975     }
1976     else if (TouchResourceIsOwner(ti, listener->listener)) {
1977         Bool normal_end = !(ev->device_event.flags & TOUCH_ACCEPT);
1978 
1979         /* FIXME: what about early acceptance */
1980         if (normal_end && listener->state != LISTENER_HAS_END)
1981             rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
1982 
1983         if ((ti->num_listeners > 1 ||
1984              (ti->num_grabs > 0 && listener->state != LISTENER_HAS_ACCEPTED)) &&
1985             (ev->device_event.flags & (TOUCH_ACCEPT | TOUCH_REJECT)) == 0) {
1986             ev->any.type = ET_TouchUpdate;
1987             ev->device_event.flags |= TOUCH_PENDING_END;
1988             ti->pending_finish = TRUE;
1989 
1990             if (normal_end && listener->state != LISTENER_HAS_END)
1991                 rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
1992         }
1993 
1994         if (normal_end)
1995             listener->state = LISTENER_HAS_END;
1996     }
1997 
1998  out:
1999     return rc;
2000 }
2001 
2002 static int
DeliverTouchEvent(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,TouchListener * listener,ClientPtr client,WindowPtr win,GrabPtr grab,XI2Mask * xi2mask)2003 DeliverTouchEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
2004                   TouchListener * listener, ClientPtr client,
2005                   WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
2006 {
2007     Bool has_ownershipmask = FALSE;
2008     int rc = Success;
2009 
2010     if (xi2mask)
2011         has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
2012 
2013     if (ev->any.type == ET_TouchOwnership) {
2014         ev->touch_ownership_event.deviceid = dev->id;
2015         if (!TouchResourceIsOwner(ti, listener->listener))
2016             goto out;
2017         rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
2018         listener->state = LISTENER_IS_OWNER;
2019     }
2020     else
2021         ev->device_event.deviceid = dev->id;
2022 
2023     if (ev->any.type == ET_TouchBegin) {
2024         rc = DeliverTouchBeginEvent(dev, ti, ev, listener, client, win, grab,
2025                                     xi2mask);
2026     }
2027     else if (ev->any.type == ET_TouchUpdate) {
2028         if (listener->type == LISTENER_POINTER_REGULAR ||
2029             listener->type == LISTENER_POINTER_GRAB)
2030             DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win, grab,
2031                                       xi2mask);
2032         else if (TouchResourceIsOwner(ti, listener->listener) ||
2033                  has_ownershipmask)
2034             rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
2035     }
2036     else if (ev->any.type == ET_TouchEnd)
2037         rc = DeliverTouchEndEvent(dev, ti, ev, listener, client, win, grab,
2038                                   xi2mask);
2039 
2040  out:
2041     return rc;
2042 }
2043 
2044 /**
2045  * Delivers a touch events to all interested clients.  For TouchBegin events,
2046  * will update ti->listeners, ti->num_listeners, and ti->num_grabs.
2047  * May also mutate ev (type and flags) upon successful delivery.  If
2048  * @resource is non-zero, will only attempt delivery to the owner of that
2049  * resource.
2050  *
2051  * @return TRUE if the event was delivered at least once, FALSE otherwise
2052  */
2053 void
DeliverTouchEvents(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,XID resource)2054 DeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
2055                    InternalEvent *ev, XID resource)
2056 {
2057     int i;
2058 
2059     if (ev->any.type == ET_TouchBegin &&
2060         !(ev->device_event.flags & (TOUCH_CLIENT_ID | TOUCH_REPLAYING)))
2061         TouchSetupListeners(dev, ti, ev);
2062 
2063     TouchEventHistoryPush(ti, &ev->device_event);
2064 
2065     for (i = 0; i < ti->num_listeners; i++) {
2066         GrabPtr grab = NULL;
2067         ClientPtr client;
2068         WindowPtr win;
2069         XI2Mask *mask;
2070         TouchListener *listener = &ti->listeners[i];
2071 
2072         if (resource && listener->listener != resource)
2073             continue;
2074 
2075         if (!RetrieveTouchDeliveryData(dev, ti, ev, listener, &client, &win,
2076                                        &grab, &mask))
2077             continue;
2078 
2079         DeliverTouchEvent(dev, ti, ev, listener, client, win, grab, mask);
2080     }
2081 }
2082 
2083 int
InitProximityClassDeviceStruct(DeviceIntPtr dev)2084 InitProximityClassDeviceStruct(DeviceIntPtr dev)
2085 {
2086     ProximityClassPtr proxc;
2087 
2088     BUG_RETURN_VAL(dev == NULL, FALSE);
2089     BUG_RETURN_VAL(dev->proximity != NULL, FALSE);
2090 
2091     proxc = (ProximityClassPtr) malloc(sizeof(ProximityClassRec));
2092     if (!proxc)
2093         return FALSE;
2094     proxc->sourceid = dev->id;
2095     proxc->in_proximity = TRUE;
2096     dev->proximity = proxc;
2097     return TRUE;
2098 }
2099 
2100 /**
2101  * Initialise the device's valuators. The memory must already be allocated,
2102  * this function merely inits the matching axis (specified through axnum) to
2103  * sane values.
2104  *
2105  * It is a condition that (minval < maxval).
2106  *
2107  * @see InitValuatorClassDeviceStruct
2108  */
2109 Bool
InitValuatorAxisStruct(DeviceIntPtr dev,int axnum,Atom label,int minval,int maxval,int resolution,int min_res,int max_res,int mode)2110 InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval,
2111                        int maxval, int resolution, int min_res, int max_res,
2112                        int mode)
2113 {
2114     AxisInfoPtr ax;
2115 
2116     BUG_RETURN_VAL(dev == NULL, FALSE);
2117     BUG_RETURN_VAL(dev->valuator == NULL, FALSE);
2118     BUG_RETURN_VAL(axnum >= dev->valuator->numAxes, FALSE);
2119     BUG_RETURN_VAL(minval > maxval && mode == Absolute, FALSE);
2120 
2121     ax = dev->valuator->axes + axnum;
2122 
2123     ax->min_value = minval;
2124     ax->max_value = maxval;
2125     ax->resolution = resolution;
2126     ax->min_resolution = min_res;
2127     ax->max_resolution = max_res;
2128     ax->label = label;
2129     ax->mode = mode;
2130 
2131     if (mode & OutOfProximity)
2132         dev->proximity->in_proximity = FALSE;
2133 
2134     return SetScrollValuator(dev, axnum, SCROLL_TYPE_NONE, 0, SCROLL_FLAG_NONE);
2135 }
2136 
2137 /**
2138  * Set the given axis number as a scrolling valuator.
2139  */
2140 Bool
SetScrollValuator(DeviceIntPtr dev,int axnum,enum ScrollType type,double increment,int flags)2141 SetScrollValuator(DeviceIntPtr dev, int axnum, enum ScrollType type,
2142                   double increment, int flags)
2143 {
2144     AxisInfoPtr ax;
2145     int *current_ax;
2146     InternalEvent dce;
2147     DeviceIntPtr master;
2148 
2149     BUG_RETURN_VAL(dev == NULL, FALSE);
2150     BUG_RETURN_VAL(dev->valuator == NULL, FALSE);
2151     BUG_RETURN_VAL(axnum >= dev->valuator->numAxes, FALSE);
2152 
2153     switch (type) {
2154     case SCROLL_TYPE_VERTICAL:
2155         current_ax = &dev->valuator->v_scroll_axis;
2156         break;
2157     case SCROLL_TYPE_HORIZONTAL:
2158         current_ax = &dev->valuator->h_scroll_axis;
2159         break;
2160     case SCROLL_TYPE_NONE:
2161         ax = &dev->valuator->axes[axnum];
2162         ax->scroll.type = type;
2163         return TRUE;
2164     default:
2165         return FALSE;
2166     }
2167 
2168     if (increment == 0.0)
2169         return FALSE;
2170 
2171     if (*current_ax != -1 && axnum != *current_ax) {
2172         ax = &dev->valuator->axes[*current_ax];
2173         if (ax->scroll.type == type &&
2174             (flags & SCROLL_FLAG_PREFERRED) &&
2175             (ax->scroll.flags & SCROLL_FLAG_PREFERRED))
2176             return FALSE;
2177     }
2178     *current_ax = axnum;
2179 
2180     ax = &dev->valuator->axes[axnum];
2181     ax->scroll.type = type;
2182     ax->scroll.increment = increment;
2183     ax->scroll.flags = flags;
2184 
2185     master = GetMaster(dev, MASTER_ATTACHED);
2186     CreateClassesChangedEvent(&dce, master, dev,
2187                               DEVCHANGE_POINTER_EVENT |
2188                               DEVCHANGE_DEVICE_CHANGE);
2189     XISendDeviceChangedEvent(dev, &dce.changed_event);
2190 
2191     /* if the current slave is us, update the master. If not, we'll update
2192      * whenever the next slave switch happens anyway. CMDC sends the event
2193      * for us */
2194     if (master && master->lastSlave == dev)
2195         ChangeMasterDeviceClasses(master, &dce.changed_event);
2196 
2197     return TRUE;
2198 }
2199 
2200 int
CheckGrabValues(ClientPtr client,GrabParameters * param)2201 CheckGrabValues(ClientPtr client, GrabParameters *param)
2202 {
2203     if (param->grabtype != CORE &&
2204         param->grabtype != XI && param->grabtype != XI2) {
2205         ErrorF("[Xi] grabtype is invalid. This is a bug.\n");
2206         return BadImplementation;
2207     }
2208 
2209     if ((param->this_device_mode != GrabModeSync) &&
2210         (param->this_device_mode != GrabModeAsync) &&
2211         (param->this_device_mode != XIGrabModeTouch)) {
2212         client->errorValue = param->this_device_mode;
2213         return BadValue;
2214     }
2215     if ((param->other_devices_mode != GrabModeSync) &&
2216         (param->other_devices_mode != GrabModeAsync) &&
2217         (param->other_devices_mode != XIGrabModeTouch)) {
2218         client->errorValue = param->other_devices_mode;
2219         return BadValue;
2220     }
2221 
2222     if (param->modifiers != AnyModifier &&
2223         param->modifiers != XIAnyModifier &&
2224         (param->modifiers & ~AllModifiersMask)) {
2225         client->errorValue = param->modifiers;
2226         return BadValue;
2227     }
2228 
2229     if ((param->ownerEvents != xFalse) && (param->ownerEvents != xTrue)) {
2230         client->errorValue = param->ownerEvents;
2231         return BadValue;
2232     }
2233     return Success;
2234 }
2235 
2236 int
GrabButton(ClientPtr client,DeviceIntPtr dev,DeviceIntPtr modifier_device,int button,GrabParameters * param,enum InputLevel grabtype,GrabMask * mask)2237 GrabButton(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device,
2238            int button, GrabParameters *param, enum InputLevel grabtype,
2239            GrabMask *mask)
2240 {
2241     WindowPtr pWin, confineTo;
2242     CursorPtr cursor;
2243     GrabPtr grab;
2244     int rc, type = -1;
2245     Mask access_mode = DixGrabAccess;
2246 
2247     rc = CheckGrabValues(client, param);
2248     if (rc != Success)
2249         return rc;
2250     if (param->confineTo == None)
2251         confineTo = NullWindow;
2252     else {
2253         rc = dixLookupWindow(&confineTo, param->confineTo, client,
2254                              DixSetAttrAccess);
2255         if (rc != Success)
2256             return rc;
2257     }
2258     if (param->cursor == None)
2259         cursor = NullCursor;
2260     else {
2261         rc = dixLookupResourceByType((void **) &cursor, param->cursor,
2262                                      RT_CURSOR, client, DixUseAccess);
2263         if (rc != Success) {
2264             client->errorValue = param->cursor;
2265             return rc;
2266         }
2267         access_mode |= DixForceAccess;
2268     }
2269     if (param->this_device_mode == GrabModeSync ||
2270         param->other_devices_mode == GrabModeSync)
2271         access_mode |= DixFreezeAccess;
2272     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
2273     if (rc != Success)
2274         return rc;
2275     rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
2276     if (rc != Success)
2277         return rc;
2278 
2279     if (grabtype == XI)
2280         type = DeviceButtonPress;
2281     else if (grabtype == XI2)
2282         type = XI_ButtonPress;
2283 
2284     grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype,
2285                       mask, param, type, button, confineTo, cursor);
2286     if (!grab)
2287         return BadAlloc;
2288     return AddPassiveGrabToList(client, grab);
2289 }
2290 
2291 /**
2292  * Grab the given key.
2293  */
2294 int
GrabKey(ClientPtr client,DeviceIntPtr dev,DeviceIntPtr modifier_device,int key,GrabParameters * param,enum InputLevel grabtype,GrabMask * mask)2295 GrabKey(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr modifier_device,
2296         int key, GrabParameters *param, enum InputLevel grabtype,
2297         GrabMask *mask)
2298 {
2299     WindowPtr pWin;
2300     GrabPtr grab;
2301     KeyClassPtr k = dev->key;
2302     Mask access_mode = DixGrabAccess;
2303     int rc, type = -1;
2304 
2305     rc = CheckGrabValues(client, param);
2306     if (rc != Success)
2307         return rc;
2308     if ((dev->id != XIAllDevices && dev->id != XIAllMasterDevices) && k == NULL)
2309         return BadMatch;
2310     if (grabtype == XI) {
2311         if ((key > k->xkbInfo->desc->max_key_code ||
2312              key < k->xkbInfo->desc->min_key_code)
2313             && (key != AnyKey)) {
2314             client->errorValue = key;
2315             return BadValue;
2316         }
2317         type = DeviceKeyPress;
2318     }
2319     else if (grabtype == XI2)
2320         type = XI_KeyPress;
2321 
2322     rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
2323     if (rc != Success)
2324         return rc;
2325     if (param->this_device_mode == GrabModeSync ||
2326         param->other_devices_mode == GrabModeSync)
2327         access_mode |= DixFreezeAccess;
2328     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
2329     if (rc != Success)
2330         return rc;
2331 
2332     grab = CreateGrab(client->index, dev, modifier_device, pWin, grabtype,
2333                       mask, param, type, key, NULL, NULL);
2334     if (!grab)
2335         return BadAlloc;
2336     return AddPassiveGrabToList(client, grab);
2337 }
2338 
2339 /* Enter/FocusIn grab */
2340 int
GrabWindow(ClientPtr client,DeviceIntPtr dev,int type,GrabParameters * param,GrabMask * mask)2341 GrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
2342            GrabParameters *param, GrabMask *mask)
2343 {
2344     WindowPtr pWin;
2345     CursorPtr cursor;
2346     GrabPtr grab;
2347     Mask access_mode = DixGrabAccess;
2348     int rc;
2349 
2350     rc = CheckGrabValues(client, param);
2351     if (rc != Success)
2352         return rc;
2353 
2354     rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
2355     if (rc != Success)
2356         return rc;
2357     if (param->cursor == None)
2358         cursor = NullCursor;
2359     else {
2360         rc = dixLookupResourceByType((void **) &cursor, param->cursor,
2361                                      RT_CURSOR, client, DixUseAccess);
2362         if (rc != Success) {
2363             client->errorValue = param->cursor;
2364             return rc;
2365         }
2366         access_mode |= DixForceAccess;
2367     }
2368     if (param->this_device_mode == GrabModeSync ||
2369         param->other_devices_mode == GrabModeSync)
2370         access_mode |= DixFreezeAccess;
2371     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
2372     if (rc != Success)
2373         return rc;
2374 
2375     grab = CreateGrab(client->index, dev, dev, pWin, XI2,
2376                       mask, param,
2377                       (type == XIGrabtypeEnter) ? XI_Enter : XI_FocusIn, 0,
2378                       NULL, cursor);
2379 
2380     if (!grab)
2381         return BadAlloc;
2382 
2383     return AddPassiveGrabToList(client, grab);
2384 }
2385 
2386 /* Touch grab */
2387 int
GrabTouch(ClientPtr client,DeviceIntPtr dev,DeviceIntPtr mod_dev,GrabParameters * param,GrabMask * mask)2388 GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
2389           GrabParameters *param, GrabMask *mask)
2390 {
2391     WindowPtr pWin;
2392     GrabPtr grab;
2393     int rc;
2394 
2395     rc = CheckGrabValues(client, param);
2396     if (rc != Success)
2397         return rc;
2398 
2399     rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
2400     if (rc != Success)
2401         return rc;
2402     rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGrabAccess);
2403     if (rc != Success)
2404         return rc;
2405 
2406     grab = CreateGrab(client->index, dev, mod_dev, pWin, XI2,
2407                       mask, param, XI_TouchBegin, 0, NullWindow, NullCursor);
2408     if (!grab)
2409         return BadAlloc;
2410 
2411     return AddPassiveGrabToList(client, grab);
2412 }
2413 
2414 int
SelectForWindow(DeviceIntPtr dev,WindowPtr pWin,ClientPtr client,Mask mask,Mask exclusivemasks)2415 SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client,
2416                 Mask mask, Mask exclusivemasks)
2417 {
2418     int mskidx = dev->id;
2419     int i, ret;
2420     Mask check;
2421     InputClientsPtr others;
2422 
2423     check = (mask & exclusivemasks);
2424     if (wOtherInputMasks(pWin)) {
2425         if (check & wOtherInputMasks(pWin)->inputEvents[mskidx]) {
2426             /* It is illegal for two different clients to select on any of
2427              * the events for maskcheck. However, it is OK, for some client
2428              * to continue selecting on one of those events.
2429              */
2430             for (others = wOtherInputMasks(pWin)->inputClients; others;
2431                  others = others->next) {
2432                 if (!SameClient(others, client) && (check &
2433                                                     others->mask[mskidx]))
2434                     return BadAccess;
2435             }
2436         }
2437         for (others = wOtherInputMasks(pWin)->inputClients; others;
2438              others = others->next) {
2439             if (SameClient(others, client)) {
2440                 check = others->mask[mskidx];
2441                 others->mask[mskidx] = mask;
2442                 if (mask == 0) {
2443                     for (i = 0; i < EMASKSIZE; i++)
2444                         if (i != mskidx && others->mask[i] != 0)
2445                             break;
2446                     if (i == EMASKSIZE) {
2447                         RecalculateDeviceDeliverableEvents(pWin);
2448                         if (ShouldFreeInputMasks(pWin, FALSE))
2449                             FreeResource(others->resource, RT_NONE);
2450                         return Success;
2451                     }
2452                 }
2453                 goto maskSet;
2454             }
2455         }
2456     }
2457     check = 0;
2458     if ((ret = AddExtensionClient(pWin, client, mask, mskidx)) != Success)
2459         return ret;
2460  maskSet:
2461     if (dev->valuator)
2462         if ((dev->valuator->motionHintWindow == pWin) &&
2463             (mask & DevicePointerMotionHintMask) &&
2464             !(check & DevicePointerMotionHintMask) && !dev->deviceGrab.grab)
2465             dev->valuator->motionHintWindow = NullWindow;
2466     RecalculateDeviceDeliverableEvents(pWin);
2467     return Success;
2468 }
2469 
2470 static void
FreeInputClient(InputClientsPtr * other)2471 FreeInputClient(InputClientsPtr * other)
2472 {
2473     xi2mask_free(&(*other)->xi2mask);
2474     free(*other);
2475     *other = NULL;
2476 }
2477 
2478 static InputClientsPtr
AllocInputClient(void)2479 AllocInputClient(void)
2480 {
2481     return calloc(1, sizeof(InputClients));
2482 }
2483 
2484 int
AddExtensionClient(WindowPtr pWin,ClientPtr client,Mask mask,int mskidx)2485 AddExtensionClient(WindowPtr pWin, ClientPtr client, Mask mask, int mskidx)
2486 {
2487     InputClientsPtr others;
2488 
2489     if (!pWin->optional && !MakeWindowOptional(pWin))
2490         return BadAlloc;
2491     others = AllocInputClient();
2492     if (!others)
2493         return BadAlloc;
2494     if (!pWin->optional->inputMasks && !MakeInputMasks(pWin))
2495         goto bail;
2496     others->xi2mask = xi2mask_new();
2497     if (!others->xi2mask)
2498         goto bail;
2499     others->mask[mskidx] = mask;
2500     others->resource = FakeClientID(client->index);
2501     others->next = pWin->optional->inputMasks->inputClients;
2502     pWin->optional->inputMasks->inputClients = others;
2503     if (!AddResource(others->resource, RT_INPUTCLIENT, (void *) pWin))
2504         goto bail;
2505     return Success;
2506 
2507  bail:
2508     FreeInputClient(&others);
2509     return BadAlloc;
2510 }
2511 
2512 static Bool
MakeInputMasks(WindowPtr pWin)2513 MakeInputMasks(WindowPtr pWin)
2514 {
2515     struct _OtherInputMasks *imasks;
2516 
2517     imasks = calloc(1, sizeof(struct _OtherInputMasks));
2518     if (!imasks)
2519         return FALSE;
2520     imasks->xi2mask = xi2mask_new();
2521     if (!imasks->xi2mask) {
2522         free(imasks);
2523         return FALSE;
2524     }
2525     pWin->optional->inputMasks = imasks;
2526     return TRUE;
2527 }
2528 
2529 static void
FreeInputMask(OtherInputMasks ** imask)2530 FreeInputMask(OtherInputMasks ** imask)
2531 {
2532     xi2mask_free(&(*imask)->xi2mask);
2533     free(*imask);
2534     *imask = NULL;
2535 }
2536 
2537 void
RecalculateDeviceDeliverableEvents(WindowPtr pWin)2538 RecalculateDeviceDeliverableEvents(WindowPtr pWin)
2539 {
2540     InputClientsPtr others;
2541     struct _OtherInputMasks *inputMasks;        /* default: NULL */
2542     WindowPtr pChild, tmp;
2543     int i;
2544 
2545     pChild = pWin;
2546     while (1) {
2547         if ((inputMasks = wOtherInputMasks(pChild)) != 0) {
2548             xi2mask_zero(inputMasks->xi2mask, -1);
2549             for (others = inputMasks->inputClients; others;
2550                  others = others->next) {
2551                 for (i = 0; i < EMASKSIZE; i++)
2552                     inputMasks->inputEvents[i] |= others->mask[i];
2553                 xi2mask_merge(inputMasks->xi2mask, others->xi2mask);
2554             }
2555             for (i = 0; i < EMASKSIZE; i++)
2556                 inputMasks->deliverableEvents[i] = inputMasks->inputEvents[i];
2557             for (tmp = pChild->parent; tmp; tmp = tmp->parent)
2558                 if (wOtherInputMasks(tmp))
2559                     for (i = 0; i < EMASKSIZE; i++)
2560                         inputMasks->deliverableEvents[i] |=
2561                             (wOtherInputMasks(tmp)->deliverableEvents[i]
2562                              & ~inputMasks->dontPropagateMask[i] &
2563                              PropagateMask[i]);
2564         }
2565         if (pChild->firstChild) {
2566             pChild = pChild->firstChild;
2567             continue;
2568         }
2569         while (!pChild->nextSib && (pChild != pWin))
2570             pChild = pChild->parent;
2571         if (pChild == pWin)
2572             break;
2573         pChild = pChild->nextSib;
2574     }
2575 }
2576 
2577 int
InputClientGone(WindowPtr pWin,XID id)2578 InputClientGone(WindowPtr pWin, XID id)
2579 {
2580     InputClientsPtr other, prev;
2581 
2582     if (!wOtherInputMasks(pWin))
2583         return Success;
2584     prev = 0;
2585     for (other = wOtherInputMasks(pWin)->inputClients; other;
2586          other = other->next) {
2587         if (other->resource == id) {
2588             if (prev) {
2589                 prev->next = other->next;
2590                 FreeInputClient(&other);
2591             }
2592             else if (!(other->next)) {
2593                 if (ShouldFreeInputMasks(pWin, TRUE)) {
2594                     OtherInputMasks *mask = wOtherInputMasks(pWin);
2595 
2596                     mask->inputClients = other->next;
2597                     FreeInputMask(&mask);
2598                     pWin->optional->inputMasks = (OtherInputMasks *) NULL;
2599                     CheckWindowOptionalNeed(pWin);
2600                     FreeInputClient(&other);
2601                 }
2602                 else {
2603                     other->resource = FakeClientID(0);
2604                     if (!AddResource(other->resource, RT_INPUTCLIENT,
2605                                      (void *) pWin))
2606                         return BadAlloc;
2607                 }
2608             }
2609             else {
2610                 wOtherInputMasks(pWin)->inputClients = other->next;
2611                 FreeInputClient(&other);
2612             }
2613             RecalculateDeviceDeliverableEvents(pWin);
2614             return Success;
2615         }
2616         prev = other;
2617     }
2618     FatalError("client not on device event list");
2619 }
2620 
2621 /**
2622  * Search for window in each touch trace for each device. Remove the window
2623  * and all its subwindows from the trace when found. The initial window
2624  * order is preserved.
2625  */
2626 void
WindowGone(WindowPtr win)2627 WindowGone(WindowPtr win)
2628 {
2629     DeviceIntPtr dev;
2630 
2631     for (dev = inputInfo.devices; dev; dev = dev->next) {
2632         TouchClassPtr t = dev->touch;
2633         int i;
2634 
2635         if (!t)
2636             continue;
2637 
2638         for (i = 0; i < t->num_touches; i++) {
2639             SpritePtr sprite = &t->touches[i].sprite;
2640             int j;
2641 
2642             for (j = 0; j < sprite->spriteTraceGood; j++) {
2643                 if (sprite->spriteTrace[j] == win) {
2644                     sprite->spriteTraceGood = j;
2645                     break;
2646                 }
2647             }
2648         }
2649     }
2650 }
2651 
2652 int
SendEvent(ClientPtr client,DeviceIntPtr d,Window dest,Bool propagate,xEvent * ev,Mask mask,int count)2653 SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate,
2654           xEvent *ev, Mask mask, int count)
2655 {
2656     WindowPtr pWin;
2657     WindowPtr effectiveFocus = NullWindow;      /* only set if dest==InputFocus */
2658     WindowPtr spriteWin = GetSpriteWindow(d);
2659 
2660     if (dest == PointerWindow)
2661         pWin = spriteWin;
2662     else if (dest == InputFocus) {
2663         WindowPtr inputFocus;
2664 
2665         if (!d->focus)
2666             inputFocus = spriteWin;
2667         else
2668             inputFocus = d->focus->win;
2669 
2670         if (inputFocus == FollowKeyboardWin)
2671             inputFocus = inputInfo.keyboard->focus->win;
2672 
2673         if (inputFocus == NoneWin)
2674             return Success;
2675 
2676         /* If the input focus is PointerRootWin, send the event to where
2677          * the pointer is if possible, then perhaps propogate up to root. */
2678         if (inputFocus == PointerRootWin)
2679             inputFocus = GetCurrentRootWindow(d);
2680 
2681         if (IsParent(inputFocus, spriteWin)) {
2682             effectiveFocus = inputFocus;
2683             pWin = spriteWin;
2684         }
2685         else
2686             effectiveFocus = pWin = inputFocus;
2687     }
2688     else
2689         dixLookupWindow(&pWin, dest, client, DixSendAccess);
2690     if (!pWin)
2691         return BadWindow;
2692     if ((propagate != xFalse) && (propagate != xTrue)) {
2693         client->errorValue = propagate;
2694         return BadValue;
2695     }
2696     ev->u.u.type |= 0x80;
2697     if (propagate) {
2698         for (; pWin; pWin = pWin->parent) {
2699             if (DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab))
2700                 return Success;
2701             if (pWin == effectiveFocus)
2702                 return Success;
2703             if (wOtherInputMasks(pWin))
2704                 mask &= ~wOtherInputMasks(pWin)->dontPropagateMask[d->id];
2705             if (!mask)
2706                 break;
2707         }
2708     }
2709     else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, ev, count))
2710         DeliverEventsToWindow(d, pWin, ev, count, mask, NullGrab);
2711     return Success;
2712 }
2713 
2714 int
SetButtonMapping(ClientPtr client,DeviceIntPtr dev,int nElts,BYTE * map)2715 SetButtonMapping(ClientPtr client, DeviceIntPtr dev, int nElts, BYTE * map)
2716 {
2717     int i;
2718     ButtonClassPtr b = dev->button;
2719 
2720     if (b == NULL)
2721         return BadMatch;
2722 
2723     if (nElts != b->numButtons) {
2724         client->errorValue = nElts;
2725         return BadValue;
2726     }
2727     if (BadDeviceMap(&map[0], nElts, 1, 255, &client->errorValue))
2728         return BadValue;
2729     for (i = 0; i < nElts; i++)
2730         if ((b->map[i + 1] != map[i]) && BitIsOn(b->down, i + 1))
2731             return MappingBusy;
2732     for (i = 0; i < nElts; i++)
2733         b->map[i + 1] = map[i];
2734     return Success;
2735 }
2736 
2737 int
ChangeKeyMapping(ClientPtr client,DeviceIntPtr dev,unsigned len,int type,KeyCode firstKeyCode,CARD8 keyCodes,CARD8 keySymsPerKeyCode,KeySym * map)2738 ChangeKeyMapping(ClientPtr client,
2739                  DeviceIntPtr dev,
2740                  unsigned len,
2741                  int type,
2742                  KeyCode firstKeyCode,
2743                  CARD8 keyCodes, CARD8 keySymsPerKeyCode, KeySym * map)
2744 {
2745     KeySymsRec keysyms;
2746     KeyClassPtr k = dev->key;
2747 
2748     if (k == NULL)
2749         return BadMatch;
2750 
2751     if (len != (keyCodes * keySymsPerKeyCode))
2752         return BadLength;
2753 
2754     if ((firstKeyCode < k->xkbInfo->desc->min_key_code) ||
2755         (firstKeyCode + keyCodes - 1 > k->xkbInfo->desc->max_key_code)) {
2756         client->errorValue = firstKeyCode;
2757         return BadValue;
2758     }
2759     if (keySymsPerKeyCode == 0) {
2760         client->errorValue = 0;
2761         return BadValue;
2762     }
2763     keysyms.minKeyCode = firstKeyCode;
2764     keysyms.maxKeyCode = firstKeyCode + keyCodes - 1;
2765     keysyms.mapWidth = keySymsPerKeyCode;
2766     keysyms.map = map;
2767 
2768     XkbApplyMappingChange(dev, &keysyms, firstKeyCode, keyCodes, NULL,
2769                           serverClient);
2770 
2771     return Success;
2772 }
2773 
2774 static void
DeleteDeviceFromAnyExtEvents(WindowPtr pWin,DeviceIntPtr dev)2775 DeleteDeviceFromAnyExtEvents(WindowPtr pWin, DeviceIntPtr dev)
2776 {
2777     WindowPtr parent;
2778 
2779     /* Deactivate any grabs performed on this window, before making
2780      * any input focus changes.
2781      * Deactivating a device grab should cause focus events. */
2782 
2783     if (dev->deviceGrab.grab && (dev->deviceGrab.grab->window == pWin))
2784         (*dev->deviceGrab.DeactivateGrab) (dev);
2785 
2786     /* If the focus window is a root window (ie. has no parent)
2787      * then don't delete the focus from it. */
2788 
2789     if (dev->focus && (pWin == dev->focus->win) && (pWin->parent != NullWindow)) {
2790         int focusEventMode = NotifyNormal;
2791 
2792         /* If a grab is in progress, then alter the mode of focus events. */
2793 
2794         if (dev->deviceGrab.grab)
2795             focusEventMode = NotifyWhileGrabbed;
2796 
2797         switch (dev->focus->revert) {
2798         case RevertToNone:
2799             if (!ActivateFocusInGrab(dev, pWin, NoneWin))
2800                 DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
2801             dev->focus->win = NoneWin;
2802             dev->focus->traceGood = 0;
2803             break;
2804         case RevertToParent:
2805             parent = pWin;
2806             do {
2807                 parent = parent->parent;
2808                 dev->focus->traceGood--;
2809             }
2810             while (!parent->realized);
2811             if (!ActivateFocusInGrab(dev, pWin, parent))
2812                 DoFocusEvents(dev, pWin, parent, focusEventMode);
2813             dev->focus->win = parent;
2814             dev->focus->revert = RevertToNone;
2815             break;
2816         case RevertToPointerRoot:
2817             if (!ActivateFocusInGrab(dev, pWin, PointerRootWin))
2818                 DoFocusEvents(dev, pWin, PointerRootWin, focusEventMode);
2819             dev->focus->win = PointerRootWin;
2820             dev->focus->traceGood = 0;
2821             break;
2822         case RevertToFollowKeyboard:
2823         {
2824             DeviceIntPtr kbd = GetMaster(dev, MASTER_KEYBOARD);
2825 
2826             if (!kbd || (kbd == dev && kbd != inputInfo.keyboard))
2827                 kbd = inputInfo.keyboard;
2828             if (kbd->focus->win) {
2829                 if (!ActivateFocusInGrab(dev, pWin, kbd->focus->win))
2830                     DoFocusEvents(dev, pWin, kbd->focus->win, focusEventMode);
2831                 dev->focus->win = FollowKeyboardWin;
2832                 dev->focus->traceGood = 0;
2833             }
2834             else {
2835                 if (!ActivateFocusInGrab(dev, pWin, NoneWin))
2836                     DoFocusEvents(dev, pWin, NoneWin, focusEventMode);
2837                 dev->focus->win = NoneWin;
2838                 dev->focus->traceGood = 0;
2839             }
2840         }
2841             break;
2842         }
2843     }
2844 
2845     if (dev->valuator)
2846         if (dev->valuator->motionHintWindow == pWin)
2847             dev->valuator->motionHintWindow = NullWindow;
2848 }
2849 
2850 void
DeleteWindowFromAnyExtEvents(WindowPtr pWin,Bool freeResources)2851 DeleteWindowFromAnyExtEvents(WindowPtr pWin, Bool freeResources)
2852 {
2853     int i;
2854     DeviceIntPtr dev;
2855     InputClientsPtr ic;
2856     struct _OtherInputMasks *inputMasks;
2857 
2858     for (dev = inputInfo.devices; dev; dev = dev->next) {
2859         DeleteDeviceFromAnyExtEvents(pWin, dev);
2860     }
2861 
2862     for (dev = inputInfo.off_devices; dev; dev = dev->next)
2863         DeleteDeviceFromAnyExtEvents(pWin, dev);
2864 
2865     if (freeResources)
2866         while ((inputMasks = wOtherInputMasks(pWin)) != 0) {
2867             ic = inputMasks->inputClients;
2868             for (i = 0; i < EMASKSIZE; i++)
2869                 inputMasks->dontPropagateMask[i] = 0;
2870             FreeResource(ic->resource, RT_NONE);
2871         }
2872 }
2873 
2874 int
MaybeSendDeviceMotionNotifyHint(deviceKeyButtonPointer * pEvents,Mask mask)2875 MaybeSendDeviceMotionNotifyHint(deviceKeyButtonPointer *pEvents, Mask mask)
2876 {
2877     DeviceIntPtr dev;
2878 
2879     dixLookupDevice(&dev, pEvents->deviceid & DEVICE_BITS, serverClient,
2880                     DixReadAccess);
2881     if (!dev)
2882         return 0;
2883 
2884     if (pEvents->type == DeviceMotionNotify) {
2885         if (mask & DevicePointerMotionHintMask) {
2886             if (WID(dev->valuator->motionHintWindow) == pEvents->event) {
2887                 return 1;       /* don't send, but pretend we did */
2888             }
2889             pEvents->detail = NotifyHint;
2890         }
2891         else {
2892             pEvents->detail = NotifyNormal;
2893         }
2894     }
2895     return 0;
2896 }
2897 
2898 void
CheckDeviceGrabAndHintWindow(WindowPtr pWin,int type,deviceKeyButtonPointer * xE,GrabPtr grab,ClientPtr client,Mask deliveryMask)2899 CheckDeviceGrabAndHintWindow(WindowPtr pWin, int type,
2900                              deviceKeyButtonPointer *xE, GrabPtr grab,
2901                              ClientPtr client, Mask deliveryMask)
2902 {
2903     DeviceIntPtr dev;
2904 
2905     dixLookupDevice(&dev, xE->deviceid & DEVICE_BITS, serverClient,
2906                     DixGrabAccess);
2907     if (!dev)
2908         return;
2909 
2910     if (type == DeviceMotionNotify)
2911         dev->valuator->motionHintWindow = pWin;
2912     else if ((type == DeviceButtonPress) && (!grab) &&
2913              (deliveryMask & DeviceButtonGrabMask)) {
2914         GrabPtr tempGrab;
2915 
2916         tempGrab = AllocGrab(NULL);
2917         if (!tempGrab)
2918             return;
2919 
2920         tempGrab->device = dev;
2921         tempGrab->resource = client->clientAsMask;
2922         tempGrab->window = pWin;
2923         tempGrab->ownerEvents =
2924             (deliveryMask & DeviceOwnerGrabButtonMask) ? TRUE : FALSE;
2925         tempGrab->eventMask = deliveryMask;
2926         tempGrab->keyboardMode = GrabModeAsync;
2927         tempGrab->pointerMode = GrabModeAsync;
2928         tempGrab->confineTo = NullWindow;
2929         tempGrab->cursor = NullCursor;
2930         tempGrab->next = NULL;
2931         (*dev->deviceGrab.ActivateGrab) (dev, tempGrab, currentTime, TRUE);
2932         FreeGrab(tempGrab);
2933     }
2934 }
2935 
2936 static Mask
DeviceEventMaskForClient(DeviceIntPtr dev,WindowPtr pWin,ClientPtr client)2937 DeviceEventMaskForClient(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client)
2938 {
2939     InputClientsPtr other;
2940 
2941     if (!wOtherInputMasks(pWin))
2942         return 0;
2943     for (other = wOtherInputMasks(pWin)->inputClients; other;
2944          other = other->next) {
2945         if (SameClient(other, client))
2946             return other->mask[dev->id];
2947     }
2948     return 0;
2949 }
2950 
2951 void
MaybeStopDeviceHint(DeviceIntPtr dev,ClientPtr client)2952 MaybeStopDeviceHint(DeviceIntPtr dev, ClientPtr client)
2953 {
2954     WindowPtr pWin;
2955     GrabPtr grab = dev->deviceGrab.grab;
2956 
2957     pWin = dev->valuator->motionHintWindow;
2958 
2959     if ((grab && SameClient(grab, client) &&
2960          ((grab->eventMask & DevicePointerMotionHintMask) ||
2961           (grab->ownerEvents &&
2962            (DeviceEventMaskForClient(dev, pWin, client) &
2963             DevicePointerMotionHintMask)))) ||
2964         (!grab &&
2965          (DeviceEventMaskForClient(dev, pWin, client) &
2966           DevicePointerMotionHintMask)))
2967         dev->valuator->motionHintWindow = NullWindow;
2968 }
2969 
2970 int
DeviceEventSuppressForWindow(WindowPtr pWin,ClientPtr client,Mask mask,int maskndx)2971 DeviceEventSuppressForWindow(WindowPtr pWin, ClientPtr client, Mask mask,
2972                              int maskndx)
2973 {
2974     struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
2975 
2976     if (mask & ~PropagateMask[maskndx]) {
2977         client->errorValue = mask;
2978         return BadValue;
2979     }
2980 
2981     if (mask == 0) {
2982         if (inputMasks)
2983             inputMasks->dontPropagateMask[maskndx] = mask;
2984     }
2985     else {
2986         if (!inputMasks)
2987             AddExtensionClient(pWin, client, 0, 0);
2988         inputMasks = wOtherInputMasks(pWin);
2989         inputMasks->dontPropagateMask[maskndx] = mask;
2990     }
2991     RecalculateDeviceDeliverableEvents(pWin);
2992     if (ShouldFreeInputMasks(pWin, FALSE))
2993         FreeResource(inputMasks->inputClients->resource, RT_NONE);
2994     return Success;
2995 }
2996 
2997 Bool
ShouldFreeInputMasks(WindowPtr pWin,Bool ignoreSelectedEvents)2998 ShouldFreeInputMasks(WindowPtr pWin, Bool ignoreSelectedEvents)
2999 {
3000     int i;
3001     Mask allInputEventMasks = 0;
3002     struct _OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
3003 
3004     for (i = 0; i < EMASKSIZE; i++)
3005         allInputEventMasks |= inputMasks->dontPropagateMask[i];
3006     if (!ignoreSelectedEvents)
3007         for (i = 0; i < EMASKSIZE; i++)
3008             allInputEventMasks |= inputMasks->inputEvents[i];
3009     if (allInputEventMasks == 0)
3010         return TRUE;
3011     else
3012         return FALSE;
3013 }
3014 
3015 /***********************************************************************
3016  *
3017  * Walk through the window tree, finding all clients that want to know
3018  * about the Event.
3019  *
3020  */
3021 
3022 static void
FindInterestedChildren(DeviceIntPtr dev,WindowPtr p1,Mask mask,xEvent * ev,int count)3023 FindInterestedChildren(DeviceIntPtr dev, WindowPtr p1, Mask mask,
3024                        xEvent *ev, int count)
3025 {
3026     WindowPtr p2;
3027 
3028     while (p1) {
3029         p2 = p1->firstChild;
3030         DeliverEventsToWindow(dev, p1, ev, count, mask, NullGrab);
3031         FindInterestedChildren(dev, p2, mask, ev, count);
3032         p1 = p1->nextSib;
3033     }
3034 }
3035 
3036 /***********************************************************************
3037  *
3038  * Send an event to interested clients in all windows on all screens.
3039  *
3040  */
3041 
3042 void
SendEventToAllWindows(DeviceIntPtr dev,Mask mask,xEvent * ev,int count)3043 SendEventToAllWindows(DeviceIntPtr dev, Mask mask, xEvent *ev, int count)
3044 {
3045     int i;
3046     WindowPtr pWin, p1;
3047 
3048     for (i = 0; i < screenInfo.numScreens; i++) {
3049         pWin = screenInfo.screens[i]->root;
3050         if (!pWin)
3051             continue;
3052         DeliverEventsToWindow(dev, pWin, ev, count, mask, NullGrab);
3053         p1 = pWin->firstChild;
3054         FindInterestedChildren(dev, p1, mask, ev, count);
3055     }
3056 }
3057 
3058 /**
3059  * Set the XI2 mask for the given client on the given window.
3060  * @param dev The device to set the mask for.
3061  * @param win The window to set the mask on.
3062  * @param client The client setting the mask.
3063  * @param len Number of bytes in mask.
3064  * @param mask Event mask in the form of (1 << eventtype)
3065  */
3066 int
XISetEventMask(DeviceIntPtr dev,WindowPtr win,ClientPtr client,unsigned int len,unsigned char * mask)3067 XISetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client,
3068                unsigned int len, unsigned char *mask)
3069 {
3070     OtherInputMasks *masks;
3071     InputClientsPtr others = NULL;
3072 
3073     masks = wOtherInputMasks(win);
3074     if (masks) {
3075         for (others = wOtherInputMasks(win)->inputClients; others;
3076              others = others->next) {
3077             if (SameClient(others, client)) {
3078                 xi2mask_zero(others->xi2mask, dev->id);
3079                 break;
3080             }
3081         }
3082     }
3083 
3084     if (len && !others) {
3085         if (AddExtensionClient(win, client, 0, 0) != Success)
3086             return BadAlloc;
3087         others = wOtherInputMasks(win)->inputClients;
3088     }
3089 
3090     if (others) {
3091         xi2mask_zero(others->xi2mask, dev->id);
3092         len = min(len, xi2mask_mask_size(others->xi2mask));
3093     }
3094 
3095     if (len) {
3096         xi2mask_set_one_mask(others->xi2mask, dev->id, mask, len);
3097     }
3098 
3099     RecalculateDeviceDeliverableEvents(win);
3100 
3101     return Success;
3102 }
3103