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