From f682e0563f736ed2c2c612ed575e05b6e3db945e Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Mon, 8 Feb 2021 05:21:29 +0200 Subject: [PATCH] dix: Send touch end to clients that do async grab without touch events If a XI2 client started listening to touches due to a selection and then creates an active async grab that does not include touch events, then it currently won't get the touch end event which will produce inconsistent view of the pending touches. Note that we only need to consider touch listeners and can ignore pointer emulation. Under XI2 if a active grab replaces a passive implicit grab and the active grab does not include the button release event, the client won't get it either. --- dix/events.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/dix/events.c b/dix/events.c index 1441cff25..b05c95c43 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1482,14 +1482,27 @@ UpdateTouchesForGrab(DeviceIntPtr mouse) CLIENT_BITS(listener->listener) == grab->resource) { listener->listener = grab->resource; listener->level = grab->grabtype; - listener->state = TOUCH_LISTENER_IS_OWNER; listener->window = grab->window; if (grab->grabtype == CORE || grab->grabtype == XI || - !xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin)) + !xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin)) { + + if (listener->type == TOUCH_LISTENER_REGULAR && + listener->state != TOUCH_LISTENER_AWAITING_BEGIN && + listener->state != TOUCH_LISTENER_HAS_END) { + /* if the listener already got any events relating to the touch, we must send + a touch end because the grab overrides the previous listener and won't + itself send any touch events. + */ + TouchEmitTouchEnd(mouse, ti, 0, listener->listener); + } listener->type = TOUCH_LISTENER_POINTER_GRAB; - else + } else { listener->type = TOUCH_LISTENER_GRAB; + } + + listener->state = TOUCH_LISTENER_IS_OWNER; + if (listener->grab) FreeGrab(listener->grab); listener->grab = AllocGrab(grab);