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