2 * Copyright © 2011 Collabra Ltd.
3 * Copyright © 2011 Red Hat, Inc.
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:
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
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.
24 * Author: Daniel Stone <daniel@fooishbar.org>
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
32 #include "scrnintstr.h"
37 #include "exglobals.h"
38 #include "inpututils.h"
39 #include "eventconvert.h"
40 #include "windowstr.h"
43 #define TOUCH_HISTORY_SIZE 100
45 /* If a touch queue resize is needed, the device id's bit is set. */
46 static unsigned char resize_waiting
[(MAXDEVICES
+ 7) / 8];
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
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.
59 * TouchUpdate and TouchEnd will only be processed if there is an active
60 * touchpoint with the same DDX id.
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.
68 * Check which devices need a bigger touch event queue and grow their
69 * last.touches by half it's current size.
71 * @param client Always the serverClient
72 * @param closure Always NULL
74 * @return Always True. If we fail to grow we probably will topple over soon
75 * anyway and re-executing this won't help.
78 TouchResizeQueue(ClientPtr client
, pointer closure
)
84 /* first two ids are reserved */
85 for (i
= 2; i
< MAXDEVICES
; i
++) {
87 DDXTouchPointInfoPtr tmp
;
90 if (!BitIsOn(resize_waiting
, i
))
93 ClearBit(resize_waiting
, i
);
95 /* device may have disappeared by now */
96 dixLookupDevice(&dev
, i
, serverClient
, DixWriteAccess
);
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;
104 tmp
= realloc(dev
->last
.touches
, size
* sizeof(*dev
->last
.touches
));
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
;
121 * Given the DDX-facing ID (which is _not_ DeviceEvent::detail.touch), find the
122 * associated DDXTouchPointInfoRec.
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
129 TouchFindByDDXID(DeviceIntPtr dev
, uint32_t ddx_id
, Bool create
)
131 DDXTouchPointInfoPtr ti
;
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
)
143 return create
? TouchBeginDDXTouch(dev
, ddx_id
) : NULL
;
147 * Given a unique DDX ID for a touchpoint, create a touchpoint record and
150 * If no other touch points are active, mark new touchpoint for pointer
153 * Returns NULL on failure (i.e. if another touch with that ID is already active,
154 * allocation failure).
157 TouchBeginDDXTouch(DeviceIntPtr dev
, uint32_t ddx_id
)
159 static int next_client_id
= 1;
161 TouchClassPtr t
= dev
->touch
;
162 DDXTouchPointInfoPtr ti
= NULL
;
163 Bool emulate_pointer
;
168 emulate_pointer
= (t
->mode
== XIDirectTouch
);
170 /* Look for another active touchpoint with the same DDX ID. DDX
171 * touchpoints must be unique. */
172 if (TouchFindByDDXID(dev
, ddx_id
, FALSE
))
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
];
182 if (!emulate_pointer
&& ti
)
191 client_id
= next_client_id
;
193 if (next_client_id
== 0)
195 ti
->client_id
= client_id
;
196 ti
->emulate_pointer
= emulate_pointer
;
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
);
206 if (!BitIsOn(resize_waiting
, dev
->id
)) {
207 SetBit(resize_waiting
, dev
->id
);
208 QueueWorkProc(TouchResizeQueue
, serverClient
, NULL
);
215 TouchEndDDXTouch(DeviceIntPtr dev
, DDXTouchPointInfoPtr ti
)
217 TouchClassPtr t
= dev
->touch
;
226 TouchInitDDXTouchPoint(DeviceIntPtr dev
, DDXTouchPointInfoPtr ddxtouch
)
228 memset(ddxtouch
, 0, sizeof(*ddxtouch
));
229 ddxtouch
->valuators
= valuator_mask_new(dev
->valuator
->numAxes
);
233 TouchInitTouchPoint(TouchClassPtr t
, ValuatorClassPtr v
, int index
)
235 TouchPointInfoPtr ti
;
237 if (index
>= t
->num_touches
)
239 ti
= &t
->touches
[index
];
241 memset(ti
, 0, sizeof(*ti
));
243 ti
->valuators
= valuator_mask_new(v
->numAxes
);
247 ti
->sprite
.spriteTrace
= calloc(32, sizeof(*ti
->sprite
.spriteTrace
));
248 if (!ti
->sprite
.spriteTrace
) {
249 valuator_mask_free(&ti
->valuators
);
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];
263 TouchFreeTouchPoint(DeviceIntPtr device
, int index
)
265 TouchPointInfoPtr ti
;
268 if (!device
->touch
|| index
>= device
->touch
->num_touches
)
270 ti
= &device
->touch
->touches
[index
];
273 TouchEndTouch(device
, ti
);
275 for (i
= 0; i
< ti
->num_listeners
; i
++)
276 TouchRemoveListener(ti
, ti
->listeners
[0].listener
);
278 valuator_mask_free(&ti
->valuators
);
279 free(ti
->sprite
.spriteTrace
);
280 ti
->sprite
.spriteTrace
= NULL
;
282 ti
->listeners
= NULL
;
285 ti
->history_size
= 0;
286 ti
->history_elements
= 0;
290 * Given a client-facing ID (e.g. DeviceEvent::detail.touch), find the
291 * associated TouchPointInfoRec.
294 TouchFindByClientID(DeviceIntPtr dev
, uint32_t client_id
)
296 TouchClassPtr t
= dev
->touch
;
297 TouchPointInfoPtr ti
;
303 for (i
= 0; i
< t
->num_touches
; i
++) {
305 if (ti
->active
&& ti
->client_id
== client_id
)
313 * Given a unique ID for a touchpoint, create a touchpoint record in the
316 * Returns NULL on failure (i.e. if another touch with that ID is already active,
317 * allocation failure).
320 TouchBeginTouch(DeviceIntPtr dev
, int sourceid
, uint32_t touchid
,
321 Bool emulate_pointer
)
324 TouchClassPtr t
= dev
->touch
;
325 TouchPointInfoPtr ti
;
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
))
340 for (i
= 0; i
< t
->num_touches
; i
++) {
344 ti
->client_id
= touchid
;
345 ti
->sourceid
= sourceid
;
346 ti
->emulate_pointer
= emulate_pointer
;
351 /* If we get here, then we've run out of touches: enlarge dev->touch and
353 tmp
= realloc(t
->touches
, (t
->num_touches
+ 1) * sizeof(*ti
));
357 if (TouchInitTouchPoint(t
, dev
->valuator
, t
->num_touches
- 1))
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.
370 TouchEndTouch(DeviceIntPtr dev
, TouchPointInfoPtr ti
)
374 if (ti
->emulate_pointer
) {
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
);
385 for (i
= 0; i
< ti
->num_listeners
; i
++)
386 TouchRemoveListener(ti
, ti
->listeners
[0].listener
);
389 ti
->pending_finish
= FALSE
;
390 ti
->sprite
.spriteTraceGood
= 0;
392 ti
->listeners
= NULL
;
393 ti
->num_listeners
= 0;
397 TouchEventHistoryFree(ti
);
399 valuator_mask_zero(ti
->valuators
);
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
407 * @return TRUE on success, FALSE on allocation errors
410 TouchEventHistoryAllocate(TouchPointInfoPtr ti
)
415 ti
->history
= calloc(TOUCH_HISTORY_SIZE
, sizeof(*ti
->history
));
416 ti
->history_elements
= 0;
418 ti
->history_size
= TOUCH_HISTORY_SIZE
;
419 return ti
->history
!= NULL
;
423 TouchEventHistoryFree(TouchPointInfoPtr ti
)
427 ti
->history_size
= 0;
428 ti
->history_elements
= 0;
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
440 TouchEventHistoryPush(TouchPointInfoPtr ti
, const DeviceEvent
*ev
)
447 /* don't store the same touchbegin twice */
448 if (ti
->history_elements
> 0)
454 return; /* no TouchEnd events in the history */
459 /* We only store real events in the history */
460 if (ev
->flags
& (TOUCH_CLIENT_ID
| TOUCH_REPLAYING
))
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
);
473 TouchEventHistoryReplay(TouchPointInfoPtr ti
, DeviceIntPtr dev
, XID resource
)
480 TouchDeliverDeviceClassesChangedEvent(ti
, ti
->history
[0].time
, resource
);
482 for (i
= 0; i
< ti
->history_elements
; i
++) {
483 DeviceEvent
*ev
= &ti
->history
[i
];
485 ev
->flags
|= TOUCH_REPLAYING
;
486 ev
->resource
= resource
;
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().
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.
500 dev
->public.processInputProc((InternalEvent
*)ev
, dev
);
505 TouchDeliverDeviceClassesChangedEvent(TouchPointInfoPtr ti
, Time time
,
512 dixLookupDevice(&dev
, ti
->sourceid
, serverClient
, DixWriteAccess
);
517 /* UpdateFromMaster generates at most one event */
518 UpdateFromMaster(&dcce
, dev
, DEVCHANGE_POINTER_EVENT
, &num_events
);
519 BUG_WARN(num_events
> 1);
522 dcce
.any
.time
= time
;
523 /* FIXME: This doesn't do anything */
524 dev
->public.processInputProc(&dcce
, dev
);
529 TouchBuildDependentSpriteTrace(DeviceIntPtr dev
, SpritePtr sprite
)
532 TouchClassPtr t
= dev
->touch
;
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)
542 if (i
< t
->num_touches
)
543 srcsprite
= &t
->touches
[i
].sprite
;
544 else if (dev
->spriteInfo
->sprite
)
545 srcsprite
= dev
->spriteInfo
->sprite
;
549 if (srcsprite
->spriteTraceGood
> sprite
->spriteTraceSize
) {
550 trace
= realloc(sprite
->spriteTrace
,
551 srcsprite
->spriteTraceSize
* sizeof(*trace
));
553 sprite
->spriteTraceGood
= 0;
556 sprite
->spriteTrace
= trace
;
557 sprite
->spriteTraceSize
= srcsprite
->spriteTraceGood
;
559 memcpy(sprite
->spriteTrace
, srcsprite
->spriteTrace
,
560 srcsprite
->spriteTraceGood
* sizeof(*trace
));
561 sprite
->spriteTraceGood
= srcsprite
->spriteTraceGood
;
567 * Ensure a window trace is present in ti->sprite, constructing one for
571 TouchBuildSprite(DeviceIntPtr sourcedev
, TouchPointInfoPtr ti
,
574 TouchClassPtr t
= sourcedev
->touch
;
575 SpritePtr sprite
= &ti
->sprite
;
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
);
584 else if (!TouchBuildDependentSpriteTrace(sourcedev
, sprite
))
587 if (sprite
->spriteTraceGood
<= 0)
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;
597 ti
->num_listeners
= 0;
603 * Copy the touch event into the pointer_event, switching the required
604 * fields to make it a correct pointer event.
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)
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
616 TouchConvertToPointerEvent(const InternalEvent
*event
,
617 InternalEvent
*motion_event
,
618 InternalEvent
*button_event
)
623 BUG_RETURN_VAL(!event
, 0);
624 BUG_RETURN_VAL(!motion_event
, 0);
626 switch (event
->any
.type
) {
631 nevents
= 2; /* motion + press */
632 ptrtype
= ET_ButtonPress
;
635 nevents
= 2; /* motion + release */
636 ptrtype
= ET_ButtonRelease
;
639 BUG_WARN_MSG(1, "Invalid event type %d\n", event
->any
.type
);
643 BUG_WARN_MSG(!(event
->device_event
.flags
& TOUCH_POINTER_EMULATED
),
644 "Non-emulating touch event\n");
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
;
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 */
663 * Return the corresponding pointer emulation internal event type for the given
664 * touch event or 0 if no such event type exists.
667 TouchGetPointerEventType(const InternalEvent
*event
)
671 switch (event
->any
.type
) {
673 type
= ET_ButtonPress
;
679 type
= ET_ButtonRelease
;
688 * @returns TRUE if the specified grab or selection is the current owner of
689 * the touch sequence.
692 TouchResourceIsOwner(TouchPointInfoPtr ti
, XID resource
)
694 return (ti
->listeners
[0].listener
== resource
);
698 * Add the resource to this touch's listeners.
701 TouchAddListener(TouchPointInfoPtr ti
, XID resource
, int resource_type
,
702 enum InputLevel level
, enum TouchListenerType type
,
703 enum TouchListenerState state
, WindowPtr window
,
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
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
;
727 * Remove the resource from this touch's listeners.
729 * @return TRUE if the resource was removed, FALSE if the resource was not
733 TouchRemoveListener(TouchPointInfoPtr ti
, XID resource
)
737 for (i
= 0; i
< ti
->num_listeners
; i
++) {
739 TouchListener
*listener
= &ti
->listeners
[i
];
741 if (listener
->listener
!= resource
)
744 if (listener
->grab
) {
745 FreeGrab(listener
->grab
);
746 listener
->grab
= NULL
;
750 for (j
= i
; j
< ti
->num_listeners
- 1; j
++)
751 ti
->listeners
[j
] = ti
->listeners
[j
+ 1];
753 ti
->listeners
[ti
->num_listeners
].listener
= 0;
754 ti
->listeners
[ti
->num_listeners
].state
= LISTENER_AWAITING_BEGIN
;
762 TouchAddGrabListener(DeviceIntPtr dev
, TouchPointInfoPtr ti
,
763 InternalEvent
*ev
, GrabPtr grab
)
765 enum TouchListenerType type
= LISTENER_GRAB
;
767 /* FIXME: owner_events */
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
;
775 else if (grab
->grabtype
== XI
|| grab
->grabtype
== CORE
) {
776 TouchEventHistoryAllocate(ti
);
777 type
= LISTENER_POINTER_GRAB
;
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
);
786 * Add one listener if there is a grab on the given window.
789 TouchAddPassiveGrabListener(DeviceIntPtr dev
, TouchPointInfoPtr ti
,
790 WindowPtr win
, InternalEvent
*ev
)
793 Bool check_core
= IsMaster(dev
) && ti
->emulate_pointer
;
795 /* FIXME: make CheckPassiveGrabsOnWindow only trigger on TouchBegin */
796 grab
= CheckPassiveGrabsOnWindow(win
, dev
, ev
, check_core
, FALSE
);
800 TouchAddGrabListener(dev
, ti
, ev
, grab
);
804 TouchAddRegularListener(DeviceIntPtr dev
, TouchPointInfoPtr ti
,
805 WindowPtr win
, InternalEvent
*ev
)
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
;
813 evtype
= GetXI2Type(ev
->any
.type
);
814 mask
= EventIsDeliverable(dev
, ev
->any
.type
, win
);
815 if (!mask
&& !ti
->emulate_pointer
)
817 else if (!mask
) { /* now try for pointer event */
818 mask
= EventIsDeliverable(dev
, TouchGetPointerEventType(ev
), win
);
820 evtype
= GetXI2Type(TouchGetPointerEventType(ev
));
821 type
= LISTENER_POINTER_REGULAR
;
827 inputMasks
= wOtherInputMasks(win
);
829 if (mask
& EVENT_XI2_MASK
) {
830 nt_list_for_each_entry(iclients
, inputMasks
->inputClients
, next
) {
831 if (!xi2mask_isset(iclients
->xi2mask
, dev
, evtype
))
834 if (!xi2mask_isset(iclients
->xi2mask
, dev
, XI_TouchOwnership
))
835 TouchEventHistoryAllocate(ti
);
837 TouchAddListener(ti
, iclients
->resource
, RT_INPUTCLIENT
, XI2
,
838 type
, LISTENER_AWAITING_BEGIN
, win
, NULL
);
843 if (mask
& EVENT_XI1_MASK
) {
844 int xitype
= GetXIType(TouchGetPointerEventType(ev
));
845 Mask xi_filter
= event_get_filter_from_type(dev
, xitype
);
847 nt_list_for_each_entry(iclients
, inputMasks
->inputClients
, next
) {
848 if (!(iclients
->mask
[dev
->id
] & xi_filter
))
851 TouchEventHistoryAllocate(ti
);
852 TouchAddListener(ti
, iclients
->resource
, RT_INPUTCLIENT
, XI
,
853 LISTENER_POINTER_REGULAR
, LISTENER_AWAITING_BEGIN
,
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
;
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
,
874 nt_list_for_each_entry(oclients
, wOtherClients(win
), next
) {
875 if (!(oclients
->mask
& core_filter
))
878 TouchEventHistoryAllocate(ti
);
879 TouchAddListener(ti
, oclients
->resource
, RT_OTHERCLIENT
, CORE
,
880 type
, LISTENER_AWAITING_BEGIN
, win
, NULL
);
889 TouchAddActiveGrabListener(DeviceIntPtr dev
, TouchPointInfoPtr ti
,
890 InternalEvent
*ev
, GrabPtr grab
)
892 if (!ti
->emulate_pointer
&&
893 (grab
->grabtype
== CORE
|| grab
->grabtype
== XI
))
896 if (!ti
->emulate_pointer
&&
897 grab
->grabtype
== XI2
&&
898 !xi2mask_isset(grab
->xi2mask
, dev
, XI_TouchBegin
))
901 TouchAddGrabListener(dev
, ti
, ev
, grab
);
905 TouchSetupListeners(DeviceIntPtr dev
, TouchPointInfoPtr ti
, InternalEvent
*ev
)
908 SpritePtr sprite
= &ti
->sprite
;
911 if (dev
->deviceGrab
.grab
&& !dev
->deviceGrab
.fromPassiveGrab
)
912 TouchAddActiveGrabListener(dev
, ti
, ev
, dev
->deviceGrab
.grab
);
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
)
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
);
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
--) {
931 win
= sprite
->spriteTrace
[i
];
932 delivered
= TouchAddRegularListener(dev
, ti
, win
, ev
);
939 * Remove the touch pointer grab from the device. Called from
940 * DeactivatePointerGrab()
943 TouchRemovePointerGrab(DeviceIntPtr dev
)
945 TouchPointInfoPtr ti
;
952 grab
= dev
->deviceGrab
.grab
;
956 ev
= dev
->deviceGrab
.sync
.event
;
957 if (!IsTouchEvent((InternalEvent
*) ev
))
960 ti
= TouchFindByClientID(dev
, ev
->touchid
);
964 /* FIXME: missing a bit of code here... */
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
971 TouchListenerGone(XID resource
)
973 TouchPointInfoPtr ti
;
975 InternalEvent
*events
= InitEventList(GetMaximumEventsNum());
979 FatalError("TouchListenerGone: couldn't allocate events\n");
981 for (dev
= inputInfo
.devices
; dev
; dev
= dev
->next
) {
985 for (i
= 0; i
< dev
->touch
->num_touches
; i
++) {
986 ti
= &dev
->touch
->touches
[i
];
990 for (j
= 0; j
< ti
->num_listeners
; j
++) {
991 if (CLIENT_BITS(ti
->listeners
[j
].listener
) != resource
)
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
);
1004 FreeEventList(events
, GetMaximumEventsNum());
1008 TouchListenerAcceptReject(DeviceIntPtr dev
, TouchPointInfoPtr ti
, int listener
,
1011 InternalEvent
*events
;
1015 BUG_RETURN_VAL(listener
< 0, BadMatch
);
1016 BUG_RETURN_VAL(listener
>= ti
->num_listeners
, BadMatch
);
1019 if (mode
== XIRejectTouch
)
1020 TouchRejected(dev
, ti
, ti
->listeners
[listener
].listener
, NULL
);
1022 ti
->listeners
[listener
].state
= LISTENER_EARLY_ACCEPT
;
1027 events
= InitEventList(GetMaximumEventsNum());
1028 BUG_RETURN_VAL_MSG(!events
, BadAlloc
, "Failed to allocate touch ownership events\n");
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");
1034 for (i
= 0; i
< nev
; i
++)
1035 mieqProcessDeviceEvent(dev
, events
+ i
, NULL
);
1037 FreeEventList(events
, GetMaximumEventsNum());
1039 return nev
? Success
: BadMatch
;
1043 TouchAcceptReject(ClientPtr client
, DeviceIntPtr dev
, int mode
,
1044 uint32_t touchid
, Window grab_window
, XID
*error
)
1046 TouchPointInfoPtr ti
;
1054 ti
= TouchFindByClientID(dev
, touchid
);
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
)
1065 if (i
== ti
->num_listeners
)
1068 return TouchListenerAcceptReject(dev
, ti
, i
, mode
);
1072 * End physically active touches for a device.
1075 TouchEndPhysicallyActiveTouches(DeviceIntPtr dev
)
1077 InternalEvent
*eventlist
= InitEventList(GetMaximumEventsNum());
1081 mieqProcessInputEvents();
1082 for (i
= 0; i
< dev
->last
.num_touches
; i
++) {
1083 DDXTouchPointInfoPtr ddxti
= dev
->last
.touches
+ i
;
1085 if (ddxti
->active
) {
1087 int nevents
= GetTouchEvents(eventlist
, dev
, ddxti
->ddx_id
,
1088 XI_TouchEnd
, 0, NULL
);
1090 for (j
= 0; j
< nevents
; j
++)
1091 mieqProcessDeviceEvent(dev
, eventlist
+ j
, NULL
);
1096 FreeEventList(eventlist
, GetMaximumEventsNum());
1100 * Generate and deliver a TouchEnd event.
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.
1110 TouchEmitTouchEnd(DeviceIntPtr dev
, TouchPointInfoPtr ti
, int flags
, XID resource
)
1112 InternalEvent event
;
1114 /* We're not processing a touch end for a frozen device */
1115 if (dev
->deviceGrab
.sync
.frozen
)
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
);
1129 TouchAcceptAndEnd(DeviceIntPtr dev
, int touchid
)
1131 TouchPointInfoPtr ti
= TouchFindByClientID(dev
, touchid
);
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
);