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;
> }

>From af01bee404728248faa608ec8ffb78e813d9e734 Mon Sep 17 00:00:00 2001
From: Peter Hutterer <[email protected]>
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 <[email protected]>
---
 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

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to