1 /*
2  * Copyright © 2011 Collabra Ltd.
3  * Copyright © 2011 Red Hat, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Author: Daniel Stone <daniel@fooishbar.org>
25  */
26 
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
29 #endif
30 
31 #include "inputstr.h"
32 #include "scrnintstr.h"
33 #include "dixgrabs.h"
34 
35 #include "eventstr.h"
36 #include "exevents.h"
37 #include "exglobals.h"
38 #include "inpututils.h"
39 #include "eventconvert.h"
40 #include "windowstr.h"
41 #include "mi.h"
42 
43 #define TOUCH_HISTORY_SIZE 100
44 
45 /**
46  * Some documentation about touch points:
47  * The driver submits touch events with it's own (unique) touch point ID.
48  * The driver may re-use those IDs, the DDX doesn't care. It just passes on
49  * the data to the DIX. In the server, the driver's ID is referred to as the
50  * DDX id anyway.
51  *
52  * On a TouchBegin, we create a DDXTouchPointInfo that contains the DDX id
53  * and the client ID that this touchpoint will have. The client ID is the
54  * one visible on the protocol.
55  *
56  * TouchUpdate and TouchEnd will only be processed if there is an active
57  * touchpoint with the same DDX id.
58  *
59  * The DDXTouchPointInfo struct is stored dev->last.touches. When the event
60  * being processed, it becomes a TouchPointInfo in dev->touch-touches which
61  * contains amongst other things the sprite trace and delivery information.
62  */
63 
64 /**
65  * Check which devices need a bigger touch event queue and grow their
66  * last.touches by half it's current size.
67  *
68  * @param client Always the serverClient
69  * @param closure Always NULL
70  *
71  * @return Always True. If we fail to grow we probably will topple over soon
72  * anyway and re-executing this won't help.
73  */
74 
75 static Bool
TouchResizeQueue(DeviceIntPtr dev)76 TouchResizeQueue(DeviceIntPtr dev)
77 {
78     DDXTouchPointInfoPtr tmp;
79     size_t size;
80 
81     /* Grow sufficiently so we don't need to do it often */
82     size = dev->last.num_touches + dev->last.num_touches / 2 + 1;
83 
84     tmp = reallocarray(dev->last.touches, size, sizeof(*dev->last.touches));
85     if (tmp) {
86         int j;
87 
88         dev->last.touches = tmp;
89         for (j = dev->last.num_touches; j < size; j++)
90             TouchInitDDXTouchPoint(dev, &dev->last.touches[j]);
91         dev->last.num_touches = size;
92         return TRUE;
93     }
94     return FALSE;
95 }
96 
97 /**
98  * Given the DDX-facing ID (which is _not_ DeviceEvent::detail.touch), find the
99  * associated DDXTouchPointInfoRec.
100  *
101  * @param dev The device to create the touch point for
102  * @param ddx_id Touch id assigned by the driver/ddx
103  * @param create Create the touchpoint if it cannot be found
104  */
105 DDXTouchPointInfoPtr
TouchFindByDDXID(DeviceIntPtr dev,uint32_t ddx_id,Bool create)106 TouchFindByDDXID(DeviceIntPtr dev, uint32_t ddx_id, Bool create)
107 {
108     DDXTouchPointInfoPtr ti;
109     int i;
110 
111     if (!dev->touch)
112         return NULL;
113 
114     for (i = 0; i < dev->last.num_touches; i++) {
115         ti = &dev->last.touches[i];
116         if (ti->active && ti->ddx_id == ddx_id)
117             return ti;
118     }
119 
120     return create ? TouchBeginDDXTouch(dev, ddx_id) : NULL;
121 }
122 
123 /**
124  * Given a unique DDX ID for a touchpoint, create a touchpoint record and
125  * return it.
126  *
127  * If no other touch points are active, mark new touchpoint for pointer
128  * emulation.
129  *
130  * Returns NULL on failure (i.e. if another touch with that ID is already active,
131  * allocation failure).
132  */
133 DDXTouchPointInfoPtr
TouchBeginDDXTouch(DeviceIntPtr dev,uint32_t ddx_id)134 TouchBeginDDXTouch(DeviceIntPtr dev, uint32_t ddx_id)
135 {
136     static int next_client_id = 1;
137     int i;
138     TouchClassPtr t = dev->touch;
139     DDXTouchPointInfoPtr ti = NULL;
140     Bool emulate_pointer;
141 
142     if (!t)
143         return NULL;
144 
145     emulate_pointer = (t->mode == XIDirectTouch);
146 
147     /* Look for another active touchpoint with the same DDX ID. DDX
148      * touchpoints must be unique. */
149     if (TouchFindByDDXID(dev, ddx_id, FALSE))
150         return NULL;
151 
152     for (;;) {
153         for (i = 0; i < dev->last.num_touches; i++) {
154             /* Only emulate pointer events on the first touch */
155             if (dev->last.touches[i].active)
156                 emulate_pointer = FALSE;
157             else if (!ti)           /* ti is now first non-active touch rec */
158                 ti = &dev->last.touches[i];
159 
160             if (!emulate_pointer && ti)
161                 break;
162         }
163         if (ti)
164             break;
165         if (!TouchResizeQueue(dev))
166             break;
167     }
168 
169     if (ti) {
170         int client_id;
171 
172         ti->active = TRUE;
173         ti->ddx_id = ddx_id;
174         client_id = next_client_id;
175         next_client_id++;
176         if (next_client_id == 0)
177             next_client_id = 1;
178         ti->client_id = client_id;
179         ti->emulate_pointer = emulate_pointer;
180     }
181     return ti;
182 }
183 
184 void
TouchEndDDXTouch(DeviceIntPtr dev,DDXTouchPointInfoPtr ti)185 TouchEndDDXTouch(DeviceIntPtr dev, DDXTouchPointInfoPtr ti)
186 {
187     TouchClassPtr t = dev->touch;
188 
189     if (!t)
190         return;
191 
192     ti->active = FALSE;
193 }
194 
195 void
TouchInitDDXTouchPoint(DeviceIntPtr dev,DDXTouchPointInfoPtr ddxtouch)196 TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch)
197 {
198     memset(ddxtouch, 0, sizeof(*ddxtouch));
199     ddxtouch->valuators = valuator_mask_new(dev->valuator->numAxes);
200 }
201 
202 Bool
TouchInitTouchPoint(TouchClassPtr t,ValuatorClassPtr v,int index)203 TouchInitTouchPoint(TouchClassPtr t, ValuatorClassPtr v, int index)
204 {
205     TouchPointInfoPtr ti;
206 
207     if (index >= t->num_touches)
208         return FALSE;
209     ti = &t->touches[index];
210 
211     memset(ti, 0, sizeof(*ti));
212 
213     ti->valuators = valuator_mask_new(v->numAxes);
214     if (!ti->valuators)
215         return FALSE;
216 
217     ti->sprite.spriteTrace = calloc(32, sizeof(*ti->sprite.spriteTrace));
218     if (!ti->sprite.spriteTrace) {
219         valuator_mask_free(&ti->valuators);
220         return FALSE;
221     }
222     ti->sprite.spriteTraceSize = 32;
223     ti->sprite.spriteTrace[0] = screenInfo.screens[0]->root;
224     ti->sprite.hot.pScreen = screenInfo.screens[0];
225     ti->sprite.hotPhys.pScreen = screenInfo.screens[0];
226 
227     ti->client_id = -1;
228 
229     return TRUE;
230 }
231 
232 void
TouchFreeTouchPoint(DeviceIntPtr device,int index)233 TouchFreeTouchPoint(DeviceIntPtr device, int index)
234 {
235     TouchPointInfoPtr ti;
236     int i;
237 
238     if (!device->touch || index >= device->touch->num_touches)
239         return;
240     ti = &device->touch->touches[index];
241 
242     if (ti->active)
243         TouchEndTouch(device, ti);
244 
245     for (i = 0; i < ti->num_listeners; i++)
246         TouchRemoveListener(ti, ti->listeners[0].listener);
247 
248     valuator_mask_free(&ti->valuators);
249     free(ti->sprite.spriteTrace);
250     ti->sprite.spriteTrace = NULL;
251     free(ti->listeners);
252     ti->listeners = NULL;
253     free(ti->history);
254     ti->history = NULL;
255     ti->history_size = 0;
256     ti->history_elements = 0;
257 }
258 
259 /**
260  * Given a client-facing ID (e.g. DeviceEvent::detail.touch), find the
261  * associated TouchPointInfoRec.
262  */
263 TouchPointInfoPtr
TouchFindByClientID(DeviceIntPtr dev,uint32_t client_id)264 TouchFindByClientID(DeviceIntPtr dev, uint32_t client_id)
265 {
266     TouchClassPtr t = dev->touch;
267     TouchPointInfoPtr ti;
268     int i;
269 
270     if (!t)
271         return NULL;
272 
273     for (i = 0; i < t->num_touches; i++) {
274         ti = &t->touches[i];
275         if (ti->active && ti->client_id == client_id)
276             return ti;
277     }
278 
279     return NULL;
280 }
281 
282 /**
283  * Given a unique ID for a touchpoint, create a touchpoint record in the
284  * server.
285  *
286  * Returns NULL on failure (i.e. if another touch with that ID is already active,
287  * allocation failure).
288  */
289 TouchPointInfoPtr
TouchBeginTouch(DeviceIntPtr dev,int sourceid,uint32_t touchid,Bool emulate_pointer)290 TouchBeginTouch(DeviceIntPtr dev, int sourceid, uint32_t touchid,
291                 Bool emulate_pointer)
292 {
293     int i;
294     TouchClassPtr t = dev->touch;
295     TouchPointInfoPtr ti;
296     void *tmp;
297 
298     if (!t)
299         return NULL;
300 
301     /* Look for another active touchpoint with the same client ID.  It's
302      * technically legitimate for a touchpoint to still exist with the same
303      * ID but only once the 32 bits wrap over and you've used up 4 billion
304      * touch ids without lifting that one finger off once. In which case
305      * you deserve a medal or something, but not error handling code. */
306     if (TouchFindByClientID(dev, touchid))
307         return NULL;
308 
309  try_find_touch:
310     for (i = 0; i < t->num_touches; i++) {
311         ti = &t->touches[i];
312         if (!ti->active) {
313             ti->active = TRUE;
314             ti->client_id = touchid;
315             ti->sourceid = sourceid;
316             ti->emulate_pointer = emulate_pointer;
317             return ti;
318         }
319     }
320 
321     /* If we get here, then we've run out of touches: enlarge dev->touch and
322      * try again. */
323     tmp = reallocarray(t->touches, t->num_touches + 1, sizeof(*ti));
324     if (tmp) {
325         t->touches = tmp;
326         t->num_touches++;
327         if (TouchInitTouchPoint(t, dev->valuator, t->num_touches - 1))
328             goto try_find_touch;
329     }
330 
331     return NULL;
332 }
333 
334 /**
335  * Releases a touchpoint for use: this must only be called after all events
336  * related to that touchpoint have been sent and finalised.  Called from
337  * ProcessTouchEvent and friends.  Not by you.
338  */
339 void
TouchEndTouch(DeviceIntPtr dev,TouchPointInfoPtr ti)340 TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
341 {
342     int i;
343 
344     if (ti->emulate_pointer) {
345         GrabPtr grab;
346 
347         if ((grab = dev->deviceGrab.grab)) {
348             if (dev->deviceGrab.fromPassiveGrab &&
349                 !dev->button->buttonsDown &&
350                 !dev->touch->buttonsDown && GrabIsPointerGrab(grab))
351                 (*dev->deviceGrab.DeactivateGrab) (dev);
352         }
353     }
354 
355     for (i = 0; i < ti->num_listeners; i++)
356         TouchRemoveListener(ti, ti->listeners[0].listener);
357 
358     ti->active = FALSE;
359     ti->pending_finish = FALSE;
360     ti->sprite.spriteTraceGood = 0;
361     free(ti->listeners);
362     ti->listeners = NULL;
363     ti->num_listeners = 0;
364     ti->num_grabs = 0;
365     ti->client_id = 0;
366 
367     TouchEventHistoryFree(ti);
368 
369     valuator_mask_zero(ti->valuators);
370 }
371 
372 /**
373  * Allocate the event history for this touch pointer. Calling this on a
374  * touchpoint that already has an event history does nothing but counts as
375  * as success.
376  *
377  * @return TRUE on success, FALSE on allocation errors
378  */
379 Bool
TouchEventHistoryAllocate(TouchPointInfoPtr ti)380 TouchEventHistoryAllocate(TouchPointInfoPtr ti)
381 {
382     if (ti->history)
383         return TRUE;
384 
385     ti->history = calloc(TOUCH_HISTORY_SIZE, sizeof(*ti->history));
386     ti->history_elements = 0;
387     if (ti->history)
388         ti->history_size = TOUCH_HISTORY_SIZE;
389     return ti->history != NULL;
390 }
391 
392 void
TouchEventHistoryFree(TouchPointInfoPtr ti)393 TouchEventHistoryFree(TouchPointInfoPtr ti)
394 {
395     free(ti->history);
396     ti->history = NULL;
397     ti->history_size = 0;
398     ti->history_elements = 0;
399 }
400 
401 /**
402  * Store the given event on the event history (if one exists)
403  * A touch event history consists of one TouchBegin and several TouchUpdate
404  * events (if applicable) but no TouchEnd event.
405  * If more than one TouchBegin is pushed onto the stack, the push is
406  * ignored, calling this function multiple times for the TouchBegin is
407  * valid.
408  */
409 void
TouchEventHistoryPush(TouchPointInfoPtr ti,const DeviceEvent * ev)410 TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev)
411 {
412     if (!ti->history)
413         return;
414 
415     switch (ev->type) {
416     case ET_TouchBegin:
417         /* don't store the same touchbegin twice */
418         if (ti->history_elements > 0)
419             return;
420         break;
421     case ET_TouchUpdate:
422         break;
423     case ET_TouchEnd:
424         return;                 /* no TouchEnd events in the history */
425     default:
426         return;
427     }
428 
429     /* We only store real events in the history */
430     if (ev->flags & (TOUCH_CLIENT_ID | TOUCH_REPLAYING))
431         return;
432 
433     ti->history[ti->history_elements++] = *ev;
434     /* FIXME: proper overflow fixes */
435     if (ti->history_elements > ti->history_size - 1) {
436         ti->history_elements = ti->history_size - 1;
437         DebugF("source device %d: history size %zu overflowing for touch %u\n",
438                ti->sourceid, ti->history_size, ti->client_id);
439     }
440 }
441 
442 void
TouchEventHistoryReplay(TouchPointInfoPtr ti,DeviceIntPtr dev,XID resource)443 TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
444 {
445     int i;
446 
447     if (!ti->history)
448         return;
449 
450     TouchDeliverDeviceClassesChangedEvent(ti, ti->history[0].time, resource);
451 
452     for (i = 0; i < ti->history_elements; i++) {
453         DeviceEvent *ev = &ti->history[i];
454 
455         ev->flags |= TOUCH_REPLAYING;
456         ev->resource = resource;
457         /* FIXME:
458            We're replaying ti->history which contains the TouchBegin +
459            all TouchUpdates for ti. This needs to be passed on to the next
460            listener. If that is a touch listener, everything is dandy.
461            If the TouchBegin however triggers a sync passive grab, the
462            TouchUpdate events must be sent to EnqueueEvent so the events end
463            up in syncEvents.pending to be forwarded correctly in a
464            subsequent ComputeFreeze().
465 
466            However, if we just send them to EnqueueEvent the sync'ing device
467            prevents handling of touch events for ownership listeners who
468            want the events right here, right now.
469          */
470         dev->public.processInputProc((InternalEvent*)ev, dev);
471     }
472 }
473 
474 void
TouchDeliverDeviceClassesChangedEvent(TouchPointInfoPtr ti,Time time,XID resource)475 TouchDeliverDeviceClassesChangedEvent(TouchPointInfoPtr ti, Time time,
476                                       XID resource)
477 {
478     DeviceIntPtr dev;
479     int num_events = 0;
480     InternalEvent dcce;
481 
482     dixLookupDevice(&dev, ti->sourceid, serverClient, DixWriteAccess);
483 
484     if (!dev)
485         return;
486 
487     /* UpdateFromMaster generates at most one event */
488     UpdateFromMaster(&dcce, dev, DEVCHANGE_POINTER_EVENT, &num_events);
489     BUG_WARN(num_events > 1);
490 
491     if (num_events) {
492         dcce.any.time = time;
493         /* FIXME: This doesn't do anything */
494         dev->public.processInputProc(&dcce, dev);
495     }
496 }
497 
498 Bool
TouchBuildDependentSpriteTrace(DeviceIntPtr dev,SpritePtr sprite)499 TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite)
500 {
501     int i;
502     TouchClassPtr t = dev->touch;
503     WindowPtr *trace;
504     SpritePtr srcsprite;
505 
506     /* All touches should have the same sprite trace, so find and reuse an
507      * existing touch's sprite if possible, else use the device's sprite. */
508     for (i = 0; i < t->num_touches; i++)
509         if (!t->touches[i].pending_finish &&
510             t->touches[i].sprite.spriteTraceGood > 0)
511             break;
512     if (i < t->num_touches)
513         srcsprite = &t->touches[i].sprite;
514     else if (dev->spriteInfo->sprite)
515         srcsprite = dev->spriteInfo->sprite;
516     else
517         return FALSE;
518 
519     if (srcsprite->spriteTraceGood > sprite->spriteTraceSize) {
520         trace = reallocarray(sprite->spriteTrace,
521                              srcsprite->spriteTraceSize, sizeof(*trace));
522         if (!trace) {
523             sprite->spriteTraceGood = 0;
524             return FALSE;
525         }
526         sprite->spriteTrace = trace;
527         sprite->spriteTraceSize = srcsprite->spriteTraceGood;
528     }
529     memcpy(sprite->spriteTrace, srcsprite->spriteTrace,
530            srcsprite->spriteTraceGood * sizeof(*trace));
531     sprite->spriteTraceGood = srcsprite->spriteTraceGood;
532 
533     return TRUE;
534 }
535 
536 /**
537  * Ensure a window trace is present in ti->sprite, constructing one for
538  * TouchBegin events.
539  */
540 Bool
TouchBuildSprite(DeviceIntPtr sourcedev,TouchPointInfoPtr ti,InternalEvent * ev)541 TouchBuildSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
542                  InternalEvent *ev)
543 {
544     TouchClassPtr t = sourcedev->touch;
545     SpritePtr sprite = &ti->sprite;
546 
547     if (t->mode == XIDirectTouch) {
548         /* Focus immediately under the touchpoint in direct touch mode.
549          * XXX: Do we need to handle crossing screens here? */
550         sprite->spriteTrace[0] =
551             sourcedev->spriteInfo->sprite->hotPhys.pScreen->root;
552         XYToWindow(sprite, ev->device_event.root_x, ev->device_event.root_y);
553     }
554     else if (!TouchBuildDependentSpriteTrace(sourcedev, sprite))
555         return FALSE;
556 
557     if (sprite->spriteTraceGood <= 0)
558         return FALSE;
559 
560     /* Mark which grabs/event selections we're delivering to: max one grab per
561      * window plus the bottom-most event selection, plus any active grab. */
562     ti->listeners = calloc(sprite->spriteTraceGood + 2, sizeof(*ti->listeners));
563     if (!ti->listeners) {
564         sprite->spriteTraceGood = 0;
565         return FALSE;
566     }
567     ti->num_listeners = 0;
568 
569     return TRUE;
570 }
571 
572 /**
573  * Copy the touch event into the pointer_event, switching the required
574  * fields to make it a correct pointer event.
575  *
576  * @param event The original touch event
577  * @param[in] motion_event The respective motion event
578  * @param[in] button_event The respective button event (if any)
579  *
580  * @returns The number of converted events.
581  * @retval 0 An error occured
582  * @retval 1 only the motion event is valid
583  * @retval 2 motion and button event are valid
584  */
585 int
TouchConvertToPointerEvent(const InternalEvent * event,InternalEvent * motion_event,InternalEvent * button_event)586 TouchConvertToPointerEvent(const InternalEvent *event,
587                            InternalEvent *motion_event,
588                            InternalEvent *button_event)
589 {
590     int ptrtype;
591     int nevents = 0;
592 
593     BUG_RETURN_VAL(!event, 0);
594     BUG_RETURN_VAL(!motion_event, 0);
595 
596     switch (event->any.type) {
597     case ET_TouchUpdate:
598         nevents = 1;
599         break;
600     case ET_TouchBegin:
601         nevents = 2;            /* motion + press */
602         ptrtype = ET_ButtonPress;
603         break;
604     case ET_TouchEnd:
605         nevents = 2;            /* motion + release */
606         ptrtype = ET_ButtonRelease;
607         break;
608     default:
609         BUG_WARN_MSG(1, "Invalid event type %d\n", event->any.type);
610         return 0;
611     }
612 
613     BUG_WARN_MSG(!(event->device_event.flags & TOUCH_POINTER_EMULATED),
614                  "Non-emulating touch event\n");
615 
616     motion_event->device_event = event->device_event;
617     motion_event->any.type = ET_Motion;
618     motion_event->device_event.detail.button = 0;
619     motion_event->device_event.flags = XIPointerEmulated;
620 
621     if (nevents > 1) {
622         BUG_RETURN_VAL(!button_event, 0);
623         button_event->device_event = event->device_event;
624         button_event->any.type = ptrtype;
625         button_event->device_event.flags = XIPointerEmulated;
626         /* detail is already correct */
627     }
628 
629     return nevents;
630 }
631 
632 /**
633  * Return the corresponding pointer emulation internal event type for the given
634  * touch event or 0 if no such event type exists.
635  */
636 int
TouchGetPointerEventType(const InternalEvent * event)637 TouchGetPointerEventType(const InternalEvent *event)
638 {
639     int type = 0;
640 
641     switch (event->any.type) {
642     case ET_TouchBegin:
643         type = ET_ButtonPress;
644         break;
645     case ET_TouchUpdate:
646         type = ET_Motion;
647         break;
648     case ET_TouchEnd:
649         type = ET_ButtonRelease;
650         break;
651     default:
652         break;
653     }
654     return type;
655 }
656 
657 /**
658  * @returns TRUE if the specified grab or selection is the current owner of
659  * the touch sequence.
660  */
661 Bool
TouchResourceIsOwner(TouchPointInfoPtr ti,XID resource)662 TouchResourceIsOwner(TouchPointInfoPtr ti, XID resource)
663 {
664     return (ti->listeners[0].listener == resource);
665 }
666 
667 /**
668  * Add the resource to this touch's listeners.
669  */
670 void
TouchAddListener(TouchPointInfoPtr ti,XID resource,int resource_type,enum InputLevel level,enum TouchListenerType type,enum TouchListenerState state,WindowPtr window,const GrabPtr grab)671 TouchAddListener(TouchPointInfoPtr ti, XID resource, int resource_type,
672                  enum InputLevel level, enum TouchListenerType type,
673                  enum TouchListenerState state, WindowPtr window,
674                  const GrabPtr grab)
675 {
676     GrabPtr g = NULL;
677 
678     /* We need a copy of the grab, not the grab itself since that may be
679      * deleted by a UngrabButton request and leaves us with a dangling
680      * pointer */
681     if (grab)
682         g = AllocGrab(grab);
683 
684     ti->listeners[ti->num_listeners].listener = resource;
685     ti->listeners[ti->num_listeners].resource_type = resource_type;
686     ti->listeners[ti->num_listeners].level = level;
687     ti->listeners[ti->num_listeners].state = state;
688     ti->listeners[ti->num_listeners].type = type;
689     ti->listeners[ti->num_listeners].window = window;
690     ti->listeners[ti->num_listeners].grab = g;
691     if (grab)
692         ti->num_grabs++;
693     ti->num_listeners++;
694 }
695 
696 /**
697  * Remove the resource from this touch's listeners.
698  *
699  * @return TRUE if the resource was removed, FALSE if the resource was not
700  * in the list
701  */
702 Bool
TouchRemoveListener(TouchPointInfoPtr ti,XID resource)703 TouchRemoveListener(TouchPointInfoPtr ti, XID resource)
704 {
705     int i;
706 
707     for (i = 0; i < ti->num_listeners; i++) {
708         int j;
709         TouchListener *listener = &ti->listeners[i];
710 
711         if (listener->listener != resource)
712             continue;
713 
714         if (listener->grab) {
715             FreeGrab(listener->grab);
716             listener->grab = NULL;
717             ti->num_grabs--;
718         }
719 
720         for (j = i; j < ti->num_listeners - 1; j++)
721             ti->listeners[j] = ti->listeners[j + 1];
722         ti->num_listeners--;
723         ti->listeners[ti->num_listeners].listener = 0;
724         ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN;
725 
726         return TRUE;
727     }
728     return FALSE;
729 }
730 
731 static void
TouchAddGrabListener(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,GrabPtr grab)732 TouchAddGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
733                      InternalEvent *ev, GrabPtr grab)
734 {
735     enum TouchListenerType type = LISTENER_GRAB;
736 
737     /* FIXME: owner_events */
738 
739     if (grab->grabtype == XI2) {
740         if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchOwnership))
741             TouchEventHistoryAllocate(ti);
742         if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin))
743             type = LISTENER_POINTER_GRAB;
744     }
745     else if (grab->grabtype == XI || grab->grabtype == CORE) {
746         TouchEventHistoryAllocate(ti);
747         type = LISTENER_POINTER_GRAB;
748     }
749 
750     /* grab listeners are always RT_NONE since we keep the grab pointer */
751     TouchAddListener(ti, grab->resource, RT_NONE, grab->grabtype,
752                      type, LISTENER_AWAITING_BEGIN, grab->window, grab);
753 }
754 
755 /**
756  * Add one listener if there is a grab on the given window.
757  */
758 static void
TouchAddPassiveGrabListener(DeviceIntPtr dev,TouchPointInfoPtr ti,WindowPtr win,InternalEvent * ev)759 TouchAddPassiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
760                             WindowPtr win, InternalEvent *ev)
761 {
762     GrabPtr grab;
763     Bool check_core = IsMaster(dev) && ti->emulate_pointer;
764 
765     /* FIXME: make CheckPassiveGrabsOnWindow only trigger on TouchBegin */
766     grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core, FALSE);
767     if (!grab)
768         return;
769 
770     TouchAddGrabListener(dev, ti, ev, grab);
771 }
772 
773 static Bool
TouchAddRegularListener(DeviceIntPtr dev,TouchPointInfoPtr ti,WindowPtr win,InternalEvent * ev)774 TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
775                         WindowPtr win, InternalEvent *ev)
776 {
777     InputClients *iclients = NULL;
778     OtherInputMasks *inputMasks = NULL;
779     uint16_t evtype = 0;        /* may be event type or emulated event type */
780     enum TouchListenerType type = LISTENER_REGULAR;
781     int mask;
782 
783     evtype = GetXI2Type(ev->any.type);
784     mask = EventIsDeliverable(dev, ev->any.type, win);
785     if (!mask && !ti->emulate_pointer)
786         return FALSE;
787     else if (!mask) {           /* now try for pointer event */
788         mask = EventIsDeliverable(dev, TouchGetPointerEventType(ev), win);
789         if (mask) {
790             evtype = GetXI2Type(TouchGetPointerEventType(ev));
791             type = LISTENER_POINTER_REGULAR;
792         }
793     }
794     if (!mask)
795         return FALSE;
796 
797     inputMasks = wOtherInputMasks(win);
798 
799     if (mask & EVENT_XI2_MASK) {
800         nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
801             if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
802                 continue;
803 
804             if (!xi2mask_isset(iclients->xi2mask, dev, XI_TouchOwnership))
805                 TouchEventHistoryAllocate(ti);
806 
807             TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI2,
808                              type, LISTENER_AWAITING_BEGIN, win, NULL);
809             return TRUE;
810         }
811     }
812 
813     if (mask & EVENT_XI1_MASK) {
814         int xitype = GetXIType(TouchGetPointerEventType(ev));
815         Mask xi_filter = event_get_filter_from_type(dev, xitype);
816 
817         nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
818             if (!(iclients->mask[dev->id] & xi_filter))
819                 continue;
820 
821             TouchEventHistoryAllocate(ti);
822             TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI,
823                              LISTENER_POINTER_REGULAR, LISTENER_AWAITING_BEGIN,
824                              win, NULL);
825             return TRUE;
826         }
827     }
828 
829     if (mask & EVENT_CORE_MASK) {
830         int coretype = GetCoreType(TouchGetPointerEventType(ev));
831         Mask core_filter = event_get_filter_from_type(dev, coretype);
832         OtherClients *oclients;
833 
834         /* window owner */
835         if (IsMaster(dev) && (win->eventMask & core_filter)) {
836             TouchEventHistoryAllocate(ti);
837             TouchAddListener(ti, win->drawable.id, RT_WINDOW, CORE,
838                              LISTENER_POINTER_REGULAR, LISTENER_AWAITING_BEGIN,
839                              win, NULL);
840             return TRUE;
841         }
842 
843         /* all others */
844         nt_list_for_each_entry(oclients, wOtherClients(win), next) {
845             if (!(oclients->mask & core_filter))
846                 continue;
847 
848             TouchEventHistoryAllocate(ti);
849             TouchAddListener(ti, oclients->resource, RT_OTHERCLIENT, CORE,
850                              type, LISTENER_AWAITING_BEGIN, win, NULL);
851             return TRUE;
852         }
853     }
854 
855     return FALSE;
856 }
857 
858 static void
TouchAddActiveGrabListener(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev,GrabPtr grab)859 TouchAddActiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
860                            InternalEvent *ev, GrabPtr grab)
861 {
862     if (!ti->emulate_pointer &&
863         (grab->grabtype == CORE || grab->grabtype == XI))
864         return;
865 
866     if (!ti->emulate_pointer &&
867         grab->grabtype == XI2 &&
868         !xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin))
869         return;
870 
871     TouchAddGrabListener(dev, ti, ev, grab);
872 }
873 
874 void
TouchSetupListeners(DeviceIntPtr dev,TouchPointInfoPtr ti,InternalEvent * ev)875 TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
876 {
877     int i;
878     SpritePtr sprite = &ti->sprite;
879     WindowPtr win;
880 
881     if (dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab)
882         TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab);
883 
884     /* We set up an active touch listener for existing touches, but not any
885      * passive grab or regular listeners. */
886     if (ev->any.type != ET_TouchBegin)
887         return;
888 
889     /* First, find all grabbing clients from the root window down
890      * to the deepest child window. */
891     for (i = 0; i < sprite->spriteTraceGood; i++) {
892         win = sprite->spriteTrace[i];
893         TouchAddPassiveGrabListener(dev, ti, win, ev);
894     }
895 
896     /* Find the first client with an applicable event selection,
897      * going from deepest child window back up to the root window. */
898     for (i = sprite->spriteTraceGood - 1; i >= 0; i--) {
899         Bool delivered;
900 
901         win = sprite->spriteTrace[i];
902         delivered = TouchAddRegularListener(dev, ti, win, ev);
903         if (delivered)
904             return;
905     }
906 }
907 
908 /**
909  * Remove the touch pointer grab from the device. Called from
910  * DeactivatePointerGrab()
911  */
912 void
TouchRemovePointerGrab(DeviceIntPtr dev)913 TouchRemovePointerGrab(DeviceIntPtr dev)
914 {
915     TouchPointInfoPtr ti;
916     GrabPtr grab;
917     DeviceEvent *ev;
918 
919     if (!dev->touch)
920         return;
921 
922     grab = dev->deviceGrab.grab;
923     if (!grab)
924         return;
925 
926     ev = dev->deviceGrab.sync.event;
927     if (!IsTouchEvent((InternalEvent *) ev))
928         return;
929 
930     ti = TouchFindByClientID(dev, ev->touchid);
931     if (!ti)
932         return;
933 
934     /* FIXME: missing a bit of code here... */
935 }
936 
937 /* As touch grabs don't turn into active grabs with their own resources, we
938  * need to walk all the touches and remove this grab from any delivery
939  * lists. */
940 void
TouchListenerGone(XID resource)941 TouchListenerGone(XID resource)
942 {
943     TouchPointInfoPtr ti;
944     DeviceIntPtr dev;
945     InternalEvent *events = InitEventList(GetMaximumEventsNum());
946     int i, j, k, nev;
947 
948     if (!events)
949         FatalError("TouchListenerGone: couldn't allocate events\n");
950 
951     for (dev = inputInfo.devices; dev; dev = dev->next) {
952         if (!dev->touch)
953             continue;
954 
955         for (i = 0; i < dev->touch->num_touches; i++) {
956             ti = &dev->touch->touches[i];
957             if (!ti->active)
958                 continue;
959 
960             for (j = 0; j < ti->num_listeners; j++) {
961                 if (CLIENT_BITS(ti->listeners[j].listener) != resource)
962                     continue;
963 
964                 nev = GetTouchOwnershipEvents(events, dev, ti, XIRejectTouch,
965                                               ti->listeners[j].listener, 0);
966                 for (k = 0; k < nev; k++)
967                     mieqProcessDeviceEvent(dev, events + k, NULL);
968 
969                 break;
970             }
971         }
972     }
973 
974     FreeEventList(events, GetMaximumEventsNum());
975 }
976 
977 int
TouchListenerAcceptReject(DeviceIntPtr dev,TouchPointInfoPtr ti,int listener,int mode)978 TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti, int listener,
979                           int mode)
980 {
981     InternalEvent *events;
982     int nev;
983     int i;
984 
985     BUG_RETURN_VAL(listener < 0, BadMatch);
986     BUG_RETURN_VAL(listener >= ti->num_listeners, BadMatch);
987 
988     if (listener > 0) {
989         if (mode == XIRejectTouch)
990             TouchRejected(dev, ti, ti->listeners[listener].listener, NULL);
991         else
992             ti->listeners[listener].state = LISTENER_EARLY_ACCEPT;
993 
994         return Success;
995     }
996 
997     events = InitEventList(GetMaximumEventsNum());
998     BUG_RETURN_VAL_MSG(!events, BadAlloc, "Failed to allocate touch ownership events\n");
999 
1000     nev = GetTouchOwnershipEvents(events, dev, ti, mode,
1001                                   ti->listeners[0].listener, 0);
1002     BUG_WARN_MSG(nev == 0, "Failed to get touch ownership events\n");
1003 
1004     for (i = 0; i < nev; i++)
1005         mieqProcessDeviceEvent(dev, events + i, NULL);
1006 
1007     FreeEventList(events, GetMaximumEventsNum());
1008 
1009     return nev ? Success : BadMatch;
1010 }
1011 
1012 int
TouchAcceptReject(ClientPtr client,DeviceIntPtr dev,int mode,uint32_t touchid,Window grab_window,XID * error)1013 TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
1014                   uint32_t touchid, Window grab_window, XID *error)
1015 {
1016     TouchPointInfoPtr ti;
1017     int i;
1018 
1019     if (!dev->touch) {
1020         *error = dev->id;
1021         return BadDevice;
1022     }
1023 
1024     ti = TouchFindByClientID(dev, touchid);
1025     if (!ti) {
1026         *error = touchid;
1027         return BadValue;
1028     }
1029 
1030     for (i = 0; i < ti->num_listeners; i++) {
1031         if (CLIENT_ID(ti->listeners[i].listener) == client->index &&
1032             ti->listeners[i].window->drawable.id == grab_window)
1033             break;
1034     }
1035     if (i == ti->num_listeners)
1036         return BadAccess;
1037 
1038     return TouchListenerAcceptReject(dev, ti, i, mode);
1039 }
1040 
1041 /**
1042  * End physically active touches for a device.
1043  */
1044 void
TouchEndPhysicallyActiveTouches(DeviceIntPtr dev)1045 TouchEndPhysicallyActiveTouches(DeviceIntPtr dev)
1046 {
1047     InternalEvent *eventlist = InitEventList(GetMaximumEventsNum());
1048     int i;
1049 
1050     input_lock();
1051     mieqProcessInputEvents();
1052     for (i = 0; i < dev->last.num_touches; i++) {
1053         DDXTouchPointInfoPtr ddxti = dev->last.touches + i;
1054 
1055         if (ddxti->active) {
1056             int j;
1057             int nevents = GetTouchEvents(eventlist, dev, ddxti->ddx_id,
1058                                          XI_TouchEnd, 0, NULL);
1059 
1060             for (j = 0; j < nevents; j++)
1061                 mieqProcessDeviceEvent(dev, eventlist + j, NULL);
1062         }
1063     }
1064     input_unlock();
1065 
1066     FreeEventList(eventlist, GetMaximumEventsNum());
1067 }
1068 
1069 /**
1070  * Generate and deliver a TouchEnd event.
1071  *
1072  * @param dev The device to deliver the event for.
1073  * @param ti The touch point record to deliver the event for.
1074  * @param flags Internal event flags. The called does not need to provide
1075  *        TOUCH_CLIENT_ID and TOUCH_POINTER_EMULATED, this function will ensure
1076  *        they are set appropriately.
1077  * @param resource The client resource to deliver to, or 0 for all clients.
1078  */
1079 void
TouchEmitTouchEnd(DeviceIntPtr dev,TouchPointInfoPtr ti,int flags,XID resource)1080 TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource)
1081 {
1082     InternalEvent event;
1083 
1084     /* We're not processing a touch end for a frozen device */
1085     if (dev->deviceGrab.sync.frozen)
1086         return;
1087 
1088     flags |= TOUCH_CLIENT_ID;
1089     if (ti->emulate_pointer)
1090         flags |= TOUCH_POINTER_EMULATED;
1091     TouchDeliverDeviceClassesChangedEvent(ti, GetTimeInMillis(), resource);
1092     GetDixTouchEnd(&event, dev, ti, flags);
1093     DeliverTouchEvents(dev, ti, &event, resource);
1094     if (ti->num_grabs == 0)
1095         UpdateDeviceState(dev, &event.device_event);
1096 }
1097 
1098 void
TouchAcceptAndEnd(DeviceIntPtr dev,int touchid)1099 TouchAcceptAndEnd(DeviceIntPtr dev, int touchid)
1100 {
1101     TouchPointInfoPtr ti = TouchFindByClientID(dev, touchid);
1102     if (!ti)
1103         return;
1104 
1105     TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
1106     if (ti->pending_finish)
1107         TouchEmitTouchEnd(dev, ti, 0, 0);
1108     if (ti->num_listeners <= 1)
1109         TouchEndTouch(dev, ti);
1110 }
1111