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