touch.c revision 1b5d61b8
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
75static Bool
76TouchResizeQueue(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 */
105DDXTouchPointInfoPtr
106TouchFindByDDXID(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 */
133DDXTouchPointInfoPtr
134TouchBeginDDXTouch(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
184void
185TouchEndDDXTouch(DeviceIntPtr dev, DDXTouchPointInfoPtr ti)
186{
187    TouchClassPtr t = dev->touch;
188
189    if (!t)
190        return;
191
192    ti->active = FALSE;
193}
194
195void
196TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch)
197{
198    memset(ddxtouch, 0, sizeof(*ddxtouch));
199    ddxtouch->valuators = valuator_mask_new(dev->valuator->numAxes);
200}
201
202Bool
203TouchInitTouchPoint(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
232void
233TouchFreeTouchPoint(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 */
263TouchPointInfoPtr
264TouchFindByClientID(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 */
289TouchPointInfoPtr
290TouchBeginTouch(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 */
339void
340TouchEndTouch(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 */
379Bool
380TouchEventHistoryAllocate(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
392void
393TouchEventHistoryFree(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 */
409void
410TouchEventHistoryPush(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
442void
443TouchEventHistoryReplay(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
474void
475TouchDeliverDeviceClassesChangedEvent(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
498Bool
499TouchBuildDependentSpriteTrace(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 */
540Bool
541TouchBuildSprite(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 */
585int
586TouchConvertToPointerEvent(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 */
636int
637TouchGetPointerEventType(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 */
661Bool
662TouchResourceIsOwner(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 */
670void
671TouchAddListener(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 */
702Bool
703TouchRemoveListener(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
731static void
732TouchAddGrabListener(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 */
758static void
759TouchAddPassiveGrabListener(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
773static Bool
774TouchAddRegularListener(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
858static void
859TouchAddActiveGrabListener(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
874void
875TouchSetupListeners(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 */
912void
913TouchRemovePointerGrab(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. */
940void
941TouchListenerGone(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
977int
978TouchListenerAcceptReject(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
1012int
1013TouchAcceptReject(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 */
1044void
1045TouchEndPhysicallyActiveTouches(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 */
1079void
1080TouchEmitTouchEnd(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
1098void
1099TouchAcceptAndEnd(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