Home | History | Annotate | Line # | Download | only in dix
      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 (at) 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 Bool 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 
     77 static Bool
     78 TouchResizeQueue(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  */
    107 DDXTouchPointInfoPtr
    108 TouchFindByDDXID(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  */
    135 DDXTouchPointInfoPtr
    136 TouchBeginDDXTouch(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 
    186 void
    187 TouchEndDDXTouch(DeviceIntPtr dev, DDXTouchPointInfoPtr ti)
    188 {
    189     TouchClassPtr t = dev->touch;
    190 
    191     if (!t)
    192         return;
    193 
    194     ti->active = FALSE;
    195 }
    196 
    197 void
    198 TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch)
    199 {
    200     memset(ddxtouch, 0, sizeof(*ddxtouch));
    201     ddxtouch->valuators = valuator_mask_new(dev->valuator->numAxes);
    202 }
    203 
    204 Bool
    205 TouchInitTouchPoint(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 
    234 void
    235 TouchFreeTouchPoint(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  */
    265 TouchPointInfoPtr
    266 TouchFindByClientID(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  */
    291 TouchPointInfoPtr
    292 TouchBeginTouch(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  */
    341 void
    342 TouchEndTouch(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  */
    381 Bool
    382 TouchEventHistoryAllocate(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 
    394 void
    395 TouchEventHistoryFree(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  */
    411 void
    412 TouchEventHistoryPush(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 
    444 void
    445 TouchEventHistoryReplay(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 
    476 Bool
    477 TouchBuildDependentSpriteTrace(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  */
    503 Bool
    504 TouchBuildSprite(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  */
    548 int
    549 TouchConvertToPointerEvent(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  */
    599 int
    600 TouchGetPointerEventType(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  */
    624 Bool
    625 TouchResourceIsOwner(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  */
    633 void
    634 TouchAddListener(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  */
    665 Bool
    666 TouchRemoveListener(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 
    694 static void
    695 TouchAddGrabListener(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  */
    721 static void
    722 TouchAddPassiveGrabListener(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 
    736 static Bool
    737 TouchAddRegularListener(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         BUG_RETURN_VAL(!inputMasks, FALSE);
    764 
    765         nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
    766             if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
    767                 continue;
    768 
    769             if (!xi2mask_isset(iclients->xi2mask, dev, XI_TouchOwnership))
    770                 TouchEventHistoryAllocate(ti);
    771 
    772             TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI2,
    773                              type, TOUCH_LISTENER_AWAITING_BEGIN, win, NULL);
    774             return TRUE;
    775         }
    776     }
    777 
    778     if (mask & EVENT_XI1_MASK) {
    779         int xitype = GetXIType(TouchGetPointerEventType(ev));
    780         Mask xi_filter = event_get_filter_from_type(dev, xitype);
    781 
    782         BUG_RETURN_VAL(!inputMasks, FALSE);
    783 
    784         nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
    785             if (!(iclients->mask[dev->id] & xi_filter))
    786                 continue;
    787 
    788             TouchEventHistoryAllocate(ti);
    789             TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI,
    790                              TOUCH_LISTENER_POINTER_REGULAR,
    791                              TOUCH_LISTENER_AWAITING_BEGIN,
    792                              win, NULL);
    793             return TRUE;
    794         }
    795     }
    796 
    797     if (mask & EVENT_CORE_MASK) {
    798         int coretype = GetCoreType(TouchGetPointerEventType(ev));
    799         Mask core_filter = event_get_filter_from_type(dev, coretype);
    800         OtherClients *oclients;
    801 
    802         /* window owner */
    803         if (IsMaster(dev) && (win->eventMask & core_filter)) {
    804             TouchEventHistoryAllocate(ti);
    805             TouchAddListener(ti, win->drawable.id, RT_WINDOW, CORE,
    806                              TOUCH_LISTENER_POINTER_REGULAR,
    807                              TOUCH_LISTENER_AWAITING_BEGIN,
    808                              win, NULL);
    809             return TRUE;
    810         }
    811 
    812         /* all others */
    813         nt_list_for_each_entry(oclients, wOtherClients(win), next) {
    814             if (!(oclients->mask & core_filter))
    815                 continue;
    816 
    817             TouchEventHistoryAllocate(ti);
    818             TouchAddListener(ti, oclients->resource, RT_OTHERCLIENT, CORE,
    819                              type, TOUCH_LISTENER_AWAITING_BEGIN, win, NULL);
    820             return TRUE;
    821         }
    822     }
    823 
    824     return FALSE;
    825 }
    826 
    827 static void
    828 TouchAddActiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
    829                            InternalEvent *ev, GrabPtr grab)
    830 {
    831     if (!ti->emulate_pointer &&
    832         (grab->grabtype == CORE || grab->grabtype == XI))
    833         return;
    834 
    835     if (!ti->emulate_pointer &&
    836         grab->grabtype == XI2 &&
    837         !xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin))
    838         return;
    839 
    840     TouchAddGrabListener(dev, ti, ev, grab);
    841 }
    842 
    843 void
    844 TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
    845 {
    846     int i;
    847     SpritePtr sprite = &ti->sprite;
    848     WindowPtr win;
    849 
    850     if (dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab)
    851         TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab);
    852 
    853     /* We set up an active touch listener for existing touches, but not any
    854      * passive grab or regular listeners. */
    855     if (ev->any.type != ET_TouchBegin)
    856         return;
    857 
    858     /* First, find all grabbing clients from the root window down
    859      * to the deepest child window. */
    860     for (i = 0; i < sprite->spriteTraceGood; i++) {
    861         win = sprite->spriteTrace[i];
    862         TouchAddPassiveGrabListener(dev, ti, win, ev);
    863     }
    864 
    865     /* Find the first client with an applicable event selection,
    866      * going from deepest child window back up to the root window. */
    867     for (i = sprite->spriteTraceGood - 1; i >= 0; i--) {
    868         Bool delivered;
    869 
    870         win = sprite->spriteTrace[i];
    871         delivered = TouchAddRegularListener(dev, ti, win, ev);
    872         if (delivered)
    873             return;
    874     }
    875 }
    876 
    877 /**
    878  * Remove the touch pointer grab from the device. Called from
    879  * DeactivatePointerGrab()
    880  */
    881 void
    882 TouchRemovePointerGrab(DeviceIntPtr dev)
    883 {
    884     TouchPointInfoPtr ti;
    885     GrabPtr grab;
    886     InternalEvent *ev;
    887 
    888     if (!dev->touch)
    889         return;
    890 
    891     grab = dev->deviceGrab.grab;
    892     if (!grab)
    893         return;
    894 
    895     ev = dev->deviceGrab.sync.event;
    896     if (!IsTouchEvent(ev))
    897         return;
    898 
    899     ti = TouchFindByClientID(dev, ev->device_event.touchid);
    900     if (!ti)
    901         return;
    902 
    903     /* FIXME: missing a bit of code here... */
    904 }
    905 
    906 /* As touch grabs don't turn into active grabs with their own resources, we
    907  * need to walk all the touches and remove this grab from any delivery
    908  * lists. */
    909 void
    910 TouchListenerGone(XID resource)
    911 {
    912     TouchPointInfoPtr ti;
    913     DeviceIntPtr dev;
    914     InternalEvent *events = InitEventList(GetMaximumEventsNum());
    915     int i, j, k, nev;
    916 
    917     if (!events)
    918         FatalError("TouchListenerGone: couldn't allocate events\n");
    919 
    920     for (dev = inputInfo.devices; dev; dev = dev->next) {
    921         if (!dev->touch)
    922             continue;
    923 
    924         for (i = 0; i < dev->touch->num_touches; i++) {
    925             ti = &dev->touch->touches[i];
    926             if (!ti->active)
    927                 continue;
    928 
    929             for (j = 0; j < ti->num_listeners; j++) {
    930                 if (CLIENT_BITS(ti->listeners[j].listener) != resource)
    931                     continue;
    932 
    933                 nev = GetTouchOwnershipEvents(events, dev, ti, XIRejectTouch,
    934                                               ti->listeners[j].listener, 0);
    935                 for (k = 0; k < nev; k++)
    936                     mieqProcessDeviceEvent(dev, events + k, NULL);
    937 
    938                 break;
    939             }
    940         }
    941     }
    942 
    943     FreeEventList(events, GetMaximumEventsNum());
    944 }
    945 
    946 int
    947 TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti, int listener,
    948                           int mode)
    949 {
    950     InternalEvent *events;
    951     int nev;
    952     int i;
    953 
    954     BUG_RETURN_VAL(listener < 0, BadMatch);
    955     BUG_RETURN_VAL(listener >= ti->num_listeners, BadMatch);
    956 
    957     if (listener > 0) {
    958         if (mode == XIRejectTouch)
    959             TouchRejected(dev, ti, ti->listeners[listener].listener, NULL);
    960         else
    961             ti->listeners[listener].state = TOUCH_LISTENER_EARLY_ACCEPT;
    962 
    963         return Success;
    964     }
    965 
    966     events = InitEventList(GetMaximumEventsNum());
    967     BUG_RETURN_VAL_MSG(!events, BadAlloc, "Failed to allocate touch ownership events\n");
    968 
    969     nev = GetTouchOwnershipEvents(events, dev, ti, mode,
    970                                   ti->listeners[0].listener, 0);
    971     BUG_WARN_MSG(nev == 0, "Failed to get touch ownership events\n");
    972 
    973     for (i = 0; i < nev; i++)
    974         mieqProcessDeviceEvent(dev, events + i, NULL);
    975 
    976     FreeEventList(events, GetMaximumEventsNum());
    977 
    978     return nev ? Success : BadMatch;
    979 }
    980 
    981 int
    982 TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
    983                   uint32_t touchid, Window grab_window, XID *error)
    984 {
    985     TouchPointInfoPtr ti;
    986     int i;
    987 
    988     if (!dev->touch) {
    989         *error = dev->id;
    990         return BadDevice;
    991     }
    992 
    993     ti = TouchFindByClientID(dev, touchid);
    994     if (!ti) {
    995         *error = touchid;
    996         return BadValue;
    997     }
    998 
    999     for (i = 0; i < ti->num_listeners; i++) {
   1000         if (CLIENT_ID(ti->listeners[i].listener) == client->index &&
   1001             ti->listeners[i].window->drawable.id == grab_window)
   1002             break;
   1003     }
   1004     if (i == ti->num_listeners)
   1005         return BadAccess;
   1006 
   1007     return TouchListenerAcceptReject(dev, ti, i, mode);
   1008 }
   1009 
   1010 /**
   1011  * End physically active touches for a device.
   1012  */
   1013 void
   1014 TouchEndPhysicallyActiveTouches(DeviceIntPtr dev)
   1015 {
   1016     InternalEvent *eventlist = InitEventList(GetMaximumEventsNum());
   1017     int i;
   1018 
   1019     input_lock();
   1020     mieqProcessInputEvents();
   1021     for (i = 0; i < dev->last.num_touches; i++) {
   1022         DDXTouchPointInfoPtr ddxti = dev->last.touches + i;
   1023 
   1024         if (ddxti->active) {
   1025             int j;
   1026             int nevents = GetTouchEvents(eventlist, dev, ddxti->ddx_id,
   1027                                          XI_TouchEnd, 0, NULL);
   1028 
   1029             for (j = 0; j < nevents; j++)
   1030                 mieqProcessDeviceEvent(dev, eventlist + j, NULL);
   1031         }
   1032     }
   1033     input_unlock();
   1034 
   1035     FreeEventList(eventlist, GetMaximumEventsNum());
   1036 }
   1037 
   1038 /**
   1039  * Generate and deliver a TouchEnd event.
   1040  *
   1041  * @param dev The device to deliver the event for.
   1042  * @param ti The touch point record to deliver the event for.
   1043  * @param flags Internal event flags. The called does not need to provide
   1044  *        TOUCH_CLIENT_ID and TOUCH_POINTER_EMULATED, this function will ensure
   1045  *        they are set appropriately.
   1046  * @param resource The client resource to deliver to, or 0 for all clients.
   1047  */
   1048 void
   1049 TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource)
   1050 {
   1051     InternalEvent event;
   1052 
   1053     /* We're not processing a touch end for a frozen device */
   1054     if (dev->deviceGrab.sync.frozen)
   1055         return;
   1056 
   1057     flags |= TOUCH_CLIENT_ID;
   1058     if (ti->emulate_pointer)
   1059         flags |= TOUCH_POINTER_EMULATED;
   1060     DeliverDeviceClassesChangedEvent(ti->sourceid, GetTimeInMillis());
   1061     GetDixTouchEnd(&event, dev, ti, flags);
   1062     DeliverTouchEvents(dev, ti, &event, resource);
   1063     if (ti->num_grabs == 0)
   1064         UpdateDeviceState(dev, &event.device_event);
   1065 }
   1066 
   1067 void
   1068 TouchAcceptAndEnd(DeviceIntPtr dev, int touchid)
   1069 {
   1070     TouchPointInfoPtr ti = TouchFindByClientID(dev, touchid);
   1071     if (!ti)
   1072         return;
   1073 
   1074     TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
   1075     if (ti->pending_finish)
   1076         TouchEmitTouchEnd(dev, ti, 0, 0);
   1077     if (ti->num_listeners <= 1)
   1078         TouchEndTouch(dev, ti);
   1079 }
   1080