135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2011 Collabra Ltd.
335c4bbdfSmrg * Copyright © 2011 Red Hat, Inc.
435c4bbdfSmrg *
535c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a
635c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
735c4bbdfSmrg * to deal in the Software without restriction, including without limitation
835c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
935c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the
1035c4bbdfSmrg * Software is furnished to do so, subject to the following conditions:
1135c4bbdfSmrg *
1235c4bbdfSmrg * The above copyright notice and this permission notice (including the next
1335c4bbdfSmrg * paragraph) shall be included in all copies or substantial portions of the
1435c4bbdfSmrg * Software.
1535c4bbdfSmrg *
1635c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1735c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1835c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1935c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2035c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2135c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2235c4bbdfSmrg * DEALINGS IN THE SOFTWARE.
2335c4bbdfSmrg *
2435c4bbdfSmrg * Author: Daniel Stone <daniel@fooishbar.org>
2535c4bbdfSmrg */
2635c4bbdfSmrg
2735c4bbdfSmrg#ifdef HAVE_DIX_CONFIG_H
2835c4bbdfSmrg#include <dix-config.h>
2935c4bbdfSmrg#endif
3035c4bbdfSmrg
3135c4bbdfSmrg#include "inputstr.h"
3235c4bbdfSmrg#include "scrnintstr.h"
3335c4bbdfSmrg#include "dixgrabs.h"
3435c4bbdfSmrg
3535c4bbdfSmrg#include "eventstr.h"
3635c4bbdfSmrg#include "exevents.h"
3735c4bbdfSmrg#include "exglobals.h"
3835c4bbdfSmrg#include "inpututils.h"
3935c4bbdfSmrg#include "eventconvert.h"
4035c4bbdfSmrg#include "windowstr.h"
4135c4bbdfSmrg#include "mi.h"
4235c4bbdfSmrg
4335c4bbdfSmrg#define TOUCH_HISTORY_SIZE 100
4435c4bbdfSmrg
45ed6184dfSmrgBool touchEmulatePointer = TRUE;
46ed6184dfSmrg
4735c4bbdfSmrg/**
4835c4bbdfSmrg * Some documentation about touch points:
49ed6184dfSmrg * The driver submits touch events with its own (unique) touch point ID.
5035c4bbdfSmrg * The driver may re-use those IDs, the DDX doesn't care. It just passes on
5135c4bbdfSmrg * the data to the DIX. In the server, the driver's ID is referred to as the
5235c4bbdfSmrg * DDX id anyway.
5335c4bbdfSmrg *
5435c4bbdfSmrg * On a TouchBegin, we create a DDXTouchPointInfo that contains the DDX id
5535c4bbdfSmrg * and the client ID that this touchpoint will have. The client ID is the
5635c4bbdfSmrg * one visible on the protocol.
5735c4bbdfSmrg *
5835c4bbdfSmrg * TouchUpdate and TouchEnd will only be processed if there is an active
5935c4bbdfSmrg * touchpoint with the same DDX id.
6035c4bbdfSmrg *
6135c4bbdfSmrg * The DDXTouchPointInfo struct is stored dev->last.touches. When the event
6235c4bbdfSmrg * being processed, it becomes a TouchPointInfo in dev->touch-touches which
6335c4bbdfSmrg * contains amongst other things the sprite trace and delivery information.
6435c4bbdfSmrg */
6535c4bbdfSmrg
6635c4bbdfSmrg/**
6735c4bbdfSmrg * Check which devices need a bigger touch event queue and grow their
68ed6184dfSmrg * last.touches by half its current size.
6935c4bbdfSmrg *
7035c4bbdfSmrg * @param client Always the serverClient
7135c4bbdfSmrg * @param closure Always NULL
7235c4bbdfSmrg *
7335c4bbdfSmrg * @return Always True. If we fail to grow we probably will topple over soon
7435c4bbdfSmrg * anyway and re-executing this won't help.
7535c4bbdfSmrg */
761b5d61b8Smrg
7735c4bbdfSmrgstatic Bool
781b5d61b8SmrgTouchResizeQueue(DeviceIntPtr dev)
7935c4bbdfSmrg{
801b5d61b8Smrg    DDXTouchPointInfoPtr tmp;
811b5d61b8Smrg    size_t size;
8235c4bbdfSmrg
831b5d61b8Smrg    /* Grow sufficiently so we don't need to do it often */
841b5d61b8Smrg    size = dev->last.num_touches + dev->last.num_touches / 2 + 1;
8535c4bbdfSmrg
861b5d61b8Smrg    tmp = reallocarray(dev->last.touches, size, sizeof(*dev->last.touches));
871b5d61b8Smrg    if (tmp) {
881b5d61b8Smrg        int j;
8935c4bbdfSmrg
901b5d61b8Smrg        dev->last.touches = tmp;
911b5d61b8Smrg        for (j = dev->last.num_touches; j < size; j++)
921b5d61b8Smrg            TouchInitDDXTouchPoint(dev, &dev->last.touches[j]);
931b5d61b8Smrg        dev->last.num_touches = size;
941b5d61b8Smrg        return TRUE;
9535c4bbdfSmrg    }
961b5d61b8Smrg    return FALSE;
9735c4bbdfSmrg}
9835c4bbdfSmrg
9935c4bbdfSmrg/**
10035c4bbdfSmrg * Given the DDX-facing ID (which is _not_ DeviceEvent::detail.touch), find the
10135c4bbdfSmrg * associated DDXTouchPointInfoRec.
10235c4bbdfSmrg *
10335c4bbdfSmrg * @param dev The device to create the touch point for
10435c4bbdfSmrg * @param ddx_id Touch id assigned by the driver/ddx
10535c4bbdfSmrg * @param create Create the touchpoint if it cannot be found
10635c4bbdfSmrg */
10735c4bbdfSmrgDDXTouchPointInfoPtr
10835c4bbdfSmrgTouchFindByDDXID(DeviceIntPtr dev, uint32_t ddx_id, Bool create)
10935c4bbdfSmrg{
11035c4bbdfSmrg    DDXTouchPointInfoPtr ti;
11135c4bbdfSmrg    int i;
11235c4bbdfSmrg
11335c4bbdfSmrg    if (!dev->touch)
11435c4bbdfSmrg        return NULL;
11535c4bbdfSmrg
11635c4bbdfSmrg    for (i = 0; i < dev->last.num_touches; i++) {
11735c4bbdfSmrg        ti = &dev->last.touches[i];
11835c4bbdfSmrg        if (ti->active && ti->ddx_id == ddx_id)
11935c4bbdfSmrg            return ti;
12035c4bbdfSmrg    }
12135c4bbdfSmrg
12235c4bbdfSmrg    return create ? TouchBeginDDXTouch(dev, ddx_id) : NULL;
12335c4bbdfSmrg}
12435c4bbdfSmrg
12535c4bbdfSmrg/**
12635c4bbdfSmrg * Given a unique DDX ID for a touchpoint, create a touchpoint record and
12735c4bbdfSmrg * return it.
12835c4bbdfSmrg *
12935c4bbdfSmrg * If no other touch points are active, mark new touchpoint for pointer
13035c4bbdfSmrg * emulation.
13135c4bbdfSmrg *
13235c4bbdfSmrg * Returns NULL on failure (i.e. if another touch with that ID is already active,
13335c4bbdfSmrg * allocation failure).
13435c4bbdfSmrg */
13535c4bbdfSmrgDDXTouchPointInfoPtr
13635c4bbdfSmrgTouchBeginDDXTouch(DeviceIntPtr dev, uint32_t ddx_id)
13735c4bbdfSmrg{
13835c4bbdfSmrg    static int next_client_id = 1;
13935c4bbdfSmrg    int i;
14035c4bbdfSmrg    TouchClassPtr t = dev->touch;
14135c4bbdfSmrg    DDXTouchPointInfoPtr ti = NULL;
14235c4bbdfSmrg    Bool emulate_pointer;
14335c4bbdfSmrg
14435c4bbdfSmrg    if (!t)
14535c4bbdfSmrg        return NULL;
14635c4bbdfSmrg
147ed6184dfSmrg    emulate_pointer = touchEmulatePointer && (t->mode == XIDirectTouch);
14835c4bbdfSmrg
14935c4bbdfSmrg    /* Look for another active touchpoint with the same DDX ID. DDX
15035c4bbdfSmrg     * touchpoints must be unique. */
15135c4bbdfSmrg    if (TouchFindByDDXID(dev, ddx_id, FALSE))
15235c4bbdfSmrg        return NULL;
15335c4bbdfSmrg
1541b5d61b8Smrg    for (;;) {
1551b5d61b8Smrg        for (i = 0; i < dev->last.num_touches; i++) {
1561b5d61b8Smrg            /* Only emulate pointer events on the first touch */
1571b5d61b8Smrg            if (dev->last.touches[i].active)
1581b5d61b8Smrg                emulate_pointer = FALSE;
1591b5d61b8Smrg            else if (!ti)           /* ti is now first non-active touch rec */
1601b5d61b8Smrg                ti = &dev->last.touches[i];
16135c4bbdfSmrg
1621b5d61b8Smrg            if (!emulate_pointer && ti)
1631b5d61b8Smrg                break;
1641b5d61b8Smrg        }
1651b5d61b8Smrg        if (ti)
1661b5d61b8Smrg            break;
1671b5d61b8Smrg        if (!TouchResizeQueue(dev))
16835c4bbdfSmrg            break;
16935c4bbdfSmrg    }
17035c4bbdfSmrg
17135c4bbdfSmrg    if (ti) {
17235c4bbdfSmrg        int client_id;
17335c4bbdfSmrg
17435c4bbdfSmrg        ti->active = TRUE;
17535c4bbdfSmrg        ti->ddx_id = ddx_id;
17635c4bbdfSmrg        client_id = next_client_id;
17735c4bbdfSmrg        next_client_id++;
17835c4bbdfSmrg        if (next_client_id == 0)
17935c4bbdfSmrg            next_client_id = 1;
18035c4bbdfSmrg        ti->client_id = client_id;
18135c4bbdfSmrg        ti->emulate_pointer = emulate_pointer;
18235c4bbdfSmrg    }
1831b5d61b8Smrg    return ti;
18435c4bbdfSmrg}
18535c4bbdfSmrg
18635c4bbdfSmrgvoid
18735c4bbdfSmrgTouchEndDDXTouch(DeviceIntPtr dev, DDXTouchPointInfoPtr ti)
18835c4bbdfSmrg{
18935c4bbdfSmrg    TouchClassPtr t = dev->touch;
19035c4bbdfSmrg
19135c4bbdfSmrg    if (!t)
19235c4bbdfSmrg        return;
19335c4bbdfSmrg
19435c4bbdfSmrg    ti->active = FALSE;
19535c4bbdfSmrg}
19635c4bbdfSmrg
19735c4bbdfSmrgvoid
19835c4bbdfSmrgTouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch)
19935c4bbdfSmrg{
20035c4bbdfSmrg    memset(ddxtouch, 0, sizeof(*ddxtouch));
20135c4bbdfSmrg    ddxtouch->valuators = valuator_mask_new(dev->valuator->numAxes);
20235c4bbdfSmrg}
20335c4bbdfSmrg
20435c4bbdfSmrgBool
20535c4bbdfSmrgTouchInitTouchPoint(TouchClassPtr t, ValuatorClassPtr v, int index)
20635c4bbdfSmrg{
20735c4bbdfSmrg    TouchPointInfoPtr ti;
20835c4bbdfSmrg
20935c4bbdfSmrg    if (index >= t->num_touches)
21035c4bbdfSmrg        return FALSE;
21135c4bbdfSmrg    ti = &t->touches[index];
21235c4bbdfSmrg
21335c4bbdfSmrg    memset(ti, 0, sizeof(*ti));
21435c4bbdfSmrg
21535c4bbdfSmrg    ti->valuators = valuator_mask_new(v->numAxes);
21635c4bbdfSmrg    if (!ti->valuators)
21735c4bbdfSmrg        return FALSE;
21835c4bbdfSmrg
21935c4bbdfSmrg    ti->sprite.spriteTrace = calloc(32, sizeof(*ti->sprite.spriteTrace));
22035c4bbdfSmrg    if (!ti->sprite.spriteTrace) {
22135c4bbdfSmrg        valuator_mask_free(&ti->valuators);
22235c4bbdfSmrg        return FALSE;
22335c4bbdfSmrg    }
22435c4bbdfSmrg    ti->sprite.spriteTraceSize = 32;
22535c4bbdfSmrg    ti->sprite.spriteTrace[0] = screenInfo.screens[0]->root;
22635c4bbdfSmrg    ti->sprite.hot.pScreen = screenInfo.screens[0];
22735c4bbdfSmrg    ti->sprite.hotPhys.pScreen = screenInfo.screens[0];
22835c4bbdfSmrg
22935c4bbdfSmrg    ti->client_id = -1;
23035c4bbdfSmrg
23135c4bbdfSmrg    return TRUE;
23235c4bbdfSmrg}
23335c4bbdfSmrg
23435c4bbdfSmrgvoid
23535c4bbdfSmrgTouchFreeTouchPoint(DeviceIntPtr device, int index)
23635c4bbdfSmrg{
23735c4bbdfSmrg    TouchPointInfoPtr ti;
23835c4bbdfSmrg    int i;
23935c4bbdfSmrg
24035c4bbdfSmrg    if (!device->touch || index >= device->touch->num_touches)
24135c4bbdfSmrg        return;
24235c4bbdfSmrg    ti = &device->touch->touches[index];
24335c4bbdfSmrg
24435c4bbdfSmrg    if (ti->active)
24535c4bbdfSmrg        TouchEndTouch(device, ti);
24635c4bbdfSmrg
24735c4bbdfSmrg    for (i = 0; i < ti->num_listeners; i++)
24835c4bbdfSmrg        TouchRemoveListener(ti, ti->listeners[0].listener);
24935c4bbdfSmrg
25035c4bbdfSmrg    valuator_mask_free(&ti->valuators);
25135c4bbdfSmrg    free(ti->sprite.spriteTrace);
25235c4bbdfSmrg    ti->sprite.spriteTrace = NULL;
25335c4bbdfSmrg    free(ti->listeners);
25435c4bbdfSmrg    ti->listeners = NULL;
25535c4bbdfSmrg    free(ti->history);
25635c4bbdfSmrg    ti->history = NULL;
25735c4bbdfSmrg    ti->history_size = 0;
25835c4bbdfSmrg    ti->history_elements = 0;
25935c4bbdfSmrg}
26035c4bbdfSmrg
26135c4bbdfSmrg/**
26235c4bbdfSmrg * Given a client-facing ID (e.g. DeviceEvent::detail.touch), find the
26335c4bbdfSmrg * associated TouchPointInfoRec.
26435c4bbdfSmrg */
26535c4bbdfSmrgTouchPointInfoPtr
26635c4bbdfSmrgTouchFindByClientID(DeviceIntPtr dev, uint32_t client_id)
26735c4bbdfSmrg{
26835c4bbdfSmrg    TouchClassPtr t = dev->touch;
26935c4bbdfSmrg    TouchPointInfoPtr ti;
27035c4bbdfSmrg    int i;
27135c4bbdfSmrg
27235c4bbdfSmrg    if (!t)
27335c4bbdfSmrg        return NULL;
27435c4bbdfSmrg
27535c4bbdfSmrg    for (i = 0; i < t->num_touches; i++) {
27635c4bbdfSmrg        ti = &t->touches[i];
27735c4bbdfSmrg        if (ti->active && ti->client_id == client_id)
27835c4bbdfSmrg            return ti;
27935c4bbdfSmrg    }
28035c4bbdfSmrg
28135c4bbdfSmrg    return NULL;
28235c4bbdfSmrg}
28335c4bbdfSmrg
28435c4bbdfSmrg/**
28535c4bbdfSmrg * Given a unique ID for a touchpoint, create a touchpoint record in the
28635c4bbdfSmrg * server.
28735c4bbdfSmrg *
28835c4bbdfSmrg * Returns NULL on failure (i.e. if another touch with that ID is already active,
28935c4bbdfSmrg * allocation failure).
29035c4bbdfSmrg */
29135c4bbdfSmrgTouchPointInfoPtr
29235c4bbdfSmrgTouchBeginTouch(DeviceIntPtr dev, int sourceid, uint32_t touchid,
29335c4bbdfSmrg                Bool emulate_pointer)
29435c4bbdfSmrg{
29535c4bbdfSmrg    int i;
29635c4bbdfSmrg    TouchClassPtr t = dev->touch;
29735c4bbdfSmrg    TouchPointInfoPtr ti;
29835c4bbdfSmrg    void *tmp;
29935c4bbdfSmrg
30035c4bbdfSmrg    if (!t)
30135c4bbdfSmrg        return NULL;
30235c4bbdfSmrg
30335c4bbdfSmrg    /* Look for another active touchpoint with the same client ID.  It's
30435c4bbdfSmrg     * technically legitimate for a touchpoint to still exist with the same
30535c4bbdfSmrg     * ID but only once the 32 bits wrap over and you've used up 4 billion
30635c4bbdfSmrg     * touch ids without lifting that one finger off once. In which case
30735c4bbdfSmrg     * you deserve a medal or something, but not error handling code. */
30835c4bbdfSmrg    if (TouchFindByClientID(dev, touchid))
30935c4bbdfSmrg        return NULL;
31035c4bbdfSmrg
31135c4bbdfSmrg try_find_touch:
31235c4bbdfSmrg    for (i = 0; i < t->num_touches; i++) {
31335c4bbdfSmrg        ti = &t->touches[i];
31435c4bbdfSmrg        if (!ti->active) {
31535c4bbdfSmrg            ti->active = TRUE;
31635c4bbdfSmrg            ti->client_id = touchid;
31735c4bbdfSmrg            ti->sourceid = sourceid;
31835c4bbdfSmrg            ti->emulate_pointer = emulate_pointer;
31935c4bbdfSmrg            return ti;
32035c4bbdfSmrg        }
32135c4bbdfSmrg    }
32235c4bbdfSmrg
32335c4bbdfSmrg    /* If we get here, then we've run out of touches: enlarge dev->touch and
32435c4bbdfSmrg     * try again. */
32535c4bbdfSmrg    tmp = reallocarray(t->touches, t->num_touches + 1, sizeof(*ti));
32635c4bbdfSmrg    if (tmp) {
32735c4bbdfSmrg        t->touches = tmp;
32835c4bbdfSmrg        t->num_touches++;
32935c4bbdfSmrg        if (TouchInitTouchPoint(t, dev->valuator, t->num_touches - 1))
33035c4bbdfSmrg            goto try_find_touch;
33135c4bbdfSmrg    }
33235c4bbdfSmrg
33335c4bbdfSmrg    return NULL;
33435c4bbdfSmrg}
33535c4bbdfSmrg
33635c4bbdfSmrg/**
33735c4bbdfSmrg * Releases a touchpoint for use: this must only be called after all events
33835c4bbdfSmrg * related to that touchpoint have been sent and finalised.  Called from
33935c4bbdfSmrg * ProcessTouchEvent and friends.  Not by you.
34035c4bbdfSmrg */
34135c4bbdfSmrgvoid
34235c4bbdfSmrgTouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
34335c4bbdfSmrg{
34435c4bbdfSmrg    int i;
34535c4bbdfSmrg
34635c4bbdfSmrg    if (ti->emulate_pointer) {
34735c4bbdfSmrg        GrabPtr grab;
34835c4bbdfSmrg
34935c4bbdfSmrg        if ((grab = dev->deviceGrab.grab)) {
35035c4bbdfSmrg            if (dev->deviceGrab.fromPassiveGrab &&
35135c4bbdfSmrg                !dev->button->buttonsDown &&
35235c4bbdfSmrg                !dev->touch->buttonsDown && GrabIsPointerGrab(grab))
35335c4bbdfSmrg                (*dev->deviceGrab.DeactivateGrab) (dev);
35435c4bbdfSmrg        }
35535c4bbdfSmrg    }
35635c4bbdfSmrg
35735c4bbdfSmrg    for (i = 0; i < ti->num_listeners; i++)
35835c4bbdfSmrg        TouchRemoveListener(ti, ti->listeners[0].listener);
35935c4bbdfSmrg
36035c4bbdfSmrg    ti->active = FALSE;
36135c4bbdfSmrg    ti->pending_finish = FALSE;
36235c4bbdfSmrg    ti->sprite.spriteTraceGood = 0;
36335c4bbdfSmrg    free(ti->listeners);
36435c4bbdfSmrg    ti->listeners = NULL;
36535c4bbdfSmrg    ti->num_listeners = 0;
36635c4bbdfSmrg    ti->num_grabs = 0;
36735c4bbdfSmrg    ti->client_id = 0;
36835c4bbdfSmrg
36935c4bbdfSmrg    TouchEventHistoryFree(ti);
37035c4bbdfSmrg
37135c4bbdfSmrg    valuator_mask_zero(ti->valuators);
37235c4bbdfSmrg}
37335c4bbdfSmrg
37435c4bbdfSmrg/**
37535c4bbdfSmrg * Allocate the event history for this touch pointer. Calling this on a
37635c4bbdfSmrg * touchpoint that already has an event history does nothing but counts as
37735c4bbdfSmrg * as success.
37835c4bbdfSmrg *
37935c4bbdfSmrg * @return TRUE on success, FALSE on allocation errors
38035c4bbdfSmrg */
38135c4bbdfSmrgBool
38235c4bbdfSmrgTouchEventHistoryAllocate(TouchPointInfoPtr ti)
38335c4bbdfSmrg{
38435c4bbdfSmrg    if (ti->history)
38535c4bbdfSmrg        return TRUE;
38635c4bbdfSmrg
38735c4bbdfSmrg    ti->history = calloc(TOUCH_HISTORY_SIZE, sizeof(*ti->history));
38835c4bbdfSmrg    ti->history_elements = 0;
38935c4bbdfSmrg    if (ti->history)
39035c4bbdfSmrg        ti->history_size = TOUCH_HISTORY_SIZE;
39135c4bbdfSmrg    return ti->history != NULL;
39235c4bbdfSmrg}
39335c4bbdfSmrg
39435c4bbdfSmrgvoid
39535c4bbdfSmrgTouchEventHistoryFree(TouchPointInfoPtr ti)
39635c4bbdfSmrg{
39735c4bbdfSmrg    free(ti->history);
39835c4bbdfSmrg    ti->history = NULL;
39935c4bbdfSmrg    ti->history_size = 0;
40035c4bbdfSmrg    ti->history_elements = 0;
40135c4bbdfSmrg}
40235c4bbdfSmrg
40335c4bbdfSmrg/**
40435c4bbdfSmrg * Store the given event on the event history (if one exists)
40535c4bbdfSmrg * A touch event history consists of one TouchBegin and several TouchUpdate
40635c4bbdfSmrg * events (if applicable) but no TouchEnd event.
40735c4bbdfSmrg * If more than one TouchBegin is pushed onto the stack, the push is
40835c4bbdfSmrg * ignored, calling this function multiple times for the TouchBegin is
40935c4bbdfSmrg * valid.
41035c4bbdfSmrg */
41135c4bbdfSmrgvoid
41235c4bbdfSmrgTouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev)
41335c4bbdfSmrg{
41435c4bbdfSmrg    if (!ti->history)
41535c4bbdfSmrg        return;
41635c4bbdfSmrg
41735c4bbdfSmrg    switch (ev->type) {
41835c4bbdfSmrg    case ET_TouchBegin:
41935c4bbdfSmrg        /* don't store the same touchbegin twice */
42035c4bbdfSmrg        if (ti->history_elements > 0)
42135c4bbdfSmrg            return;
42235c4bbdfSmrg        break;
42335c4bbdfSmrg    case ET_TouchUpdate:
42435c4bbdfSmrg        break;
42535c4bbdfSmrg    case ET_TouchEnd:
42635c4bbdfSmrg        return;                 /* no TouchEnd events in the history */
42735c4bbdfSmrg    default:
42835c4bbdfSmrg        return;
42935c4bbdfSmrg    }
43035c4bbdfSmrg
43135c4bbdfSmrg    /* We only store real events in the history */
43235c4bbdfSmrg    if (ev->flags & (TOUCH_CLIENT_ID | TOUCH_REPLAYING))
43335c4bbdfSmrg        return;
43435c4bbdfSmrg
43535c4bbdfSmrg    ti->history[ti->history_elements++] = *ev;
43635c4bbdfSmrg    /* FIXME: proper overflow fixes */
43735c4bbdfSmrg    if (ti->history_elements > ti->history_size - 1) {
43835c4bbdfSmrg        ti->history_elements = ti->history_size - 1;
43935c4bbdfSmrg        DebugF("source device %d: history size %zu overflowing for touch %u\n",
44035c4bbdfSmrg               ti->sourceid, ti->history_size, ti->client_id);
44135c4bbdfSmrg    }
44235c4bbdfSmrg}
44335c4bbdfSmrg
44435c4bbdfSmrgvoid
44535c4bbdfSmrgTouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
44635c4bbdfSmrg{
44735c4bbdfSmrg    int i;
44835c4bbdfSmrg
44935c4bbdfSmrg    if (!ti->history)
45035c4bbdfSmrg        return;
45135c4bbdfSmrg
452ed6184dfSmrg    DeliverDeviceClassesChangedEvent(ti->sourceid, ti->history[0].time);
45335c4bbdfSmrg
45435c4bbdfSmrg    for (i = 0; i < ti->history_elements; i++) {
45535c4bbdfSmrg        DeviceEvent *ev = &ti->history[i];
45635c4bbdfSmrg
45735c4bbdfSmrg        ev->flags |= TOUCH_REPLAYING;
45835c4bbdfSmrg        ev->resource = resource;
45935c4bbdfSmrg        /* FIXME:
46035c4bbdfSmrg           We're replaying ti->history which contains the TouchBegin +
46135c4bbdfSmrg           all TouchUpdates for ti. This needs to be passed on to the next
46235c4bbdfSmrg           listener. If that is a touch listener, everything is dandy.
46335c4bbdfSmrg           If the TouchBegin however triggers a sync passive grab, the
46435c4bbdfSmrg           TouchUpdate events must be sent to EnqueueEvent so the events end
46535c4bbdfSmrg           up in syncEvents.pending to be forwarded correctly in a
46635c4bbdfSmrg           subsequent ComputeFreeze().
46735c4bbdfSmrg
46835c4bbdfSmrg           However, if we just send them to EnqueueEvent the sync'ing device
46935c4bbdfSmrg           prevents handling of touch events for ownership listeners who
47035c4bbdfSmrg           want the events right here, right now.
47135c4bbdfSmrg         */
47235c4bbdfSmrg        dev->public.processInputProc((InternalEvent*)ev, dev);
47335c4bbdfSmrg    }
47435c4bbdfSmrg}
47535c4bbdfSmrg
47635c4bbdfSmrgBool
47735c4bbdfSmrgTouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite)
47835c4bbdfSmrg{
47935c4bbdfSmrg    int i;
48035c4bbdfSmrg    TouchClassPtr t = dev->touch;
48135c4bbdfSmrg    SpritePtr srcsprite;
48235c4bbdfSmrg
48335c4bbdfSmrg    /* All touches should have the same sprite trace, so find and reuse an
48435c4bbdfSmrg     * existing touch's sprite if possible, else use the device's sprite. */
48535c4bbdfSmrg    for (i = 0; i < t->num_touches; i++)
48635c4bbdfSmrg        if (!t->touches[i].pending_finish &&
48735c4bbdfSmrg            t->touches[i].sprite.spriteTraceGood > 0)
48835c4bbdfSmrg            break;
48935c4bbdfSmrg    if (i < t->num_touches)
49035c4bbdfSmrg        srcsprite = &t->touches[i].sprite;
49135c4bbdfSmrg    else if (dev->spriteInfo->sprite)
49235c4bbdfSmrg        srcsprite = dev->spriteInfo->sprite;
49335c4bbdfSmrg    else
49435c4bbdfSmrg        return FALSE;
49535c4bbdfSmrg
496ed6184dfSmrg    return CopySprite(srcsprite, sprite);
49735c4bbdfSmrg}
49835c4bbdfSmrg
49935c4bbdfSmrg/**
50035c4bbdfSmrg * Ensure a window trace is present in ti->sprite, constructing one for
50135c4bbdfSmrg * TouchBegin events.
50235c4bbdfSmrg */
50335c4bbdfSmrgBool
50435c4bbdfSmrgTouchBuildSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
50535c4bbdfSmrg                 InternalEvent *ev)
50635c4bbdfSmrg{
50735c4bbdfSmrg    TouchClassPtr t = sourcedev->touch;
50835c4bbdfSmrg    SpritePtr sprite = &ti->sprite;
50935c4bbdfSmrg
51035c4bbdfSmrg    if (t->mode == XIDirectTouch) {
51135c4bbdfSmrg        /* Focus immediately under the touchpoint in direct touch mode.
51235c4bbdfSmrg         * XXX: Do we need to handle crossing screens here? */
51335c4bbdfSmrg        sprite->spriteTrace[0] =
51435c4bbdfSmrg            sourcedev->spriteInfo->sprite->hotPhys.pScreen->root;
51535c4bbdfSmrg        XYToWindow(sprite, ev->device_event.root_x, ev->device_event.root_y);
51635c4bbdfSmrg    }
51735c4bbdfSmrg    else if (!TouchBuildDependentSpriteTrace(sourcedev, sprite))
51835c4bbdfSmrg        return FALSE;
51935c4bbdfSmrg
52035c4bbdfSmrg    if (sprite->spriteTraceGood <= 0)
52135c4bbdfSmrg        return FALSE;
52235c4bbdfSmrg
52335c4bbdfSmrg    /* Mark which grabs/event selections we're delivering to: max one grab per
52435c4bbdfSmrg     * window plus the bottom-most event selection, plus any active grab. */
52535c4bbdfSmrg    ti->listeners = calloc(sprite->spriteTraceGood + 2, sizeof(*ti->listeners));
52635c4bbdfSmrg    if (!ti->listeners) {
52735c4bbdfSmrg        sprite->spriteTraceGood = 0;
52835c4bbdfSmrg        return FALSE;
52935c4bbdfSmrg    }
53035c4bbdfSmrg    ti->num_listeners = 0;
53135c4bbdfSmrg
53235c4bbdfSmrg    return TRUE;
53335c4bbdfSmrg}
53435c4bbdfSmrg
53535c4bbdfSmrg/**
53635c4bbdfSmrg * Copy the touch event into the pointer_event, switching the required
53735c4bbdfSmrg * fields to make it a correct pointer event.
53835c4bbdfSmrg *
53935c4bbdfSmrg * @param event The original touch event
54035c4bbdfSmrg * @param[in] motion_event The respective motion event
54135c4bbdfSmrg * @param[in] button_event The respective button event (if any)
54235c4bbdfSmrg *
54335c4bbdfSmrg * @returns The number of converted events.
544ed6184dfSmrg * @retval 0 An error occurred
54535c4bbdfSmrg * @retval 1 only the motion event is valid
54635c4bbdfSmrg * @retval 2 motion and button event are valid
54735c4bbdfSmrg */
54835c4bbdfSmrgint
54935c4bbdfSmrgTouchConvertToPointerEvent(const InternalEvent *event,
55035c4bbdfSmrg                           InternalEvent *motion_event,
55135c4bbdfSmrg                           InternalEvent *button_event)
55235c4bbdfSmrg{
55335c4bbdfSmrg    int ptrtype;
55435c4bbdfSmrg    int nevents = 0;
55535c4bbdfSmrg
55635c4bbdfSmrg    BUG_RETURN_VAL(!event, 0);
55735c4bbdfSmrg    BUG_RETURN_VAL(!motion_event, 0);
55835c4bbdfSmrg
55935c4bbdfSmrg    switch (event->any.type) {
56035c4bbdfSmrg    case ET_TouchUpdate:
56135c4bbdfSmrg        nevents = 1;
56235c4bbdfSmrg        break;
56335c4bbdfSmrg    case ET_TouchBegin:
56435c4bbdfSmrg        nevents = 2;            /* motion + press */
56535c4bbdfSmrg        ptrtype = ET_ButtonPress;
56635c4bbdfSmrg        break;
56735c4bbdfSmrg    case ET_TouchEnd:
56835c4bbdfSmrg        nevents = 2;            /* motion + release */
56935c4bbdfSmrg        ptrtype = ET_ButtonRelease;
57035c4bbdfSmrg        break;
57135c4bbdfSmrg    default:
57235c4bbdfSmrg        BUG_WARN_MSG(1, "Invalid event type %d\n", event->any.type);
57335c4bbdfSmrg        return 0;
57435c4bbdfSmrg    }
57535c4bbdfSmrg
57635c4bbdfSmrg    BUG_WARN_MSG(!(event->device_event.flags & TOUCH_POINTER_EMULATED),
57735c4bbdfSmrg                 "Non-emulating touch event\n");
57835c4bbdfSmrg
57935c4bbdfSmrg    motion_event->device_event = event->device_event;
58035c4bbdfSmrg    motion_event->any.type = ET_Motion;
58135c4bbdfSmrg    motion_event->device_event.detail.button = 0;
58235c4bbdfSmrg    motion_event->device_event.flags = XIPointerEmulated;
58335c4bbdfSmrg
58435c4bbdfSmrg    if (nevents > 1) {
58535c4bbdfSmrg        BUG_RETURN_VAL(!button_event, 0);
58635c4bbdfSmrg        button_event->device_event = event->device_event;
58735c4bbdfSmrg        button_event->any.type = ptrtype;
58835c4bbdfSmrg        button_event->device_event.flags = XIPointerEmulated;
58935c4bbdfSmrg        /* detail is already correct */
59035c4bbdfSmrg    }
59135c4bbdfSmrg
59235c4bbdfSmrg    return nevents;
59335c4bbdfSmrg}
59435c4bbdfSmrg
59535c4bbdfSmrg/**
59635c4bbdfSmrg * Return the corresponding pointer emulation internal event type for the given
59735c4bbdfSmrg * touch event or 0 if no such event type exists.
59835c4bbdfSmrg */
59935c4bbdfSmrgint
60035c4bbdfSmrgTouchGetPointerEventType(const InternalEvent *event)
60135c4bbdfSmrg{
60235c4bbdfSmrg    int type = 0;
60335c4bbdfSmrg
60435c4bbdfSmrg    switch (event->any.type) {
60535c4bbdfSmrg    case ET_TouchBegin:
60635c4bbdfSmrg        type = ET_ButtonPress;
60735c4bbdfSmrg        break;
60835c4bbdfSmrg    case ET_TouchUpdate:
60935c4bbdfSmrg        type = ET_Motion;
61035c4bbdfSmrg        break;
61135c4bbdfSmrg    case ET_TouchEnd:
61235c4bbdfSmrg        type = ET_ButtonRelease;
61335c4bbdfSmrg        break;
61435c4bbdfSmrg    default:
61535c4bbdfSmrg        break;
61635c4bbdfSmrg    }
61735c4bbdfSmrg    return type;
61835c4bbdfSmrg}
61935c4bbdfSmrg
62035c4bbdfSmrg/**
62135c4bbdfSmrg * @returns TRUE if the specified grab or selection is the current owner of
62235c4bbdfSmrg * the touch sequence.
62335c4bbdfSmrg */
62435c4bbdfSmrgBool
62535c4bbdfSmrgTouchResourceIsOwner(TouchPointInfoPtr ti, XID resource)
62635c4bbdfSmrg{
62735c4bbdfSmrg    return (ti->listeners[0].listener == resource);
62835c4bbdfSmrg}
62935c4bbdfSmrg
63035c4bbdfSmrg/**
63135c4bbdfSmrg * Add the resource to this touch's listeners.
63235c4bbdfSmrg */
63335c4bbdfSmrgvoid
63435c4bbdfSmrgTouchAddListener(TouchPointInfoPtr ti, XID resource, int resource_type,
63535c4bbdfSmrg                 enum InputLevel level, enum TouchListenerType type,
63635c4bbdfSmrg                 enum TouchListenerState state, WindowPtr window,
63735c4bbdfSmrg                 const GrabPtr grab)
63835c4bbdfSmrg{
63935c4bbdfSmrg    GrabPtr g = NULL;
64035c4bbdfSmrg
64135c4bbdfSmrg    /* We need a copy of the grab, not the grab itself since that may be
64235c4bbdfSmrg     * deleted by a UngrabButton request and leaves us with a dangling
64335c4bbdfSmrg     * pointer */
64435c4bbdfSmrg    if (grab)
64535c4bbdfSmrg        g = AllocGrab(grab);
64635c4bbdfSmrg
64735c4bbdfSmrg    ti->listeners[ti->num_listeners].listener = resource;
64835c4bbdfSmrg    ti->listeners[ti->num_listeners].resource_type = resource_type;
64935c4bbdfSmrg    ti->listeners[ti->num_listeners].level = level;
65035c4bbdfSmrg    ti->listeners[ti->num_listeners].state = state;
65135c4bbdfSmrg    ti->listeners[ti->num_listeners].type = type;
65235c4bbdfSmrg    ti->listeners[ti->num_listeners].window = window;
65335c4bbdfSmrg    ti->listeners[ti->num_listeners].grab = g;
65435c4bbdfSmrg    if (grab)
65535c4bbdfSmrg        ti->num_grabs++;
65635c4bbdfSmrg    ti->num_listeners++;
65735c4bbdfSmrg}
65835c4bbdfSmrg
65935c4bbdfSmrg/**
66035c4bbdfSmrg * Remove the resource from this touch's listeners.
66135c4bbdfSmrg *
66235c4bbdfSmrg * @return TRUE if the resource was removed, FALSE if the resource was not
66335c4bbdfSmrg * in the list
66435c4bbdfSmrg */
66535c4bbdfSmrgBool
66635c4bbdfSmrgTouchRemoveListener(TouchPointInfoPtr ti, XID resource)
66735c4bbdfSmrg{
66835c4bbdfSmrg    int i;
66935c4bbdfSmrg
67035c4bbdfSmrg    for (i = 0; i < ti->num_listeners; i++) {
67135c4bbdfSmrg        int j;
67235c4bbdfSmrg        TouchListener *listener = &ti->listeners[i];
67335c4bbdfSmrg
67435c4bbdfSmrg        if (listener->listener != resource)
67535c4bbdfSmrg            continue;
67635c4bbdfSmrg
67735c4bbdfSmrg        if (listener->grab) {
67835c4bbdfSmrg            FreeGrab(listener->grab);
67935c4bbdfSmrg            listener->grab = NULL;
68035c4bbdfSmrg            ti->num_grabs--;
68135c4bbdfSmrg        }
68235c4bbdfSmrg
68335c4bbdfSmrg        for (j = i; j < ti->num_listeners - 1; j++)
68435c4bbdfSmrg            ti->listeners[j] = ti->listeners[j + 1];
68535c4bbdfSmrg        ti->num_listeners--;
68635c4bbdfSmrg        ti->listeners[ti->num_listeners].listener = 0;
687ed6184dfSmrg        ti->listeners[ti->num_listeners].state = TOUCH_LISTENER_AWAITING_BEGIN;
68835c4bbdfSmrg
68935c4bbdfSmrg        return TRUE;
69035c4bbdfSmrg    }
69135c4bbdfSmrg    return FALSE;
69235c4bbdfSmrg}
69335c4bbdfSmrg
69435c4bbdfSmrgstatic void
69535c4bbdfSmrgTouchAddGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
69635c4bbdfSmrg                     InternalEvent *ev, GrabPtr grab)
69735c4bbdfSmrg{
698ed6184dfSmrg    enum TouchListenerType type = TOUCH_LISTENER_GRAB;
69935c4bbdfSmrg
70035c4bbdfSmrg    /* FIXME: owner_events */
70135c4bbdfSmrg
70235c4bbdfSmrg    if (grab->grabtype == XI2) {
70335c4bbdfSmrg        if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchOwnership))
70435c4bbdfSmrg            TouchEventHistoryAllocate(ti);
70535c4bbdfSmrg        if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin))
706ed6184dfSmrg            type = TOUCH_LISTENER_POINTER_GRAB;
70735c4bbdfSmrg    }
70835c4bbdfSmrg    else if (grab->grabtype == XI || grab->grabtype == CORE) {
70935c4bbdfSmrg        TouchEventHistoryAllocate(ti);
710ed6184dfSmrg        type = TOUCH_LISTENER_POINTER_GRAB;
71135c4bbdfSmrg    }
71235c4bbdfSmrg
71335c4bbdfSmrg    /* grab listeners are always RT_NONE since we keep the grab pointer */
71435c4bbdfSmrg    TouchAddListener(ti, grab->resource, RT_NONE, grab->grabtype,
715ed6184dfSmrg                     type, TOUCH_LISTENER_AWAITING_BEGIN, grab->window, grab);
71635c4bbdfSmrg}
71735c4bbdfSmrg
71835c4bbdfSmrg/**
71935c4bbdfSmrg * Add one listener if there is a grab on the given window.
72035c4bbdfSmrg */
72135c4bbdfSmrgstatic void
72235c4bbdfSmrgTouchAddPassiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
72335c4bbdfSmrg                            WindowPtr win, InternalEvent *ev)
72435c4bbdfSmrg{
72535c4bbdfSmrg    GrabPtr grab;
72635c4bbdfSmrg    Bool check_core = IsMaster(dev) && ti->emulate_pointer;
72735c4bbdfSmrg
72835c4bbdfSmrg    /* FIXME: make CheckPassiveGrabsOnWindow only trigger on TouchBegin */
72935c4bbdfSmrg    grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core, FALSE);
73035c4bbdfSmrg    if (!grab)
73135c4bbdfSmrg        return;
73235c4bbdfSmrg
73335c4bbdfSmrg    TouchAddGrabListener(dev, ti, ev, grab);
73435c4bbdfSmrg}
73535c4bbdfSmrg
73635c4bbdfSmrgstatic Bool
73735c4bbdfSmrgTouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
73835c4bbdfSmrg                        WindowPtr win, InternalEvent *ev)
73935c4bbdfSmrg{
74035c4bbdfSmrg    InputClients *iclients = NULL;
74135c4bbdfSmrg    OtherInputMasks *inputMasks = NULL;
74235c4bbdfSmrg    uint16_t evtype = 0;        /* may be event type or emulated event type */
743ed6184dfSmrg    enum TouchListenerType type = TOUCH_LISTENER_REGULAR;
74435c4bbdfSmrg    int mask;
74535c4bbdfSmrg
74635c4bbdfSmrg    evtype = GetXI2Type(ev->any.type);
74735c4bbdfSmrg    mask = EventIsDeliverable(dev, ev->any.type, win);
74835c4bbdfSmrg    if (!mask && !ti->emulate_pointer)
74935c4bbdfSmrg        return FALSE;
75035c4bbdfSmrg    else if (!mask) {           /* now try for pointer event */
75135c4bbdfSmrg        mask = EventIsDeliverable(dev, TouchGetPointerEventType(ev), win);
75235c4bbdfSmrg        if (mask) {
75335c4bbdfSmrg            evtype = GetXI2Type(TouchGetPointerEventType(ev));
754ed6184dfSmrg            type = TOUCH_LISTENER_POINTER_REGULAR;
75535c4bbdfSmrg        }
75635c4bbdfSmrg    }
75735c4bbdfSmrg    if (!mask)
75835c4bbdfSmrg        return FALSE;
75935c4bbdfSmrg
76035c4bbdfSmrg    inputMasks = wOtherInputMasks(win);
76135c4bbdfSmrg
76235c4bbdfSmrg    if (mask & EVENT_XI2_MASK) {
76335c4bbdfSmrg        nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
76435c4bbdfSmrg            if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
76535c4bbdfSmrg                continue;
76635c4bbdfSmrg
76735c4bbdfSmrg            if (!xi2mask_isset(iclients->xi2mask, dev, XI_TouchOwnership))
76835c4bbdfSmrg                TouchEventHistoryAllocate(ti);
76935c4bbdfSmrg
77035c4bbdfSmrg            TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI2,
771ed6184dfSmrg                             type, TOUCH_LISTENER_AWAITING_BEGIN, win, NULL);
77235c4bbdfSmrg            return TRUE;
77335c4bbdfSmrg        }
77435c4bbdfSmrg    }
77535c4bbdfSmrg
77635c4bbdfSmrg    if (mask & EVENT_XI1_MASK) {
77735c4bbdfSmrg        int xitype = GetXIType(TouchGetPointerEventType(ev));
77835c4bbdfSmrg        Mask xi_filter = event_get_filter_from_type(dev, xitype);
77935c4bbdfSmrg
78035c4bbdfSmrg        nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
78135c4bbdfSmrg            if (!(iclients->mask[dev->id] & xi_filter))
78235c4bbdfSmrg                continue;
78335c4bbdfSmrg
78435c4bbdfSmrg            TouchEventHistoryAllocate(ti);
78535c4bbdfSmrg            TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI,
786ed6184dfSmrg                             TOUCH_LISTENER_POINTER_REGULAR,
787ed6184dfSmrg                             TOUCH_LISTENER_AWAITING_BEGIN,
78835c4bbdfSmrg                             win, NULL);
78935c4bbdfSmrg            return TRUE;
79035c4bbdfSmrg        }
79135c4bbdfSmrg    }
79235c4bbdfSmrg
79335c4bbdfSmrg    if (mask & EVENT_CORE_MASK) {
79435c4bbdfSmrg        int coretype = GetCoreType(TouchGetPointerEventType(ev));
79535c4bbdfSmrg        Mask core_filter = event_get_filter_from_type(dev, coretype);
79635c4bbdfSmrg        OtherClients *oclients;
79735c4bbdfSmrg
79835c4bbdfSmrg        /* window owner */
79935c4bbdfSmrg        if (IsMaster(dev) && (win->eventMask & core_filter)) {
80035c4bbdfSmrg            TouchEventHistoryAllocate(ti);
80135c4bbdfSmrg            TouchAddListener(ti, win->drawable.id, RT_WINDOW, CORE,
802ed6184dfSmrg                             TOUCH_LISTENER_POINTER_REGULAR,
803ed6184dfSmrg                             TOUCH_LISTENER_AWAITING_BEGIN,
80435c4bbdfSmrg                             win, NULL);
80535c4bbdfSmrg            return TRUE;
80635c4bbdfSmrg        }
80735c4bbdfSmrg
80835c4bbdfSmrg        /* all others */
80935c4bbdfSmrg        nt_list_for_each_entry(oclients, wOtherClients(win), next) {
81035c4bbdfSmrg            if (!(oclients->mask & core_filter))
81135c4bbdfSmrg                continue;
81235c4bbdfSmrg
81335c4bbdfSmrg            TouchEventHistoryAllocate(ti);
81435c4bbdfSmrg            TouchAddListener(ti, oclients->resource, RT_OTHERCLIENT, CORE,
815ed6184dfSmrg                             type, TOUCH_LISTENER_AWAITING_BEGIN, win, NULL);
81635c4bbdfSmrg            return TRUE;
81735c4bbdfSmrg        }
81835c4bbdfSmrg    }
81935c4bbdfSmrg
82035c4bbdfSmrg    return FALSE;
82135c4bbdfSmrg}
82235c4bbdfSmrg
82335c4bbdfSmrgstatic void
82435c4bbdfSmrgTouchAddActiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
82535c4bbdfSmrg                           InternalEvent *ev, GrabPtr grab)
82635c4bbdfSmrg{
82735c4bbdfSmrg    if (!ti->emulate_pointer &&
82835c4bbdfSmrg        (grab->grabtype == CORE || grab->grabtype == XI))
82935c4bbdfSmrg        return;
83035c4bbdfSmrg
83135c4bbdfSmrg    if (!ti->emulate_pointer &&
83235c4bbdfSmrg        grab->grabtype == XI2 &&
83335c4bbdfSmrg        !xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin))
83435c4bbdfSmrg        return;
83535c4bbdfSmrg
83635c4bbdfSmrg    TouchAddGrabListener(dev, ti, ev, grab);
83735c4bbdfSmrg}
83835c4bbdfSmrg
83935c4bbdfSmrgvoid
84035c4bbdfSmrgTouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
84135c4bbdfSmrg{
84235c4bbdfSmrg    int i;
84335c4bbdfSmrg    SpritePtr sprite = &ti->sprite;
84435c4bbdfSmrg    WindowPtr win;
84535c4bbdfSmrg
84635c4bbdfSmrg    if (dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab)
84735c4bbdfSmrg        TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab);
84835c4bbdfSmrg
84935c4bbdfSmrg    /* We set up an active touch listener for existing touches, but not any
85035c4bbdfSmrg     * passive grab or regular listeners. */
85135c4bbdfSmrg    if (ev->any.type != ET_TouchBegin)
85235c4bbdfSmrg        return;
85335c4bbdfSmrg
85435c4bbdfSmrg    /* First, find all grabbing clients from the root window down
85535c4bbdfSmrg     * to the deepest child window. */
85635c4bbdfSmrg    for (i = 0; i < sprite->spriteTraceGood; i++) {
85735c4bbdfSmrg        win = sprite->spriteTrace[i];
85835c4bbdfSmrg        TouchAddPassiveGrabListener(dev, ti, win, ev);
85935c4bbdfSmrg    }
86035c4bbdfSmrg
86135c4bbdfSmrg    /* Find the first client with an applicable event selection,
86235c4bbdfSmrg     * going from deepest child window back up to the root window. */
86335c4bbdfSmrg    for (i = sprite->spriteTraceGood - 1; i >= 0; i--) {
86435c4bbdfSmrg        Bool delivered;
86535c4bbdfSmrg
86635c4bbdfSmrg        win = sprite->spriteTrace[i];
86735c4bbdfSmrg        delivered = TouchAddRegularListener(dev, ti, win, ev);
86835c4bbdfSmrg        if (delivered)
86935c4bbdfSmrg            return;
87035c4bbdfSmrg    }
87135c4bbdfSmrg}
87235c4bbdfSmrg
87335c4bbdfSmrg/**
87435c4bbdfSmrg * Remove the touch pointer grab from the device. Called from
87535c4bbdfSmrg * DeactivatePointerGrab()
87635c4bbdfSmrg */
87735c4bbdfSmrgvoid
87835c4bbdfSmrgTouchRemovePointerGrab(DeviceIntPtr dev)
87935c4bbdfSmrg{
88035c4bbdfSmrg    TouchPointInfoPtr ti;
88135c4bbdfSmrg    GrabPtr grab;
882ed6184dfSmrg    InternalEvent *ev;
88335c4bbdfSmrg
88435c4bbdfSmrg    if (!dev->touch)
88535c4bbdfSmrg        return;
88635c4bbdfSmrg
88735c4bbdfSmrg    grab = dev->deviceGrab.grab;
88835c4bbdfSmrg    if (!grab)
88935c4bbdfSmrg        return;
89035c4bbdfSmrg
89135c4bbdfSmrg    ev = dev->deviceGrab.sync.event;
892ed6184dfSmrg    if (!IsTouchEvent(ev))
89335c4bbdfSmrg        return;
89435c4bbdfSmrg
895ed6184dfSmrg    ti = TouchFindByClientID(dev, ev->device_event.touchid);
89635c4bbdfSmrg    if (!ti)
89735c4bbdfSmrg        return;
89835c4bbdfSmrg
89935c4bbdfSmrg    /* FIXME: missing a bit of code here... */
90035c4bbdfSmrg}
90135c4bbdfSmrg
90235c4bbdfSmrg/* As touch grabs don't turn into active grabs with their own resources, we
90335c4bbdfSmrg * need to walk all the touches and remove this grab from any delivery
90435c4bbdfSmrg * lists. */
90535c4bbdfSmrgvoid
90635c4bbdfSmrgTouchListenerGone(XID resource)
90735c4bbdfSmrg{
90835c4bbdfSmrg    TouchPointInfoPtr ti;
90935c4bbdfSmrg    DeviceIntPtr dev;
91035c4bbdfSmrg    InternalEvent *events = InitEventList(GetMaximumEventsNum());
91135c4bbdfSmrg    int i, j, k, nev;
91235c4bbdfSmrg
91335c4bbdfSmrg    if (!events)
91435c4bbdfSmrg        FatalError("TouchListenerGone: couldn't allocate events\n");
91535c4bbdfSmrg
91635c4bbdfSmrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
91735c4bbdfSmrg        if (!dev->touch)
91835c4bbdfSmrg            continue;
91935c4bbdfSmrg
92035c4bbdfSmrg        for (i = 0; i < dev->touch->num_touches; i++) {
92135c4bbdfSmrg            ti = &dev->touch->touches[i];
92235c4bbdfSmrg            if (!ti->active)
92335c4bbdfSmrg                continue;
92435c4bbdfSmrg
92535c4bbdfSmrg            for (j = 0; j < ti->num_listeners; j++) {
92635c4bbdfSmrg                if (CLIENT_BITS(ti->listeners[j].listener) != resource)
92735c4bbdfSmrg                    continue;
92835c4bbdfSmrg
92935c4bbdfSmrg                nev = GetTouchOwnershipEvents(events, dev, ti, XIRejectTouch,
93035c4bbdfSmrg                                              ti->listeners[j].listener, 0);
93135c4bbdfSmrg                for (k = 0; k < nev; k++)
93235c4bbdfSmrg                    mieqProcessDeviceEvent(dev, events + k, NULL);
93335c4bbdfSmrg
93435c4bbdfSmrg                break;
93535c4bbdfSmrg            }
93635c4bbdfSmrg        }
93735c4bbdfSmrg    }
93835c4bbdfSmrg
93935c4bbdfSmrg    FreeEventList(events, GetMaximumEventsNum());
94035c4bbdfSmrg}
94135c4bbdfSmrg
94235c4bbdfSmrgint
94335c4bbdfSmrgTouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti, int listener,
94435c4bbdfSmrg                          int mode)
94535c4bbdfSmrg{
94635c4bbdfSmrg    InternalEvent *events;
94735c4bbdfSmrg    int nev;
94835c4bbdfSmrg    int i;
94935c4bbdfSmrg
95035c4bbdfSmrg    BUG_RETURN_VAL(listener < 0, BadMatch);
95135c4bbdfSmrg    BUG_RETURN_VAL(listener >= ti->num_listeners, BadMatch);
95235c4bbdfSmrg
95335c4bbdfSmrg    if (listener > 0) {
95435c4bbdfSmrg        if (mode == XIRejectTouch)
95535c4bbdfSmrg            TouchRejected(dev, ti, ti->listeners[listener].listener, NULL);
95635c4bbdfSmrg        else
957ed6184dfSmrg            ti->listeners[listener].state = TOUCH_LISTENER_EARLY_ACCEPT;
95835c4bbdfSmrg
95935c4bbdfSmrg        return Success;
96035c4bbdfSmrg    }
96135c4bbdfSmrg
96235c4bbdfSmrg    events = InitEventList(GetMaximumEventsNum());
96335c4bbdfSmrg    BUG_RETURN_VAL_MSG(!events, BadAlloc, "Failed to allocate touch ownership events\n");
96435c4bbdfSmrg
96535c4bbdfSmrg    nev = GetTouchOwnershipEvents(events, dev, ti, mode,
96635c4bbdfSmrg                                  ti->listeners[0].listener, 0);
96735c4bbdfSmrg    BUG_WARN_MSG(nev == 0, "Failed to get touch ownership events\n");
96835c4bbdfSmrg
96935c4bbdfSmrg    for (i = 0; i < nev; i++)
97035c4bbdfSmrg        mieqProcessDeviceEvent(dev, events + i, NULL);
97135c4bbdfSmrg
97235c4bbdfSmrg    FreeEventList(events, GetMaximumEventsNum());
97335c4bbdfSmrg
97435c4bbdfSmrg    return nev ? Success : BadMatch;
97535c4bbdfSmrg}
97635c4bbdfSmrg
97735c4bbdfSmrgint
97835c4bbdfSmrgTouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
97935c4bbdfSmrg                  uint32_t touchid, Window grab_window, XID *error)
98035c4bbdfSmrg{
98135c4bbdfSmrg    TouchPointInfoPtr ti;
98235c4bbdfSmrg    int i;
98335c4bbdfSmrg
98435c4bbdfSmrg    if (!dev->touch) {
98535c4bbdfSmrg        *error = dev->id;
98635c4bbdfSmrg        return BadDevice;
98735c4bbdfSmrg    }
98835c4bbdfSmrg
98935c4bbdfSmrg    ti = TouchFindByClientID(dev, touchid);
99035c4bbdfSmrg    if (!ti) {
99135c4bbdfSmrg        *error = touchid;
99235c4bbdfSmrg        return BadValue;
99335c4bbdfSmrg    }
99435c4bbdfSmrg
99535c4bbdfSmrg    for (i = 0; i < ti->num_listeners; i++) {
99635c4bbdfSmrg        if (CLIENT_ID(ti->listeners[i].listener) == client->index &&
99735c4bbdfSmrg            ti->listeners[i].window->drawable.id == grab_window)
99835c4bbdfSmrg            break;
99935c4bbdfSmrg    }
100035c4bbdfSmrg    if (i == ti->num_listeners)
100135c4bbdfSmrg        return BadAccess;
100235c4bbdfSmrg
100335c4bbdfSmrg    return TouchListenerAcceptReject(dev, ti, i, mode);
100435c4bbdfSmrg}
100535c4bbdfSmrg
100635c4bbdfSmrg/**
100735c4bbdfSmrg * End physically active touches for a device.
100835c4bbdfSmrg */
100935c4bbdfSmrgvoid
101035c4bbdfSmrgTouchEndPhysicallyActiveTouches(DeviceIntPtr dev)
101135c4bbdfSmrg{
101235c4bbdfSmrg    InternalEvent *eventlist = InitEventList(GetMaximumEventsNum());
101335c4bbdfSmrg    int i;
101435c4bbdfSmrg
10151b5d61b8Smrg    input_lock();
101635c4bbdfSmrg    mieqProcessInputEvents();
101735c4bbdfSmrg    for (i = 0; i < dev->last.num_touches; i++) {
101835c4bbdfSmrg        DDXTouchPointInfoPtr ddxti = dev->last.touches + i;
101935c4bbdfSmrg
102035c4bbdfSmrg        if (ddxti->active) {
102135c4bbdfSmrg            int j;
102235c4bbdfSmrg            int nevents = GetTouchEvents(eventlist, dev, ddxti->ddx_id,
102335c4bbdfSmrg                                         XI_TouchEnd, 0, NULL);
102435c4bbdfSmrg
102535c4bbdfSmrg            for (j = 0; j < nevents; j++)
102635c4bbdfSmrg                mieqProcessDeviceEvent(dev, eventlist + j, NULL);
102735c4bbdfSmrg        }
102835c4bbdfSmrg    }
10291b5d61b8Smrg    input_unlock();
103035c4bbdfSmrg
103135c4bbdfSmrg    FreeEventList(eventlist, GetMaximumEventsNum());
103235c4bbdfSmrg}
103335c4bbdfSmrg
103435c4bbdfSmrg/**
103535c4bbdfSmrg * Generate and deliver a TouchEnd event.
103635c4bbdfSmrg *
103735c4bbdfSmrg * @param dev The device to deliver the event for.
103835c4bbdfSmrg * @param ti The touch point record to deliver the event for.
103935c4bbdfSmrg * @param flags Internal event flags. The called does not need to provide
104035c4bbdfSmrg *        TOUCH_CLIENT_ID and TOUCH_POINTER_EMULATED, this function will ensure
104135c4bbdfSmrg *        they are set appropriately.
104235c4bbdfSmrg * @param resource The client resource to deliver to, or 0 for all clients.
104335c4bbdfSmrg */
104435c4bbdfSmrgvoid
104535c4bbdfSmrgTouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource)
104635c4bbdfSmrg{
104735c4bbdfSmrg    InternalEvent event;
104835c4bbdfSmrg
104935c4bbdfSmrg    /* We're not processing a touch end for a frozen device */
105035c4bbdfSmrg    if (dev->deviceGrab.sync.frozen)
105135c4bbdfSmrg        return;
105235c4bbdfSmrg
105335c4bbdfSmrg    flags |= TOUCH_CLIENT_ID;
105435c4bbdfSmrg    if (ti->emulate_pointer)
105535c4bbdfSmrg        flags |= TOUCH_POINTER_EMULATED;
1056ed6184dfSmrg    DeliverDeviceClassesChangedEvent(ti->sourceid, GetTimeInMillis());
105735c4bbdfSmrg    GetDixTouchEnd(&event, dev, ti, flags);
105835c4bbdfSmrg    DeliverTouchEvents(dev, ti, &event, resource);
105935c4bbdfSmrg    if (ti->num_grabs == 0)
106035c4bbdfSmrg        UpdateDeviceState(dev, &event.device_event);
106135c4bbdfSmrg}
106235c4bbdfSmrg
106335c4bbdfSmrgvoid
106435c4bbdfSmrgTouchAcceptAndEnd(DeviceIntPtr dev, int touchid)
106535c4bbdfSmrg{
106635c4bbdfSmrg    TouchPointInfoPtr ti = TouchFindByClientID(dev, touchid);
106735c4bbdfSmrg    if (!ti)
106835c4bbdfSmrg        return;
106935c4bbdfSmrg
107035c4bbdfSmrg    TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
107135c4bbdfSmrg    if (ti->pending_finish)
107235c4bbdfSmrg        TouchEmitTouchEnd(dev, ti, 0, 0);
107335c4bbdfSmrg    if (ti->num_listeners <= 1)
107435c4bbdfSmrg        TouchEndTouch(dev, ti);
107535c4bbdfSmrg}
1076