Problem with touchscreen events and grabs

Peter Hutterer peter.hutterer at who-t.net
Sun Oct 21 23:47:14 PDT 2012


On Tue, Oct 16, 2012 at 09:54:23PM -0400, Thomas Jaeger wrote:
> I've noticed an issue with grabs as well, not sure if it's related to
> this one.  It's really easy to reproduce, though:  All you need is a
> little test client that passively grabs button 1 on the MD (like the one
> attached).  A passive core grab will do as well.  What happens is that
> (1) clients selecting for core events will receive emulated pointer
> events despite the passive grab and (2) sometimes ButtonRelease events
> go missing (this goes both for the grabbing and non-grabbing clients,
> but not necessarily at the same time).

btw, did you file a bug for this one? I've got a preliminary patch
(attached) but I'm not sure of the side-effects yet.

Cheers,
   Peter


> On 10/15/2012 11:09 PM, Peter Hutterer wrote:
> > On Fri, Oct 12, 2012 at 03:38:24PM +0200, Thierry Reding wrote:
> >> Hi,
> >>
> >> I've been seeing a very strange issue. Originally this was observed when
> >> using a browser with an onscreen keyboard. It would sometimes happen
> >> that the keys on the keyboard would get stuck and be repeatedly sent.
> > 
> > But on the whole, this issue looks convoluted enough that you may have to
> > write a little test application to reliably reproduce this.
> > 
> > Cheers,
> >    Peter

> /* gcc -Wall grab.c -o grab -lXi -lX11 */
> 
> #include <X11/Xlib.h>
> #include <X11/extensions/XInput2.h>
> #include <stdlib.h>
> #include <stdio.h>
> #include <stdbool.h>
> 
> Display *dpy;
> Window root;
> int opcode;
> 
> void init_xi2() {
> 	int event, error;
> 	int major = 2, minor = 0;
> 	if (!XQueryExtension(dpy, "XInputExtension", &opcode, &event, &error) ||
> 			XIQueryVersion(dpy, &major, &minor) == BadRequest ||
> 			major < 2) {
> 		printf("Error: XI2 required\n");
> 		exit(EXIT_FAILURE);
> 	}
> }
> 
> void grab(int dev) {
> 	unsigned char mask_data[2] = {0,}; 
> 	XISetMask(mask_data, XI_ButtonPress);
> 	XISetMask(mask_data, XI_ButtonRelease);
> 	XIEventMask mask = { XIAllDevices, sizeof(mask_data), mask_data };
> 	XIGrabModifiers mods = { XIAnyModifier };
> 	XIGrabButton(dpy, dev, 1, root, None, GrabModeAsync, GrabModeAsync, False, &mask, 1, &mods);
> }
> 
> 
> int main(int argc, char *argv[]) {
> 	dpy = XOpenDisplay(NULL);
> 	root = DefaultRootWindow(dpy);
> 
> 	init_xi2();
> 	if (argc < 2 || atoi(argv[1]) <= 0) {
> 		printf("Usage: %s <device number>\n", argv[0]);
> 		return EXIT_FAILURE;
> 	}
> 	int dev = atoi(argv[1]);
> 
> 	grab(dev);
> 
> 	while (true) {
> 		XEvent ev;
> 		XNextEvent(dpy, &ev);
> 		if (XGetEventData(dpy, &ev.xcookie) && ev.xcookie.extension == opcode) {
> 			switch (ev.xcookie.evtype) {
> 				case XI_ButtonPress:
> 					printf("Press\n");
> 					break;
> 				case XI_ButtonRelease:
> 					printf("Release\n");
> 					break;
> 			}
> 		}
> 		XFreeEventData(dpy, &ev.xcookie);
> 	}
> 
> 	return EXIT_SUCCESS;
> }

-------------- next part --------------
>From af01bee404728248faa608ec8ffb78e813d9e734 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer at who-t.net>
Date: Mon, 22 Oct 2012 14:58:05 +1000
Subject: [PATCH] dix: don't remove the device grab from a terminating passive
 grab

A TouchEnd will terminate a passive grab for that touch point. If that is
the case, don't try to remove that grab from all other touch points as well.

This fixes two bugs.

Bug 1:
If the number of touches is equal or larger than max_touches for the device,
we trigger infinite recursion.

Test case:
Register for passive button 1 grab on the root window, then
initiate and end max_touches + 1 touch points in quick
succession, i.e. before the server gets to actually process them.

Terminating the first will cause the passive pointer grab to be deactivated,
which erroneously triggered a removal of the device grab from all other
touch points - causing more TouchEnd events that tried to do the same.

Bug 2:
If a client has an async pointer grab on a window and another client a
(non-ownership) touch selection on that same window, the client must never
receive touch events. Pointer grab async is akin to TouchAccept, so no touch
event ever goes past the grab.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 dix/events.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dix/events.c b/dix/events.c
index ddb5b34..c5689e0 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1505,6 +1505,7 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
     DeviceIntPtr dev;
     Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
                         mouse->deviceGrab.implicitGrab);
+    Bool wasPassive = mouse->deviceGrab.fromPassiveGrab;
     XID grab_resource = grab->resource;
     int i;
 
@@ -1534,7 +1535,7 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
 
     /* If an explicit grab was deactivated, we must remove it from the head of
      * all the touches' listener lists. */
-    for (i = 0; mouse->touch && i < mouse->touch->num_touches; i++) {
+    for (i = 0; !wasPassive && mouse->touch && i < mouse->touch->num_touches; i++) {
         TouchPointInfoPtr ti = mouse->touch->touches + i;
 
         if (ti->active && TouchResourceIsOwner(ti, grab_resource))
-- 
1.7.11.7



More information about the xorg-devel mailing list