[PATCH] Xi: deliver the motion event before an touch-emulated ButtonRelease normally

Peter Hutterer peter.hutterer at who-t.net
Thu Feb 7 22:25:40 PST 2013


Protocol (sort-of [1]) requires us to deliver motion events before button
events. For emulated events, the requirement is:
* TouchBegin: motion + button press
* TouchUpdate: motion
* TouchEnd: motion + button release

The TouchUpdate was handled through normal deliver, changing the TouchUpdate
event in to a pointer event where required and delivering it. Being touch
events by nature, we can assume that any touch sequence is always grabbed
(or discarded). Thus, the TouchUpdate events were discarded if we didn't
have listeners.

The motion before the TouchBegin however needs to be sent regardless of
listeners since it comes before the emulated ButtonPress.

For TouchEnd, we used the same hook as for TouchBegin, but that's bogus. A
client listening to motion events but not button events would get the motion
before the TouchBegin, no others and then again the motion before the
TouchEnd (with the button mask set).

This patch changes the hook, so we still do the out-of-band motion for
TouchBegin, but hook up the motion-before-end through the same mechanism as
the TouchUpdate. This is mostly just shuffling around, making sure we do
send the motion event that we previously skipped.

[1] And by "sort-of" I mean "It's not explicitly required in the spec, but
could be implicitly read as such though and we appear to have always done so
and I'm not about to find out what breaks if we stop doing so."

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 Xi/exevents.c | 83 ++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 57 insertions(+), 26 deletions(-)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index be62667..913d0db 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1364,30 +1364,12 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
 }
 
 static int
-DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
-                          InternalEvent *ev, TouchListener * listener,
-                          ClientPtr client, WindowPtr win, GrabPtr grab,
-                          XI2Mask *xi2mask)
+DeliverTouchEmulatedPointerEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                                 InternalEvent *ptrev,
+                                 InternalEvent *ev, TouchListener * listener,
+                                 ClientPtr client, WindowPtr win, GrabPtr grab,
+                                 XI2Mask *xi2mask)
 {
-    InternalEvent motion, button;
-    InternalEvent *ptrev = &motion;
-    int nevents;
-    DeviceIntPtr kbd;
-
-    /* We don't deliver pointer events to non-owners */
-    if (!TouchResourceIsOwner(ti, listener->listener))
-        return Success;
-
-    nevents = TouchConvertToPointerEvent(ev, &motion, &button);
-    BUG_RETURN_VAL(nevents == 0, BadValue);
-
-    if (nevents > 1)
-        ptrev = &button;
-
-    kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
-    event_set_state(dev, kbd, &ptrev->device_event);
-    ptrev->device_event.corestate = event_get_corestate(dev, kbd);
-
     if (grab) {
         /* this side-steps the usual activation mechanisms, but... */
         if (ev->any.type == ET_TouchBegin && !dev->deviceGrab.grab)
@@ -1465,6 +1447,56 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
     return Success;
 }
 
+static int
+DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                          InternalEvent *ev, TouchListener * listener,
+                          ClientPtr client, WindowPtr win, GrabPtr grab,
+                          XI2Mask *xi2mask)
+{
+    InternalEvent motion, button;
+    int nevents;
+    DeviceIntPtr kbd;
+    int rc;
+
+    /* We don't deliver pointer events to non-owners */
+    if (!TouchResourceIsOwner(ti, listener->listener))
+        return Success;
+
+    nevents = TouchConvertToPointerEvent(ev, &motion, &button);
+    BUG_RETURN_VAL(nevents == 0, BadValue);
+
+    kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
+    event_set_state(dev, kbd, &motion.device_event);
+    motion.device_event.corestate = event_get_corestate(dev, kbd);
+
+    if (nevents > 1) {
+        event_set_state(dev, kbd, &button.device_event);
+        button.device_event.corestate = event_get_corestate(dev, kbd);
+    }
+
+    /* TouchBegin sends the emulated motion event in ProcessTouchEvents.
+       That first motion event must be delivered regardless of touch
+       listener state. For Update/End, we only deliver to listeners */
+    if (ev->any.type != ET_TouchBegin) {
+        /* Save the event type, because if we pass a TouchEnd through to
+           DTEPE it will cancel any implicit grabs.
+          */
+        int type = ev->any.type;
+        ev->any.type = ET_TouchUpdate;
+        rc = DeliverTouchEmulatedPointerEvent(dev, ti, &motion, ev,
+                                              listener, client, win,
+                                              grab, xi2mask);
+        ev->any.type = type;
+    }
+
+    if (nevents > 1)
+        rc = DeliverTouchEmulatedPointerEvent(dev, ti, &button, ev,
+                                              listener, client, win,
+                                              grab, xi2mask);
+
+    return rc;
+}
+
 static void
 DeliverEmulatedMotionEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
                            InternalEvent *ev)
@@ -1592,9 +1624,8 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
     }
 
     /* if emulate_pointer is set, emulate the motion event right
-     * here, so we can ignore it for button event emulation. TouchUpdate
-     * events which _only_ emulate motion just work normally */
-    if (emulate_pointer && ev->any.type != ET_TouchUpdate)
+     * here, so it doesn't depend on listeners */
+    if (emulate_pointer && ev->any.type == ET_TouchBegin)
         DeliverEmulatedMotionEvent(dev, ti, ev);
 
     if (emulate_pointer && IsMaster(dev))
-- 
1.8.1



More information about the xorg-devel mailing list