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