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