xserver: Branch 'server-1.14-branch' - 33 commits

Matt Dew marcoz at kemper.freedesktop.org
Thu Jul 25 22:06:15 PDT 2013


 Xext/saver.c                   |    8 +-
 Xi/exevents.c                  |  155 +++++++++++++++++++++--------------------
 Xi/ungrdevb.c                  |    2 
 Xi/ungrdevk.c                  |    2 
 Xi/xipassivegrab.c             |    2 
 dix/cursor.c                   |   29 +++++++
 dix/devices.c                  |    4 -
 dix/dispatch.c                 |    1 
 dix/events.c                   |  101 ++++++++++++++------------
 dix/grabs.c                    |   21 ++---
 dix/touch.c                    |  114 +++++++++++++++++++++++++-----
 dix/window.c                   |   15 +--
 hw/xfree86/modes/xf86Cursors.c |    4 -
 hw/xfree86/ramdac/xf86Cursor.c |   28 +++----
 include/cursor.h               |    4 +
 include/dixgrabs.h             |    2 
 include/eventstr.h             |    1 
 include/input.h                |    2 
 include/inputstr.h             |    2 
 render/animcur.c               |    3 
 xfixes/cursor.c                |    6 -
 21 files changed, 316 insertions(+), 190 deletions(-)

New commits:
commit bc41226f7741098e55a3b0df924986991576d50a
Merge: 4ebd618 2cd62dc
Author: Matt Dew <marcoz at osource.org>
Date:   Thu Jul 25 22:56:24 2013 -0600

    Merge branch 'server-1.14-touch-fixes' of git://people.freedesktop.org/~whot/xserver into server-1.14-branch

commit 2cd62dc02b67c70d2417b2ccd307ead9596a2967
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Mar 1 08:43:58 2013 +1000

    Xi: return !Success from DeliverTouchEmulatedEvent if we didn't deliver
    
    All callers currently ignore the new value, so this patch has no effect.
    Inverse call graph:
    
    DeliverTouchEmulatedEvent
            DeliverEmulatedMotionEvent              Ignores value
            DeliverTouchBeginEvent
                    DeliverTouchEvent
                            DeliverTouchEvents      Ignores value
            DeliverTouchEndEvent
                    DeliverTouchEvent
                            DeliverTouchEvents      Ignores value
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Keith Packard <keithp at keithp.com>
    (cherry picked from commit 9978b57b8d94f061d72a67b99a02b0ba16a11429)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 91281ae..067e6b3 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1373,7 +1373,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
 
     /* We don't deliver pointer events to non-owners */
     if (!TouchResourceIsOwner(ti, listener->listener))
-        return Success;
+        return !Success;
 
     nevents = TouchConvertToPointerEvent(ev, &motion, &button);
     BUG_RETURN_VAL(nevents == 0, BadValue);
@@ -1395,7 +1395,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
             /* 'grab' is the passive grab, but if the grab isn't active,
              * don't deliver */
             if (!dev->deviceGrab.grab)
-                return Success;
+                return !Success;
 
             if (grab->ownerEvents) {
                 WindowPtr focus = NullWindow;
commit c203568905bcbb65fb1e079b626d2c1e90ecb72d
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon May 13 15:22:12 2013 +1000

    Xi: fix warning - remove unused 'rc'
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit fd5ea0237db6d725a48f76b706135df9d3246b82)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 30e48f0..91281ae 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1036,7 +1036,6 @@ DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
 static void
 ActivateEarlyAccept(DeviceIntPtr dev, TouchPointInfoPtr ti)
 {
-    int rc;
     ClientPtr client;
     XID error;
     GrabPtr grab = ti->listeners[0].grab;
commit 93f063c40dc4b339ae9114551071c57b52d98dba
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Jul 12 14:10:10 2013 +1000

    dix: UpdateTouchesForGrab must only free the listener grab if it is non-NULL
    
    If a client calls XIGrabDevice in response to a ButtonPress event (regular
    event selection), the device will have a grab, but listener->grab is NULL.
    
    Check for that, to avoid logspam.
    
    [ 26293.863] (EE) BUG: triggered 'if (!pGrab)'
    [ 26293.863] (EE) BUG: grabs.c:256 in FreeGrab()
    [ 26293.863] (EE)
    [ 26293.863] (EE) Backtrace:
    [ 26293.864] (EE) 0: /usr/bin/Xorg (FreeGrab+0x54) [0x45d3fc]
    [ 26293.864] (EE) 1: /usr/bin/Xorg (UpdateTouchesForGrab+0x135) [0x447d4e]
    [ 26293.864] (EE) 2: /usr/bin/Xorg (ActivatePointerGrab+0x1ba) [0x447f3d]
    [ 26293.864] (EE) 3: /usr/bin/Xorg (GrabDevice+0x3e6) [0x4503bc]
    [ 26293.864] (EE) 4: /usr/bin/Xorg (ProcXIGrabDevice+0x1f9) [0x5981b1]
    [ 26293.865] (EE) 5: /usr/bin/Xorg (ProcIDispatch+0x78) [0x58aa17]
    [ 26293.865] (EE) 6: /usr/bin/Xorg (Dispatch+0x30d) [0x43347e]
    [ 26293.865] (EE) 7: /usr/bin/Xorg (main+0x61d) [0x498175]
    [ 26293.865] (EE) 8: /lib64/libc.so.6 (__libc_start_main+0xf5) [0x3df5621b75]
    [ 26293.865] (EE) 9: /usr/bin/Xorg (_start+0x29) [0x423a19]
    [ 26293.866] (EE) 10: ? (?+0x29) [0x29]
    [ 26293.866] (EE)
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Keith Packard <keithp at keithp.com>
    (cherry picked from commit 0e3be0b25fcfeff386bad132526352c2e45f1932)

diff --git a/dix/events.c b/dix/events.c
index f9b2ed7..c079f97 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1438,7 +1438,8 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
                 listener->type = LISTENER_POINTER_GRAB;
             else
                 listener->type = LISTENER_GRAB;
-            FreeGrab(listener->grab);
+            if (listener->grab)
+                FreeGrab(listener->grab);
             listener->grab = AllocGrab(grab);
         }
     }
commit ecd178e632a99ae2f12d2d9b6e9a48eaa421335d
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Jul 9 13:27:19 2013 +1000

    dix: when ungrabbing an active grab, accept pointer grabs (#66720)
    
    Ungrabbing a device during an active touch grab rejects the grab. Ungrabbing
    a device during an active pointer grab accepts the grab.
    
    Rejection is not really an option for a pointer-emulated grab, if a client
    has a button mask on the window it would get a ButtonPress emulated after
    UngrabDevice. That is against the core grab behaviour.
    
    X.Org Bug 66720 <http://bugs.freedesktop.org/show_bug.cgi?id=66720>
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Jasper St. Pierre <jstpierre at mecheye.net>
    (cherry picked from commit 8eeaa74bc241acb41f1d3ed64971e0b01e794776)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index e1945b9..30e48f0 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1224,9 +1224,13 @@ ProcessTouchOwnershipEvent(TouchOwnershipEvent *ev,
     else if (ev->reason == XIAcceptTouch) {
         int i;
 
-        /* Go through the motions of ending the touch if the listener has
+
+        /* For pointer-emulated listeners that ungrabbed the active grab,
+         * the state was forced to LISTENER_HAS_END. Still go
+         * through the motions of ending the touch if the listener has
          * already seen the end. This ensures that the touch record is ended in
-         * the server. */
+         * the server.
+         */
         if (ti->listeners[0].state == LISTENER_HAS_END)
             TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[0].listener);
 
@@ -1884,16 +1888,23 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
 
     if (listener->type == LISTENER_POINTER_REGULAR ||
         listener->type == LISTENER_POINTER_GRAB) {
-        rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
-                                       grab, xi2mask);
-
-         /* Once we send a TouchEnd to a legacy listener, we're already well
-          * past the accepting/rejecting stage (can only happen on
-          * GrabModeSync + replay. This listener now gets the end event,
-          * and we can continue.
-          */
-        if (rc == Success)
-            listener->state = LISTENER_HAS_END;
+        /* Note: If the active grab was ungrabbed, we already changed the
+         * state to LISTENER_HAS_END but still get here. So we mustn't
+         * actually send the event.
+         * This is part two of the hack in DeactivatePointerGrab
+         */
+        if (listener->state != LISTENER_HAS_END) {
+            rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
+                                           grab, xi2mask);
+
+             /* Once we send a TouchEnd to a legacy listener, we're already well
+              * past the accepting/rejecting stage (can only happen on
+              * GrabModeSync + replay. This listener now gets the end event,
+              * and we can continue.
+              */
+            if (rc == Success)
+                listener->state = LISTENER_HAS_END;
+        }
         goto out;
     }
 
diff --git a/dix/events.c b/dix/events.c
index 4d50a24..f9b2ed7 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1519,13 +1519,20 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
     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)) {
+            int mode = XIRejectTouch;
             /* Rejecting will generate a TouchEnd, but we must not
                emulate a ButtonRelease here. So pretend the listener
                already has the end event */
             if (grab->grabtype == CORE || grab->grabtype == XI ||
-                    !xi2mask_isset(mouse->deviceGrab.grab->xi2mask, mouse, XI_TouchBegin))
+                    !xi2mask_isset(mouse->deviceGrab.grab->xi2mask, mouse, XI_TouchBegin)) {
+                mode = XIAcceptTouch;
+                /* NOTE: we set the state here, but
+                 * ProcessTouchOwnershipEvent() will still call
+                 * TouchEmitTouchEnd for this listener. The other half of
+                 * this hack is in DeliverTouchEndEvent */
                 ti->listeners[0].state = LISTENER_HAS_END;
-            TouchListenerAcceptReject(mouse, ti, 0, XIRejectTouch);
+            }
+            TouchListenerAcceptReject(mouse, ti, 0, mode);
         }
     }
 
commit 54a7ae04a8475df6ce87e52ff995de22fafc7c92
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon May 27 13:46:49 2013 +1000

    dix: remove logspam in RefCursor()
    
    This shouldn't have been in the patch
    
    Reported-by: Colin Harrison <colin.harrison at virgin.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Keith Packard <keithp at keithp.com>
    (cherry picked from commit c21344add2fc589df83b29be5831c36a372201bd)

diff --git a/dix/cursor.c b/dix/cursor.c
index 0820b18..cd8305c 100644
--- a/dix/cursor.c
+++ b/dix/cursor.c
@@ -134,12 +134,8 @@ FreeCursor(pointer value, XID cid)
 CursorPtr
 RefCursor(CursorPtr cursor)
 {
-    ErrorF("%s ::::: cursor is %p", __func__, cursor);
-    if (cursor) {
-        xorg_backtrace();
+    if (cursor)
         cursor->refcnt++;
-    }
-    ErrorF("\n");
     return cursor;
 }
 
commit 1e29b269fd712ae1e3552eeddd3529015baee7ae
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed May 15 19:01:11 2013 +1000

    Abstract cursor refcounting
    
    Too many callers relied on the refcnt being handled correctly. Use a simple
    wrapper to handle that case.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 9a5ad65330693b3273972b63d10f2907d9ab954a)

diff --git a/Xext/saver.c b/Xext/saver.c
index 8de043f..fe81bc4 100644
--- a/Xext/saver.c
+++ b/Xext/saver.c
@@ -531,15 +531,16 @@ CreateSaverWindow(ScreenPtr pScreen)
         mask |= CWBorderPixmap;
     }
     if (pAttr->pCursor) {
+        CursorPtr cursor;
         if (!pWin->optional)
             if (!MakeWindowOptional(pWin)) {
                 FreeResource(pWin->drawable.id, RT_NONE);
                 return FALSE;
             }
-        pAttr->pCursor->refcnt++;
+        cursor = RefCursor(pAttr->pCursor);
         if (pWin->optional->cursor)
             FreeCursor(pWin->optional->cursor, (Cursor) 0);
-        pWin->optional->cursor = pAttr->pCursor;
+        pWin->optional->cursor = cursor;
         pWin->cursorIsNone = FALSE;
         CheckWindowOptionalNeed(pWin);
         mask |= CWCursor;
@@ -1065,8 +1066,7 @@ ScreenSaverSetAttributes(ClientPtr client)
                     client->errorValue = cursorID;
                     goto PatchUp;
                 }
-                pCursor->refcnt++;
-                pAttr->pCursor = pCursor;
+                pAttr->pCursor = RefCursor(pCursor);
                 pAttr->mask &= ~CWCursor;
             }
             break;
diff --git a/dix/cursor.c b/dix/cursor.c
index 1ee127a..0820b18 100644
--- a/dix/cursor.c
+++ b/dix/cursor.c
@@ -114,9 +114,13 @@ FreeCursor(pointer value, XID cid)
     ScreenPtr pscr;
     DeviceIntPtr pDev = NULL;   /* unused anyway */
 
-    if (--pCurs->refcnt != 0)
+
+    UnrefCursor(pCurs);
+    if (CursorRefCount(pCurs) != 0)
         return Success;
 
+    BUG_WARN(CursorRefCount(pCurs) < 0);
+
     for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
         pscr = screenInfo.screens[nscr];
         (void) (*pscr->UnrealizeCursor) (pDev, pscr, pCurs);
@@ -127,6 +131,33 @@ FreeCursor(pointer value, XID cid)
     return Success;
 }
 
+CursorPtr
+RefCursor(CursorPtr cursor)
+{
+    ErrorF("%s ::::: cursor is %p", __func__, cursor);
+    if (cursor) {
+        xorg_backtrace();
+        cursor->refcnt++;
+    }
+    ErrorF("\n");
+    return cursor;
+}
+
+CursorPtr
+UnrefCursor(CursorPtr cursor)
+{
+    if (cursor)
+        cursor->refcnt--;
+    return cursor;
+}
+
+int
+CursorRefCount(const CursorPtr cursor)
+{
+    return cursor ? cursor->refcnt : 0;
+}
+
+
 /*
  * We check for empty cursors so that we won't have to display them
  */
diff --git a/dix/events.c b/dix/events.c
index 64a8f15..4d50a24 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -931,8 +931,7 @@ ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor)
 
         (*pScreen->DisplayCursor) (pDev, pScreen, cursor);
         FreeCursor(pSprite->current, (Cursor) 0);
-        pSprite->current = cursor;
-        pSprite->current->refcnt++;
+        pSprite->current = RefCursor(cursor);
     }
 }
 
@@ -3207,11 +3206,10 @@ InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin)
         pSprite->pEnqueueScreen = screenInfo.screens[0];
         pSprite->pDequeueScreen = pSprite->pEnqueueScreen;
     }
-    if (pCursor)
-        pCursor->refcnt++;
+    pCursor = RefCursor(pCursor);
     if (pSprite->current)
         FreeCursor(pSprite->current, None);
-    pSprite->current = pCursor;
+    pSprite->current = RefCursor(pCursor);
 
     if (pScreen) {
         (*pScreen->RealizeCursor) (pDev, pScreen, pSprite->current);
@@ -3290,9 +3288,7 @@ UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen)
     pSprite->hotLimits.x2 = pScreen->width;
     pSprite->hotLimits.y2 = pScreen->height;
     pSprite->win = win;
-    pCursor = wCursor(win);
-    if (pCursor)
-        pCursor->refcnt++;
+    pCursor = RefCursor(wCursor(win));
     if (pSprite->current)
         FreeCursor(pSprite->current, 0);
     pSprite->current = pCursor;
@@ -4942,9 +4938,7 @@ ProcChangeActivePointerGrab(ClientPtr client)
         (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER))
         return Success;
     oldCursor = grab->cursor;
-    grab->cursor = newCursor;
-    if (newCursor)
-        newCursor->refcnt++;
+    grab->cursor = RefCursor(newCursor);
     PostNewCursor(device);
     if (oldCursor)
         FreeCursor(oldCursor, (Cursor) 0);
@@ -5089,9 +5083,7 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev,
         else
             xi2mask_merge(tempGrab->xi2mask, mask->xi2mask);
         tempGrab->device = dev;
-        tempGrab->cursor = cursor;
-        if (cursor)
-            tempGrab->cursor->refcnt++;
+        tempGrab->cursor = RefCursor(cursor);
         tempGrab->confineTo = confineTo;
         tempGrab->grabtype = grabtype;
         (*grabInfo->ActivateGrab) (dev, tempGrab, time, FALSE);
diff --git a/dix/grabs.c b/dix/grabs.c
index b254ddc..a03897a 100644
--- a/dix/grabs.c
+++ b/dix/grabs.c
@@ -241,13 +241,11 @@ CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice,
     grab->detail.exact = keybut;
     grab->detail.pMask = NULL;
     grab->confineTo = confineTo;
-    grab->cursor = cursor;
+    grab->cursor = RefCursor(cursor);
     grab->next = NULL;
 
     if (grabtype == XI2)
         xi2mask_merge(grab->xi2mask, mask->xi2mask);
-    if (cursor)
-        cursor->refcnt++;
     return grab;
 
 }
@@ -274,9 +272,6 @@ CopyGrab(GrabPtr dst, const GrabPtr src)
     Mask *details_mask = NULL;
     XI2Mask *xi2mask;
 
-    if (src->cursor)
-        src->cursor->refcnt++;
-
     if (src->modifiersDetail.pMask) {
         int len = MasksPerDetailMask * sizeof(Mask);
 
@@ -314,6 +309,7 @@ CopyGrab(GrabPtr dst, const GrabPtr src)
     dst->modifiersDetail.pMask = mdetails_mask;
     dst->detail.pMask = details_mask;
     dst->xi2mask = xi2mask;
+    dst->cursor = RefCursor(src->cursor);
 
     xi2mask_merge(dst->xi2mask, src->xi2mask);
 
diff --git a/dix/window.c b/dix/window.c
index a5b28a6..8e61779 100644
--- a/dix/window.c
+++ b/dix/window.c
@@ -547,8 +547,7 @@ InitRootWindow(WindowPtr pWin)
     (*pScreen->PositionWindow) (pWin, 0, 0);
 
     pWin->cursorIsNone = FALSE;
-    pWin->optional->cursor = rootCursor;
-    rootCursor->refcnt++;
+    pWin->optional->cursor = RefCursor(rootCursor);
 
     if (party_like_its_1989) {
         MakeRootTile(pWin);
@@ -1416,8 +1415,7 @@ ChangeWindowAttributes(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client)
                     else if (pWin->parent && pCursor == wCursor(pWin->parent))
                         checkOptional = TRUE;
                     pOldCursor = pWin->optional->cursor;
-                    pWin->optional->cursor = pCursor;
-                    pCursor->refcnt++;
+                    pWin->optional->cursor = RefCursor(pCursor);
                     pWin->cursorIsNone = FALSE;
                     /*
                      * check on any children now matching the new cursor
@@ -3321,8 +3319,7 @@ MakeWindowOptional(WindowPtr pWin)
     parentOptional = FindWindowWithOptional(pWin)->optional;
     optional->visual = parentOptional->visual;
     if (!pWin->cursorIsNone) {
-        optional->cursor = parentOptional->cursor;
-        optional->cursor->refcnt++;
+        optional->cursor = RefCursor(parentOptional->cursor);
     }
     else {
         optional->cursor = None;
@@ -3410,8 +3407,7 @@ ChangeWindowDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev, CursorPtr pCursor)
     if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor))
         pNode->cursor = None;
     else {
-        pNode->cursor = pCursor;
-        pCursor->refcnt++;
+        pNode->cursor = RefCursor(pCursor);
     }
 
     pNode = pPrev = NULL;
@@ -3419,8 +3415,7 @@ ChangeWindowDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev, CursorPtr pCursor)
     for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
         if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev)) {
             if (pNode->cursor == None) {        /* inherited from parent */
-                pNode->cursor = pOldCursor;
-                pOldCursor->refcnt++;
+                pNode->cursor = RefCursor(pOldCursor);
             }
             else if (pNode->cursor == pCursor) {
                 pNode->cursor = None;
diff --git a/hw/xfree86/modes/xf86Cursors.c b/hw/xfree86/modes/xf86Cursors.c
index 634ee3f..2b0db34 100644
--- a/hw/xfree86/modes/xf86Cursors.c
+++ b/hw/xfree86/modes/xf86Cursors.c
@@ -481,7 +481,7 @@ xf86_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
 
-    ++cursor->refcnt;
+    cursor = RefCursor(cursor);
     if (xf86_config->cursor)
         FreeCursor(xf86_config->cursor, None);
     xf86_config->cursor = cursor;
@@ -500,7 +500,7 @@ xf86_use_hw_cursor_argb(ScreenPtr screen, CursorPtr cursor)
     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
 
-    ++cursor->refcnt;
+    cursor = RefCursor(cursor);
     if (xf86_config->cursor)
         FreeCursor(xf86_config->cursor, None);
     xf86_config->cursor = cursor;
diff --git a/hw/xfree86/ramdac/xf86Cursor.c b/hw/xfree86/ramdac/xf86Cursor.c
index 8d48a75..f30bd33 100644
--- a/hw/xfree86/ramdac/xf86Cursor.c
+++ b/hw/xfree86/ramdac/xf86Cursor.c
@@ -272,7 +272,7 @@ xf86CursorRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs)
         (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
                                                xf86CursorScreenKey);
 
-    if (pCurs->refcnt <= 1)
+    if (CursorRefCount(pCurs) <= 1)
         dixSetScreenPrivate(&pCurs->devPrivates, CursorScreenKey, pScreen,
                             NULL);
 
@@ -286,7 +286,7 @@ xf86CursorUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs)
         (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
                                                xf86CursorScreenKey);
 
-    if (pCurs->refcnt <= 1) {
+    if (CursorRefCount(pCurs) <= 1) {
         free(dixLookupScreenPrivate
              (&pCurs->devPrivates, CursorScreenKey, pScreen));
         dixSetScreenPrivate(&pCurs->devPrivates, CursorScreenKey, pScreen,
@@ -323,37 +323,37 @@ xf86CursorSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs,
     /* only update for VCP, otherwise we get cursor jumps when removing a
        sprite. The second cursor is never HW rendered anyway. */
     if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer) {
-        pCurs->refcnt++;
+        CursorPtr cursor = RefCursor(pCurs);
         if (ScreenPriv->CurrentCursor)
             FreeCursor(ScreenPriv->CurrentCursor, None);
-        ScreenPriv->CurrentCursor = pCurs;
+        ScreenPriv->CurrentCursor = cursor;
         ScreenPriv->x = x;
         ScreenPriv->y = y;
         ScreenPriv->CursorToRestore = NULL;
-        ScreenPriv->HotX = pCurs->bits->xhot;
-        ScreenPriv->HotY = pCurs->bits->yhot;
+        ScreenPriv->HotX = cursor->bits->xhot;
+        ScreenPriv->HotY = cursor->bits->yhot;
 
         if (!infoPtr->pScrn->vtSema)
-            ScreenPriv->SavedCursor = pCurs;
+            ScreenPriv->SavedCursor = cursor;
 
         if (infoPtr->pScrn->vtSema && xorg_list_is_empty(&pScreen->pixmap_dirty_list) &&
             (ScreenPriv->ForceHWCursorCount ||
              ((
 #ifdef ARGB_CURSOR
-               pCurs->bits->argb &&
+               cursor->bits->argb &&
                infoPtr->UseHWCursorARGB &&
-               (*infoPtr->UseHWCursorARGB)(pScreen, pCurs)) ||
-              (pCurs->bits->argb == 0 &&
+               (*infoPtr->UseHWCursorARGB)(pScreen, cursor)) ||
+              (cursor->bits->argb == 0 &&
 #endif
-               (pCurs->bits->height <= infoPtr->MaxHeight) &&
-               (pCurs->bits->width <= infoPtr->MaxWidth) &&
-               (!infoPtr->UseHWCursor || (*infoPtr->UseHWCursor) (pScreen, pCurs)))))) {
+               (cursor->bits->height <= infoPtr->MaxHeight) &&
+               (cursor->bits->width <= infoPtr->MaxWidth) &&
+               (!infoPtr->UseHWCursor || (*infoPtr->UseHWCursor) (pScreen, cursor)))))) {
             
             if (ScreenPriv->SWCursor)   /* remove the SW cursor */
                 (*ScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen,
                                                        NullCursor, x, y);
 
-            xf86SetCursor(pScreen, pCurs, x, y);
+            xf86SetCursor(pScreen, cursor, x, y);
             ScreenPriv->SWCursor = FALSE;
             ScreenPriv->isUp = TRUE;
 
diff --git a/include/cursor.h b/include/cursor.h
index 0823251..89a650f 100644
--- a/include/cursor.h
+++ b/include/cursor.h
@@ -71,6 +71,10 @@ extern _X_EXPORT CursorPtr rootCursor;
 extern _X_EXPORT int FreeCursor(pointer /*pCurs */ ,
                                 XID /*cid */ );
 
+extern _X_EXPORT CursorPtr RefCursor(CursorPtr /* cursor */);
+extern _X_EXPORT CursorPtr UnrefCursor(CursorPtr /* cursor */);
+extern _X_EXPORT int CursorRefCount(const CursorPtr /* cursor */);
+
 extern _X_EXPORT int AllocARGBCursor(unsigned char * /*psrcbits */ ,
                                      unsigned char * /*pmaskbits */ ,
                                      CARD32 * /*argb */ ,
diff --git a/render/animcur.c b/render/animcur.c
index 9cbba83..038c5b9 100644
--- a/render/animcur.c
+++ b/render/animcur.c
@@ -383,8 +383,7 @@ AnimCursorCreate(CursorPtr *cursors, CARD32 *deltas, int ncursor,
     ac->elts = (AnimCurElt *) (ac + 1);
 
     for (i = 0; i < ncursor; i++) {
-        cursors[i]->refcnt++;
-        ac->elts[i].pCursor = cursors[i];
+        ac->elts[i].pCursor = RefCursor(cursors[i]);
         ac->elts[i].delay = deltas[i];
     }
 
diff --git a/xfixes/cursor.c b/xfixes/cursor.c
index 568e717..cc6e059 100644
--- a/xfixes/cursor.c
+++ b/xfixes/cursor.c
@@ -619,12 +619,12 @@ ReplaceCursorLookup(pointer value, XID id, pointer closure)
     }
     if (pCursor && pCursor != rcl->pNew) {
         if ((*rcl->testCursor) (pCursor, rcl->closure)) {
-            rcl->pNew->refcnt++;
+            CursorPtr curs = RefCursor(rcl->pNew);
             /* either redirect reference or update resource database */
             if (pCursorRef)
-                *pCursorRef = rcl->pNew;
+                *pCursorRef = curs;
             else
-                ChangeResourceValue(id, RT_CURSOR, rcl->pNew);
+                ChangeResourceValue(id, RT_CURSOR, curs);
             FreeCursor(pCursor, cursor);
         }
     }
commit c0be1168fd3dd2eb01187789ddc30d7aab909a98
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue May 14 14:51:31 2013 +1000

    dix: call UpdateDeviceState() for emulated TouchEndEvents
    
    ProcessTouchEvents() calls UDS for all touch events, but if the event type
    was switched to TouchUpdate(pending end) UDS is a noop.
    
    Daniel Drake found this can cause stuck buttons if a touch grab is
    activated, rejected and the touch event is passed to a regular listener.
    This sequence causes the TouchEnd to be changed to TouchUpdate(pending end).
    
    The actual TouchEnd event is later generated by the server once it is passed
    to the next listener. UDS is never called for this event, thus the button
    remains logically down.
    
    A previous patch suggested for UDS to handle TouchUpdate events [1], however
    this would release the button when the first TouchEvent is processed, not
    when the last grab has been released (as is the case for sync pointer
    grabs). A client may thus have the grab on the device, receive a ButtonPress
    but see the button logically up in an XQueryPointer request.
    
    This patch adds a call to UDS to TouchEmitTouchEnd(). The device state must
    be updated once a TouchEnd event was sent to the last grabbing listener and
    the number of grabs on the touchpoint is 0.
    
    [1] http://patchwork.freedesktop.org/patch/13464/
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 35c2e263db01b2b61354298e5e85aa3cae8ac317)

diff --git a/dix/touch.c b/dix/touch.c
index 110b1cc..a4b6d7e 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -1122,6 +1122,8 @@ TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resourc
     TouchDeliverDeviceClassesChangedEvent(ti, GetTimeInMillis(), resource);
     GetDixTouchEnd(&event, dev, ti, flags);
     DeliverTouchEvents(dev, ti, &event, resource);
+    if (ti->num_grabs == 0)
+        UpdateDeviceState(dev, &event.device_event);
 }
 
 void
commit 5c32bd0e2c104deaa2820c62289916fff6a4e3cd
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri May 3 15:07:58 2013 +1000

    dix: fix cursor refcounting
    
    The cursor is referenced during CopyGrab(), thus doesn't need to be handled
    manually anymore. It does need to be refcounted for temp grabs though.
    
    The oldGrab handling in ProcGrabPointer is a leftover from the cursor in the
    grab being refcounted, but the grab itself being a static struct in the
    DeviceIntRec. Now that all grabs are copied, this lead to a double-free of
    the cursor (Reproduced in Thunderbird, dragging an email twice (or more
    often) causes a crash).
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 481702101b86fff003430e952dc65fb41eb56400)

diff --git a/dix/events.c b/dix/events.c
index 24fd6b9..64a8f15 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1488,9 +1488,6 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
         grabinfo->grabTime = syncEvents.time;
     else
         grabinfo->grabTime = time;
-    if (grab->cursor)
-        grab->cursor->refcnt++;
-    BUG_WARN(grabinfo->grab != NULL);
     grabinfo->grab = AllocGrab(grab);
     grabinfo->fromPassiveGrab = isPassive;
     grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
@@ -1549,8 +1546,6 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
     if (grab->confineTo)
         ConfineCursorToWindow(mouse, GetCurrentRootWindow(mouse), FALSE, FALSE);
     PostNewCursor(mouse);
-    if (grab->cursor)
-        FreeCursor(grab->cursor, (Cursor) 0);
 
     if (!wasImplicit && grab->grabtype == XI2)
         ReattachToOldMaster(mouse);
@@ -4857,7 +4852,6 @@ ProcGrabPointer(ClientPtr client)
     GrabPtr grab;
     GrabMask mask;
     WindowPtr confineTo;
-    CursorPtr oldCursor;
     BYTE status;
 
     REQUEST(xGrabPointerReq);
@@ -4880,15 +4874,10 @@ ProcGrabPointer(ClientPtr client)
             return rc;
     }
 
-    oldCursor = NullCursor;
     grab = device->deviceGrab.grab;
 
-    if (grab) {
-        if (grab->confineTo && !confineTo)
-            ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE,
-                                  FALSE);
-        oldCursor = grab->cursor;
-    }
+    if (grab && grab->confineTo && !confineTo)
+        ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE, FALSE);
 
     mask.core = stuff->eventMask;
 
@@ -4898,9 +4887,6 @@ ProcGrabPointer(ClientPtr client)
     if (rc != Success)
         return rc;
 
-    if (oldCursor && status == GrabSuccess)
-        FreeCursor(oldCursor, (Cursor) 0);
-
     rep = (xGrabPointerReply) {
         .type = X_Reply,
         .status = status,
@@ -5104,6 +5090,8 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev,
             xi2mask_merge(tempGrab->xi2mask, mask->xi2mask);
         tempGrab->device = dev;
         tempGrab->cursor = cursor;
+        if (cursor)
+            tempGrab->cursor->refcnt++;
         tempGrab->confineTo = confineTo;
         tempGrab->grabtype = grabtype;
         (*grabInfo->ActivateGrab) (dev, tempGrab, time, FALSE);
commit 0ee9704f3c70fa7cf77edef55d158ad78df72a25
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri May 3 15:02:05 2013 +1000

    dix: free the old grab when activating a new grab
    
    A client may call XIGrabDevice twice, overwriting the existing grab. Thus,
    make sure we free the old copy after we copied it. Free it last, to make
    sure our refcounts don't run to 0 and inadvertantly free something on the
    way.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 3093f78d17e48a506aab170a9089cd10e21af299)

diff --git a/dix/events.c b/dix/events.c
index 8745c11..24fd6b9 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1465,6 +1465,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
                     TimeStamp time, Bool autoGrab)
 {
     GrabInfoPtr grabinfo = &mouse->deviceGrab;
+    GrabPtr oldgrab = grabinfo->grab;
     WindowPtr oldWin = (grabinfo->grab) ?
         grabinfo->grab->window : mouse->spriteInfo->sprite->win;
     Bool isPassive = autoGrab & ~ImplicitGrabMask;
@@ -1497,6 +1498,8 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
     UpdateTouchesForGrab(mouse);
     CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
                       (Bool) grab->keyboardMode);
+    if (oldgrab)
+        FreeGrab(oldgrab);
 }
 
 /**
@@ -1567,6 +1570,7 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time,
                      Bool passive)
 {
     GrabInfoPtr grabinfo = &keybd->deviceGrab;
+    GrabPtr oldgrab = grabinfo->grab;
     WindowPtr oldWin;
 
     /* slave devices need to float for the duration of the grab. */
@@ -1592,12 +1596,13 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time,
         grabinfo->grabTime = syncEvents.time;
     else
         grabinfo->grabTime = time;
-    BUG_WARN(grabinfo->grab != NULL);
     grabinfo->grab = AllocGrab(grab);
     grabinfo->fromPassiveGrab = passive;
     grabinfo->implicitGrab = passive & ImplicitGrabMask;
     CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode,
                       (Bool) grab->pointerMode);
+    if (oldgrab)
+        FreeGrab(oldgrab);
 }
 
 /**
commit ef0fff102d1feb5bccffc918da5c0dc7c0d28f3b
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Apr 24 14:46:06 2013 +1000

    Xi: check for HAS_ACCEPTED only for grab listeners
    
    If we have one listener left but it's not a grab, it cannot be in
    LISTENER_HAS_ACCEPTED state.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 2566bdd8bc996cccde77b846819808c6239a89d2)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 90cbcc5..e1945b9 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1917,7 +1917,7 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
             rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
 
         if ((ti->num_listeners > 1 ||
-             listener->state != LISTENER_HAS_ACCEPTED) &&
+             (ti->num_grabs > 0 && listener->state != LISTENER_HAS_ACCEPTED)) &&
             (ev->device_event.flags & (TOUCH_ACCEPT | TOUCH_REJECT)) == 0) {
             ev->any.type = ET_TouchUpdate;
             ev->device_event.flags |= TOUCH_PENDING_END;
commit f3d63710d57aea0184ae07f0422a76b0fd6d415f
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Apr 24 14:40:31 2013 +1000

    Move TouchListenerGone call to CloseDownClient
    
    TouchListenerGone cleans up if a client disappears. Having this in
    FreeGrab() triggers cyclic removal of grabs, emitting wrong events. In
    particular, it would clean up a passive grab record while that grab is
    active.
    
    Move it to CloseDownClient() instead, cleaning up before we go.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 5b00fc52270e9cfdfe7ac1838a21defe50fc3d31)

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 8d61735..20f2414 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -3398,6 +3398,7 @@ CloseDownClient(ClientPtr client)
             clientinfo.setup = (xConnSetup *) NULL;
             CallCallbacks((&ClientStateCallback), (pointer) &clientinfo);
         }
+        TouchListenerGone(client->clientAsMask);
         FreeClientResources(client);
         /* Disable client ID tracking. This must be done after
          * ClientStateCallback. */
diff --git a/dix/grabs.c b/dix/grabs.c
index f46a6b2..b254ddc 100644
--- a/dix/grabs.c
+++ b/dix/grabs.c
@@ -257,9 +257,6 @@ FreeGrab(GrabPtr pGrab)
 {
     BUG_RETURN(!pGrab);
 
-    if (pGrab->grabtype == XI2 && pGrab->type == XI_TouchBegin)
-        TouchListenerGone(pGrab->resource);
-
     free(pGrab->modifiersDetail.pMask);
     free(pGrab->detail.pMask);
 
diff --git a/dix/touch.c b/dix/touch.c
index 0099914..110b1cc 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -989,11 +989,11 @@ TouchListenerGone(XID resource)
                 continue;
 
             for (j = 0; j < ti->num_listeners; j++) {
-                if (ti->listeners[j].listener != resource)
+                if (CLIENT_BITS(ti->listeners[j].listener) != resource)
                     continue;
 
                 nev = GetTouchOwnershipEvents(events, dev, ti, XIRejectTouch,
-                                              resource, 0);
+                                              ti->listeners[j].listener, 0);
                 for (k = 0; k < nev; k++)
                     mieqProcessDeviceEvent(dev, events + k, NULL);
 
commit 6c880c143f6a32d3bbc529e4a0ab1663ddecf0a0
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Apr 24 12:53:52 2013 +1000

    dix: remove all listeners when freeing a touch
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 34c9b39d9937c2e19c2dffc9748605f90d40f965)

diff --git a/dix/touch.c b/dix/touch.c
index fb218d4..0099914 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -263,6 +263,7 @@ void
 TouchFreeTouchPoint(DeviceIntPtr device, int index)
 {
     TouchPointInfoPtr ti;
+    int i;
 
     if (!device->touch || index >= device->touch->num_touches)
         return;
@@ -271,6 +272,9 @@ TouchFreeTouchPoint(DeviceIntPtr device, int index)
     if (ti->active)
         TouchEndTouch(device, ti);
 
+    for (i = 0; i < ti->num_listeners; i++)
+        TouchRemoveListener(ti, ti->listeners[0].listener);
+
     valuator_mask_free(&ti->valuators);
     free(ti->sprite.spriteTrace);
     ti->sprite.spriteTrace = NULL;
commit ab76a3a3fc56cf8f530e5ab9b6389b09da1cdc12
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Apr 17 20:15:35 2013 +1000

    dix: always copy grabs, don't reference them
    
    Introduced in xorg-server-1.13.99.901-2-g9ad0fdb. Storing the grab pointer
    in the listener turns out to be a bad idea. If the grab is not an active
    grab or an implicit grab, the pointer stored is the one to the grab attached
    on the window. This grab may be removed if the client calls UngrabButton or
    similar while the touch is still active, leaving a dangling pointer.
    
    To avoid this, copy the grab wherever we need to reference it later. This
    is also what we do for pointer/keyboard grabs, where we copy the grab as
    soon as it becomes active.
    
    Reported-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 395124bd2782823de37e5c5b2f15dba49cff05f6)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index ff32e02..90cbcc5 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1429,8 +1429,11 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
          */
         if (!devgrab && dev->deviceGrab.grab && dev->deviceGrab.implicitGrab) {
             TouchListener *l;
+            GrabPtr g;
 
             devgrab = dev->deviceGrab.grab;
+            g = AllocGrab(devgrab);
+            BUG_WARN(!g);
 
             *dev->deviceGrab.sync.event = ev->device_event;
 
@@ -1439,8 +1442,8 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
              * event selection. Thus, we update the last listener in the array.
              */
             l = &ti->listeners[ti->num_listeners - 1];
-            l->listener = devgrab->resource;
-            l->grab = devgrab;
+            l->listener = g->resource;
+            l->grab = g;
             //l->resource_type = RT_NONE;
 
             if (devgrab->grabtype != XI2 || devgrab->type != XI_TouchBegin)
diff --git a/dix/events.c b/dix/events.c
index 6a8e7a6..8745c11 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1439,7 +1439,8 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
                 listener->type = LISTENER_POINTER_GRAB;
             else
                 listener->type = LISTENER_GRAB;
-            listener->grab = grab;
+            FreeGrab(listener->grab);
+            listener->grab = AllocGrab(grab);
         }
     }
 }
diff --git a/dix/touch.c b/dix/touch.c
index 01a554e..fb218d4 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -365,6 +365,8 @@ TouchBeginTouch(DeviceIntPtr dev, int sourceid, uint32_t touchid,
 void
 TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
 {
+    int i;
+
     if (ti->emulate_pointer) {
         GrabPtr grab;
 
@@ -376,6 +378,9 @@ TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
         }
     }
 
+    for (i = 0; i < ti->num_listeners; i++)
+        TouchRemoveListener(ti, ti->listeners[0].listener);
+
     ti->active = FALSE;
     ti->pending_finish = FALSE;
     ti->sprite.spriteTraceGood = 0;
@@ -692,15 +697,23 @@ void
 TouchAddListener(TouchPointInfoPtr ti, XID resource, int resource_type,
                  enum InputLevel level, enum TouchListenerType type,
                  enum TouchListenerState state, WindowPtr window,
-                 GrabPtr grab)
+                 const GrabPtr grab)
 {
+    GrabPtr g = NULL;
+
+    /* We need a copy of the grab, not the grab itself since that may be
+     * deleted by a UngrabButton request and leaves us with a dangling
+     * pointer */
+    if (grab)
+        g = AllocGrab(grab);
+
     ti->listeners[ti->num_listeners].listener = resource;
     ti->listeners[ti->num_listeners].resource_type = resource_type;
     ti->listeners[ti->num_listeners].level = level;
     ti->listeners[ti->num_listeners].state = state;
     ti->listeners[ti->num_listeners].type = type;
     ti->listeners[ti->num_listeners].window = window;
-    ti->listeners[ti->num_listeners].grab = grab;
+    ti->listeners[ti->num_listeners].grab = g;
     if (grab)
         ti->num_grabs++;
     ti->num_listeners++;
@@ -725,6 +738,7 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource)
             continue;
 
         if (listener->grab) {
+            FreeGrab(listener->grab);
             listener->grab = NULL;
             ti->num_grabs--;
         }
@@ -734,6 +748,7 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource)
         ti->num_listeners--;
         ti->listeners[ti->num_listeners].listener = 0;
         ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN;
+
         return TRUE;
     }
     return FALSE;
commit 6bd9badc780ec9d1fb147dfa0c671979c75b722c
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Apr 23 15:52:18 2013 +1000

    dix: AllocGrab can copy if an argument is passed in
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 925e35122ebad877395bcf13676e9dbeb254bdfa)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index c33a922..ff32e02 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -2845,7 +2845,7 @@ CheckDeviceGrabAndHintWindow(WindowPtr pWin, int type,
              (deliveryMask & DeviceButtonGrabMask)) {
         GrabPtr tempGrab;
 
-        tempGrab = AllocGrab();
+        tempGrab = AllocGrab(NULL);
         if (!tempGrab)
             return;
 
diff --git a/Xi/ungrdevb.c b/Xi/ungrdevb.c
index c4632fa..b02510e 100644
--- a/Xi/ungrdevb.c
+++ b/Xi/ungrdevb.c
@@ -127,7 +127,7 @@ ProcXUngrabDeviceButton(ClientPtr client)
         (stuff->modifiers & ~AllModifiersMask))
         return BadValue;
 
-    temporaryGrab = AllocGrab();
+    temporaryGrab = AllocGrab(NULL);
     if (!temporaryGrab)
         return BadAlloc;
 
diff --git a/Xi/ungrdevk.c b/Xi/ungrdevk.c
index 3273878..f981171 100644
--- a/Xi/ungrdevk.c
+++ b/Xi/ungrdevk.c
@@ -134,7 +134,7 @@ ProcXUngrabDeviceKey(ClientPtr client)
         (stuff->modifiers & ~AllModifiersMask))
         return BadValue;
 
-    temporaryGrab = AllocGrab();
+    temporaryGrab = AllocGrab(NULL);
     if (!temporaryGrab)
         return BadAlloc;
 
diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c
index 62a3a46..eccec0a 100644
--- a/Xi/xipassivegrab.c
+++ b/Xi/xipassivegrab.c
@@ -307,7 +307,7 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
 
     mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD);
 
-    tempGrab = AllocGrab();
+    tempGrab = AllocGrab(NULL);
     if (!tempGrab)
         return BadAlloc;
 
diff --git a/dix/events.c b/dix/events.c
index 0216502..6a8e7a6 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1489,8 +1489,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
     if (grab->cursor)
         grab->cursor->refcnt++;
     BUG_WARN(grabinfo->grab != NULL);
-    grabinfo->grab = AllocGrab();
-    CopyGrab(grabinfo->grab, grab);
+    grabinfo->grab = AllocGrab(grab);
     grabinfo->fromPassiveGrab = isPassive;
     grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
     PostNewCursor(mouse);
@@ -1593,8 +1592,7 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time,
     else
         grabinfo->grabTime = time;
     BUG_WARN(grabinfo->grab != NULL);
-    grabinfo->grab = AllocGrab();
-    CopyGrab(grabinfo->grab, grab);
+    grabinfo->grab = AllocGrab(grab);
     grabinfo->fromPassiveGrab = passive;
     grabinfo->implicitGrab = passive & ImplicitGrabMask;
     CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode,
@@ -1988,7 +1986,7 @@ ActivateImplicitGrab(DeviceIntPtr dev, ClientPtr client, WindowPtr win,
     else
         return FALSE;
 
-    tempGrab = AllocGrab();
+    tempGrab = AllocGrab(NULL);
     if (!tempGrab)
         return FALSE;
     tempGrab->next = NULL;
@@ -3895,7 +3893,7 @@ CheckPassiveGrabsOnWindow(WindowPtr pWin,
     if (!grab)
         return NULL;
 
-    tempGrab = AllocGrab();
+    tempGrab = AllocGrab(NULL);
 
     /* Fill out the grab details, but leave the type for later before
      * comparing */
@@ -5084,7 +5082,7 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev,
     else {
         GrabPtr tempGrab;
 
-        tempGrab = AllocGrab();
+        tempGrab = AllocGrab(NULL);
 
         tempGrab->next = NULL;
         tempGrab->window = pWin;
@@ -5440,7 +5438,7 @@ ProcUngrabKey(ClientPtr client)
         client->errorValue = stuff->modifiers;
         return BadValue;
     }
-    tempGrab = AllocGrab();
+    tempGrab = AllocGrab(NULL);
     if (!tempGrab)
         return BadAlloc;
     tempGrab->resource = client->clientAsMask;
@@ -5634,7 +5632,7 @@ ProcUngrabButton(ClientPtr client)
 
     ptr = PickPointer(client);
 
-    tempGrab = AllocGrab();
+    tempGrab = AllocGrab(NULL);
     if (!tempGrab)
         return BadAlloc;
     tempGrab->resource = client->clientAsMask;
diff --git a/dix/grabs.c b/dix/grabs.c
index 0a2111d..f46a6b2 100644
--- a/dix/grabs.c
+++ b/dix/grabs.c
@@ -189,7 +189,7 @@ UngrabAllDevices(Bool kill_client)
 }
 
 GrabPtr
-AllocGrab(void)
+AllocGrab(const GrabPtr src)
 {
     GrabPtr grab = calloc(1, sizeof(GrabRec));
 
@@ -201,6 +201,12 @@ AllocGrab(void)
         }
     }
 
+    if (src && !CopyGrab(grab, src)) {
+        free(grab->xi2mask);
+        free(grab);
+        grab = NULL;
+    }
+
     return grab;
 }
 
@@ -213,7 +219,7 @@ CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice,
 {
     GrabPtr grab;
 
-    grab = AllocGrab();
+    grab = AllocGrab(NULL);
     if (!grab)
         return (GrabPtr) NULL;
     grab->resource = FakeClientID(client);
diff --git a/include/dixgrabs.h b/include/dixgrabs.h
index eccec77..ca3c95b 100644
--- a/include/dixgrabs.h
+++ b/include/dixgrabs.h
@@ -31,7 +31,7 @@ struct _GrabParameters;
 extern void PrintDeviceGrabInfo(DeviceIntPtr dev);
 extern void UngrabAllDevices(Bool kill_client);
 
-extern GrabPtr AllocGrab(void);
+extern GrabPtr AllocGrab(const GrabPtr src);
 extern void FreeGrab(GrabPtr grab);
 extern Bool CopyGrab(GrabPtr dst, const GrabPtr src);
 
commit 479f8bf236d17e2a2093d349d2ef6471ff089a53
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Apr 23 15:46:04 2013 +1000

    dix: freeing a null grab is a bug, complain if doing so
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 4980bcef9973ba1f90f53028f061669ee5d2661b)

diff --git a/dix/grabs.c b/dix/grabs.c
index 3b02352..0a2111d 100644
--- a/dix/grabs.c
+++ b/dix/grabs.c
@@ -249,6 +249,8 @@ CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice,
 void
 FreeGrab(GrabPtr pGrab)
 {
+    BUG_RETURN(!pGrab);
+
     if (pGrab->grabtype == XI2 && pGrab->type == XI_TouchBegin)
         TouchListenerGone(pGrab->resource);
 
commit 27752301377698124634d48b62ba7fcf8310caab
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Apr 23 15:39:32 2013 +1000

    dix: use a temporary variable for listeners[0]
    
    no functional changes
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit ccfa0f2d5de557546815a5e4f59552e2af46b578)

diff --git a/dix/events.c b/dix/events.c
index 9ac8792..0216502 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1424,21 +1424,22 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
 
     for (i = 0; i < mouse->touch->num_touches; i++) {
         TouchPointInfoPtr ti = mouse->touch->touches + i;
+        TouchListener *listener = &ti->listeners[0];
         GrabPtr grab = mouse->deviceGrab.grab;
 
         if (ti->active &&
-            CLIENT_BITS(ti->listeners[0].listener) == grab->resource) {
-            ti->listeners[0].listener = grab->resource;
-            ti->listeners[0].level = grab->grabtype;
-            ti->listeners[0].state = LISTENER_IS_OWNER;
-            ti->listeners[0].window = grab->window;
+            CLIENT_BITS(listener->listener) == grab->resource) {
+            listener->listener = grab->resource;
+            listener->level = grab->grabtype;
+            listener->state = LISTENER_IS_OWNER;
+            listener->window = grab->window;
 
             if (grab->grabtype == CORE || grab->grabtype == XI ||
                 !xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin))
-                ti->listeners[0].type = LISTENER_POINTER_GRAB;
+                listener->type = LISTENER_POINTER_GRAB;
             else
-                ti->listeners[0].type = LISTENER_GRAB;
-            ti->listeners[0].grab = grab;
+                listener->type = LISTENER_GRAB;
+            listener->grab = grab;
         }
     }
 }
commit d8c0cc9bab1fe159f58c2b5e8056c2d94a623789
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Apr 18 10:32:11 2013 +1000

    dix: drop DeviceIntRec's activeGrab struct
    
    Obsolete since 4bc2761ad5ec2d0668aec639780ffb136605fbc8. This struct
    existed so copying a passive grab could be simply done by
      activeGrab = *grab
    
    and thus have a copy of the GrabPtr we'd get from various sources but still
    be able to check device->grab for NULL.
    
    Since 4bc2761 activeGrab is a pointer itself and points to the same memory
    as grabinfo->grab, leaving us with the potential of dangling pointers if
    either calls FreeGrab() and doesn't reset the other one.
    
    There is no reader of activeGrab anyway, so simply removing it is
    sufficient.
    
    Note: field is merely renamed to keep the ABI. Should be removed in the
    future.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 5363433a5cc64e2f83859aa1c32a89e5e1ddf9e4)

diff --git a/dix/devices.c b/dix/devices.c
index a0d545a..9ef32bb 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -281,7 +281,6 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart)
     dev->deviceGrab.grabTime = currentTime;
     dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
     dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
-    dev->deviceGrab.activeGrab = AllocGrab();
     dev->deviceGrab.sync.event = calloc(1, sizeof(DeviceEvent));
 
     XkbSetExtension(dev, ProcessKeyboardEvent);
@@ -977,7 +976,8 @@ CloseDevice(DeviceIntPtr dev)
         }
     }
 
-    FreeGrab(dev->deviceGrab.activeGrab);
+    if (dev->deviceGrab.grab)
+        FreeGrab(dev->deviceGrab.grab);
     free(dev->deviceGrab.sync.event);
     free(dev->config_info);     /* Allocated in xf86ActivateDevice. */
     free(dev->last.scroll);
diff --git a/dix/events.c b/dix/events.c
index 7772c0b..9ac8792 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1487,8 +1487,9 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
         grabinfo->grabTime = time;
     if (grab->cursor)
         grab->cursor->refcnt++;
-    CopyGrab(grabinfo->activeGrab, grab);
-    grabinfo->grab = grabinfo->activeGrab;
+    BUG_WARN(grabinfo->grab != NULL);
+    grabinfo->grab = AllocGrab();
+    CopyGrab(grabinfo->grab, grab);
     grabinfo->fromPassiveGrab = isPassive;
     grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
     PostNewCursor(mouse);
@@ -1551,6 +1552,8 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
         ReattachToOldMaster(mouse);
 
     ComputeFreezes();
+
+    FreeGrab(grab);
 }
 
 /**
@@ -1588,8 +1591,9 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time,
         grabinfo->grabTime = syncEvents.time;
     else
         grabinfo->grabTime = time;
-    CopyGrab(grabinfo->activeGrab, grab);
-    grabinfo->grab = grabinfo->activeGrab;
+    BUG_WARN(grabinfo->grab != NULL);
+    grabinfo->grab = AllocGrab();
+    CopyGrab(grabinfo->grab, grab);
     grabinfo->fromPassiveGrab = passive;
     grabinfo->implicitGrab = passive & ImplicitGrabMask;
     CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode,
@@ -1635,6 +1639,8 @@ DeactivateKeyboardGrab(DeviceIntPtr keybd)
         ReattachToOldMaster(keybd);
 
     ComputeFreezes();
+
+    FreeGrab(grab);
 }
 
 void
diff --git a/include/inputstr.h b/include/inputstr.h
index de96fae..85be885 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -485,7 +485,7 @@ typedef struct _GrabInfoRec {
     TimeStamp grabTime;
     Bool fromPassiveGrab;       /* true if from passive grab */
     Bool implicitGrab;          /* implicit from ButtonPress */
-    GrabPtr activeGrab;
+    GrabPtr unused;             /* Kept for ABI stability, remove soon */
     GrabPtr grab;
     CARD8 activatingKey;
     void (*ActivateGrab) (DeviceIntPtr /*device */ ,
commit 25b641bb324c33226313c15448592b785043eaba
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Apr 17 20:14:56 2013 +1000

    dix: use a tmp variable for the to-be-removed touch listener
    
    No functional changes.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 7dbf61817d3bd4b1fc71710677e56c5d8cfcdb4e)

diff --git a/dix/touch.c b/dix/touch.c
index be4a7de..01a554e 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -719,12 +719,13 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource)
 
     for (i = 0; i < ti->num_listeners; i++) {
         int j;
+        TouchListener *listener = &ti->listeners[i];
 
-        if (ti->listeners[i].listener != resource)
+        if (listener->listener != resource)
             continue;
 
-        if (ti->listeners[i].grab) {
-            ti->listeners[i].grab = NULL;
+        if (listener->grab) {
+            listener->grab = NULL;
             ti->num_grabs--;
         }
 
commit 88273287e1d7b3c06313f77d450f87a31bf53780
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Apr 17 20:13:34 2013 +1000

    dix: invert a loop condition
    
    Change the single if condition in the loop body to a
        if (!foo) continue;
    and re-indent the rest.
    
    No functional changes.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit a71a283934406d870bcd8dc376eb1c9ce1c8bbb4)

diff --git a/dix/touch.c b/dix/touch.c
index 0cbc2eb..be4a7de 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -718,21 +718,22 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource)
     int i;
 
     for (i = 0; i < ti->num_listeners; i++) {
-        if (ti->listeners[i].listener == resource) {
-            int j;
+        int j;
 
-            if (ti->listeners[i].grab) {
-                ti->listeners[i].grab = NULL;
-                ti->num_grabs--;
-            }
+        if (ti->listeners[i].listener != resource)
+            continue;
 
-            for (j = i; j < ti->num_listeners - 1; j++)
-                ti->listeners[j] = ti->listeners[j + 1];
-            ti->num_listeners--;
-            ti->listeners[ti->num_listeners].listener = 0;
-            ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN;
-            return TRUE;
+        if (ti->listeners[i].grab) {
+            ti->listeners[i].grab = NULL;
+            ti->num_grabs--;
         }
+
+        for (j = i; j < ti->num_listeners - 1; j++)
+            ti->listeners[j] = ti->listeners[j + 1];
+        ti->num_listeners--;
+        ti->listeners[ti->num_listeners].listener = 0;
+        ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN;
+        return TRUE;
     }
     return FALSE;
 }
commit 4081b00d36d074eedf5c8d04196998d23cff28cf
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Feb 28 11:02:40 2013 +1000

    dix: XAllowEvents() on a touch event means accepting it
    
    A sync grab is the owner once it gets events. If it doesn't replay the
    event it will get all events from this touch, equivalent to accepting it.
    
    If the touch has ended before XAllowEvents() is called, we also now need to
    send the TouchEnd event and clean-up since we won't see anything more from
    this touch.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 5174b1f98204beee79eba74c4cda5f2be0a60a8f)

diff --git a/dix/events.c b/dix/events.c
index 2682ecd..7772c0b 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1739,6 +1739,16 @@ AllowSome(ClientPtr client, TimeStamp time, DeviceIntPtr thisDev, int newState)
         }
         break;
     }
+
+    /* We've unfrozen the grab. If the grab was a touch grab, we're now the
+     * owner and expected to accept/reject it. Reject == ReplayPointer which
+     * we've handled in ComputeFreezes() (during DeactivateGrab) above,
+     * anything else is accept.
+     */
+    if (newState != NOT_GRABBED /* Replay */ &&
+        IsTouchEvent((InternalEvent*)grabinfo->sync.event)) {
+        TouchAcceptAndEnd(thisDev, grabinfo->sync.event->touchid);
+    }
 }
 
 /**
diff --git a/dix/touch.c b/dix/touch.c
index f7112fc..0cbc2eb 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -1102,3 +1102,17 @@ TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resourc
     GetDixTouchEnd(&event, dev, ti, flags);
     DeliverTouchEvents(dev, ti, &event, resource);
 }
+
+void
+TouchAcceptAndEnd(DeviceIntPtr dev, int touchid)
+{
+    TouchPointInfoPtr ti = TouchFindByClientID(dev, touchid);
+    if (!ti)
+        return;
+
+    TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
+    if (ti->pending_finish)
+        TouchEmitTouchEnd(dev, ti, 0, 0);
+    if (ti->num_listeners <= 1)
+        TouchEndTouch(dev, ti);
+}
diff --git a/include/input.h b/include/input.h
index 866879b..7eed60b 100644
--- a/include/input.h
+++ b/include/input.h
@@ -591,6 +591,7 @@ extern void TouchEndPhysicallyActiveTouches(DeviceIntPtr dev);
 extern void TouchDeliverDeviceClassesChangedEvent(TouchPointInfoPtr ti,
                                                   Time time, XID resource);
 extern void TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource);
+extern void TouchAcceptAndEnd(DeviceIntPtr dev, int touchid);
 
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent *ev, InputClientsPtr clients);
commit 8666395484d0ff68526b1afd0044329ca3e9c907
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Mar 1 12:52:35 2013 +1000

    dix: move EmitTouchEnd to touch.c
    
    No functional changes, this just enables it to be re-used easier.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit e7f79c48b0faea910dc881034c00eb807fcd6210)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 10fb810..c33a922 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1053,33 +1053,6 @@ ActivateEarlyAccept(DeviceIntPtr dev, TouchPointInfoPtr ti)
 }
 
 /**
- * Generate and deliver a TouchEnd event.
- *
- * @param dev The device to deliver the event for.
- * @param ti The touch point record to deliver the event for.
- * @param flags Internal event flags. The called does not need to provide
- *        TOUCH_CLIENT_ID and TOUCH_POINTER_EMULATED, this function will ensure
- *        they are set appropriately.
- * @param resource The client resource to deliver to, or 0 for all clients.
- */
-static void
-EmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource)
-{
-    InternalEvent event;
-
-    /* We're not processing a touch end for a frozen device */
-    if (dev->deviceGrab.sync.frozen)
-        return;
-
-    flags |= TOUCH_CLIENT_ID;
-    if (ti->emulate_pointer)
-        flags |= TOUCH_POINTER_EMULATED;
-    TouchDeliverDeviceClassesChangedEvent(ti, GetTimeInMillis(), resource);
-    GetDixTouchEnd(&event, dev, ti, flags);
-    DeliverTouchEvents(dev, ti, &event, resource);
-}
-
-/**
  * Find the oldest touch that still has a pointer emulation client.
  *
  * Pointer emulation can only be performed for the oldest touch. Otherwise, the
@@ -1150,7 +1123,7 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
     /* New owner has Begin/Update but not end. If touch is pending_finish,
      * emulate the TouchEnd now */
     if (ti->pending_finish) {
-        EmitTouchEnd(dev, ti, 0, 0);
+        TouchEmitTouchEnd(dev, ti, 0, 0);
 
         /* If the last owner is not a touch grab, finalise the touch, we
            won't get more correspondence on this.
@@ -1208,7 +1181,7 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource,
     for (i = 0; i < ti->num_listeners; i++) {
         if (ti->listeners[i].listener == resource) {
             if (ti->listeners[i].state != LISTENER_HAS_END)
-                EmitTouchEnd(sourcedev, ti, TOUCH_REJECT, resource);
+                TouchEmitTouchEnd(sourcedev, ti, TOUCH_REJECT, resource);
             break;
         }
     }
@@ -1255,12 +1228,12 @@ ProcessTouchOwnershipEvent(TouchOwnershipEvent *ev,
          * already seen the end. This ensures that the touch record is ended in
          * the server. */
         if (ti->listeners[0].state == LISTENER_HAS_END)
-            EmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[0].listener);
+            TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[0].listener);
 
         /* The touch owner has accepted the touch.  Send TouchEnd events to
          * everyone else, and truncate the list of listeners. */
         for (i = 1; i < ti->num_listeners; i++)
-            EmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[i].listener);
+            TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[i].listener);
 
         while (ti->num_listeners > 1)
             TouchRemoveListener(ti, ti->listeners[1].listener);
diff --git a/dix/touch.c b/dix/touch.c
index 76592e7..f7112fc 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -1075,3 +1075,30 @@ TouchEndPhysicallyActiveTouches(DeviceIntPtr dev)
 
     FreeEventList(eventlist, GetMaximumEventsNum());
 }
+
+/**
+ * Generate and deliver a TouchEnd event.
+ *
+ * @param dev The device to deliver the event for.
+ * @param ti The touch point record to deliver the event for.
+ * @param flags Internal event flags. The called does not need to provide
+ *        TOUCH_CLIENT_ID and TOUCH_POINTER_EMULATED, this function will ensure
+ *        they are set appropriately.
+ * @param resource The client resource to deliver to, or 0 for all clients.
+ */
+void
+TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource)
+{
+    InternalEvent event;
+
+    /* We're not processing a touch end for a frozen device */
+    if (dev->deviceGrab.sync.frozen)
+        return;
+
+    flags |= TOUCH_CLIENT_ID;
+    if (ti->emulate_pointer)
+        flags |= TOUCH_POINTER_EMULATED;
+    TouchDeliverDeviceClassesChangedEvent(ti, GetTimeInMillis(), resource);
+    GetDixTouchEnd(&event, dev, ti, flags);
+    DeliverTouchEvents(dev, ti, &event, resource);
+}
diff --git a/include/input.h b/include/input.h
index 5c65597..866879b 100644
--- a/include/input.h
+++ b/include/input.h
@@ -590,6 +590,7 @@ extern int TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
 extern void TouchEndPhysicallyActiveTouches(DeviceIntPtr dev);
 extern void TouchDeliverDeviceClassesChangedEvent(TouchPointInfoPtr ti,
                                                   Time time, XID resource);
+extern void TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource);
 
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent *ev, InputClientsPtr clients);
commit 4dac09796ca7ec19c1a9b17f338babd51c999e2e
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Mar 1 10:41:01 2013 +1000

    Xi: Don't emit a TouchEnd event to a frozen device
    
    EmitTouchEnd calls DeliverTouchEvents directly instead of through
    public.processInputProc. If a device is frozen, the TouchEnd is
    processed while the device is waiting for a XAllowEvents and thus ends the
    touch point (and the grab) before the client decided what to do with it. In
    the case of ReplayPointer, this loses the event.
    
    This is a hack, but making EmitTouchEnd use processInputProc breaks
    approximately everything, especially the touch point is cleaned up during
    ProcessTouchEvents. Working around that is a bigger hack than this.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 0eb9390f6048049136347d5a5834d88bfc67cc09)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 7975a40..10fb810 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1067,6 +1067,10 @@ EmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource)
 {
     InternalEvent event;
 
+    /* We're not processing a touch end for a frozen device */
+    if (dev->deviceGrab.sync.frozen)
+        return;
+
     flags |= TOUCH_CLIENT_ID;
     if (ti->emulate_pointer)
         flags |= TOUCH_POINTER_EMULATED;
commit c8a48358065ff94b8307d8aedfe58e54f34ba84f
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Feb 28 13:07:26 2013 +1000

    Xi: use public.processInputProc to replay the touch history
    
    If a device is frozen in results to a grab, we need to enqueue the events.
    
    This makes things complicated, and hard to follow since touch events are now
    replayed in the history, pushed into EnqueueEvent, then replayed later
    during PlayReleasedEvents in response to an XAllowEvents.
    
    While the device is frozen, no touch events are processed, so if there is a
    touch client with ownership mask _below_ the grab this will delay the
    delivery and potentially screw gesture recognition. However, this is the
    behaviour we have already anyway if the top-most client is a sync pgrab or
    there is a sync grab active on the device when the TouchBegin was generated.
    
    (also note, such a client would only reliably work in case of ReplayPointer
    anyway)
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit a7d989d335f903ffd8b168cd2beeb82c78d30c21)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index a8b3ee6..7975a40 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1554,7 +1554,7 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
 
     touchid = ev->device_event.touchid;
 
-    if (type == ET_TouchBegin) {
+    if (type == ET_TouchBegin && !(ev->device_event.flags & TOUCH_REPLAYING)) {
         ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
                              emulate_pointer);
     }
@@ -1621,7 +1621,9 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
      * called after event type mutation. Touch end events are always processed
      * in order to end touch records. */
     /* FIXME: check this */
-    if ((type == ET_TouchBegin && !TouchBuildSprite(dev, ti, ev)) ||
+    if ((type == ET_TouchBegin &&
+         !(ev->device_event.flags & TOUCH_REPLAYING) &&
+         !TouchBuildSprite(dev, ti, ev)) ||
         (type != ET_TouchEnd && ti->sprite.spriteTraceGood == 0))
         return;
 
@@ -1629,7 +1631,7 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
     /* WARNING: the event type may change to TouchUpdate in
      * DeliverTouchEvents if a TouchEnd was delivered to a grabbing
      * owner */
-    DeliverTouchEvents(dev, ti, (InternalEvent *) ev, 0);
+    DeliverTouchEvents(dev, ti, ev, ev->device_event.resource);
     if (ev->any.type == ET_TouchEnd)
         TouchEndTouch(dev, ti);
 
diff --git a/dix/touch.c b/dix/touch.c
index 5d6e2a7..76592e7 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -474,7 +474,21 @@ TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
         DeviceEvent *ev = &ti->history[i];
 
         ev->flags |= TOUCH_REPLAYING;
-        DeliverTouchEvents(dev, ti, (InternalEvent *) ev, resource);
+        ev->resource = resource;
+        /* FIXME:
+           We're replaying ti->history which contains the TouchBegin +
+           all TouchUpdates for ti. This needs to be passed on to the next
+           listener. If that is a touch listener, everything is dandy.
+           If the TouchBegin however triggers a sync passive grab, the
+           TouchUpdate events must be sent to EnqueueEvent so the events end
+           up in syncEvents.pending to be forwarded correctly in a
+           subsequent ComputeFreeze().
+
+           However, if we just send them to EnqueueEvent the sync'ing device
+           prevents handling of touch events for ownership listeners who
+           want the events right here, right now.
+         */
+        dev->public.processInputProc((InternalEvent*)ev, dev);
     }
 }
 
diff --git a/include/eventstr.h b/include/eventstr.h
index 5c1adc4..3950584 100644
--- a/include/eventstr.h
+++ b/include/eventstr.h
@@ -123,6 +123,7 @@ struct _DeviceEvent {
     int corestate;    /**< Core key/button state BEFORE the event */
     int key_repeat;   /**< Internally-generated key repeat event */
     uint32_t flags;   /**< Flags to be copied into the generated event */
+    uint32_t resource; /**< Touch event resource, only for TOUCH_REPLAYING */
 };
 
 /**
commit 2fcf86036f95128e9b90ddbd5ffc6edbacd3de9f
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Feb 27 15:05:54 2013 +1000

    Xi: when punting to a new owner, always create TouchEnd events
    
    If a touch is pending_finish and we just punted it to the next owner, that
    client must receive a TouchEnd event.
    
    If we just punted to the last owner and that owner not a touch grab, we need
    to end the touch since this is the last event to be sent, and the client
    cannot accept/reject this.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 214d11d3fcdac51fc7afbf3770516ec14f9e13c1)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 14b0cec..a8b3ee6 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1143,12 +1143,21 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
         TouchEventHistoryReplay(ti, dev, listener->listener);
     }
 
-    /* If we've just removed the last grab and the touch has physically
-     * ended, send a TouchEnd event too and finalise the touch. */
-    if (ti->num_listeners == 1 && ti->num_grabs == 0 && ti->pending_finish) {
+    /* New owner has Begin/Update but not end. If touch is pending_finish,
+     * emulate the TouchEnd now */
+    if (ti->pending_finish) {
         EmitTouchEnd(dev, ti, 0, 0);
-        TouchEndTouch(dev, ti);
-        return;
+
+        /* If the last owner is not a touch grab, finalise the touch, we
+           won't get more correspondence on this.
+         */
+        if (ti->num_listeners == 1 &&
+            (ti->num_grabs == 0 ||
+             listener->grab->grabtype != XI2 ||
+             !xi2mask_isset(listener->grab->xi2mask, dev, XI_TouchBegin))) {
+            TouchEndTouch(dev, ti);
+            return;
+        }
     }
 
     if (accepted_early)
commit e1c908f3931aa82c7c5f14aa162e02f3abf98faf
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Mar 1 09:15:37 2013 +1000

    Xi: save state for early acceptance
    
    Delivering an event changes the state to LISTENER_IS_OWNER and we thus lose
    the information of early acceptance.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 026627fe19aad007544eccf209f0dea05e67a7a7)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index f1081cf..14b0cec 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1126,10 +1126,10 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
                      TouchOwnershipEvent *ev)
 {
     TouchListener *listener = &ti->listeners[0]; /* new owner */
+    int accepted_early = listener->state == LISTENER_EARLY_ACCEPT;
 
     /* Deliver the ownership */
-    if (listener->state == LISTENER_AWAITING_OWNER ||
-        listener->state == LISTENER_EARLY_ACCEPT)
+    if (listener->state == LISTENER_AWAITING_OWNER || accepted_early)
         DeliverTouchEvents(dev, ti, (InternalEvent *) ev,
                            listener->listener);
     else if (listener->state == LISTENER_AWAITING_BEGIN) {
@@ -1151,7 +1151,7 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
         return;
     }
 
-    if (listener->state == LISTENER_EARLY_ACCEPT)
+    if (accepted_early)
         ActivateEarlyAccept(dev, ti);
 }
 
commit 7343d05e3a502216532aa9901c3a8948ea118c78
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Feb 28 15:28:46 2013 +1000

    Xi: if a passive async grab is activated from an emulated touch, accept
    
    Async grabs cannot replay events, they cannot reject, so we can do an early
    accept here.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit d905348134c80f19793eefb761731b00559ddf3a)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 180f4b5..f1081cf 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1848,8 +1848,14 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
         listener->type == LISTENER_POINTER_GRAB) {
         rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
                                        grab, xi2mask);
-        if (rc == Success)
+        if (rc == Success) {
             listener->state = LISTENER_IS_OWNER;
+            /* async grabs cannot replay, so automatically accept this touch */
+            if (dev->deviceGrab.grab &&
+                dev->deviceGrab.fromPassiveGrab &&
+                dev->deviceGrab.grab->pointerMode == GrabModeAsync)
+                ActivateEarlyAccept(dev, ti);
+        }
         goto out;
     }
 
commit 18346911ab0ce1ad66986b83f9afefadec25555e
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Feb 28 13:04:36 2013 +1000

    Xi: fix lookup in ActivateEarlyAccept
    
    ActivateEarlyAccept() can only be called from a grabbing client, so we can
    ignore the rest. And it's easy enough to get the client from that since
    9ad0fdb135a1c336771aee1f6eab75a6ad874aff.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 8b0d21044956f3810199d5e2f38ce33069e97be7)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index d075815..180f4b5 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1039,17 +1039,16 @@ ActivateEarlyAccept(DeviceIntPtr dev, TouchPointInfoPtr ti)
     int rc;
     ClientPtr client;
     XID error;
+    GrabPtr grab = ti->listeners[0].grab;
 
-    rc = dixLookupClient(&client, ti->listeners[0].listener, serverClient,
-                         DixSendAccess);
-    if (rc != Success) {
-        ErrorF("[Xi] Failed to lookup early accepting client.\n");
-        return;
-    }
+    BUG_RETURN(ti->listeners[0].type != LISTENER_GRAB &&
+               ti->listeners[0].type != LISTENER_POINTER_GRAB);
+    BUG_RETURN(!grab);
+
+    client = rClient(grab);
 
     if (TouchAcceptReject(client, dev, XIAcceptTouch, ti->client_id,
-                          ti->listeners[0].window->drawable.id, &error) !=
-        Success)
+                          ti->listeners[0].window->drawable.id, &error) != Success)
         ErrorF("[Xi] Failed to accept touch grab after early acceptance.\n");
 }
 
commit 000d469dd4d97424c72d82e4383ec295e31ffd34
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Feb 28 13:08:27 2013 +1000

    Xi: update the core listener state if we delivered the touch event
    
    If a TouchBegin is sent to a core client, that client is now the owner.
    
    By the time the TouchEnd is being processed, the client cannot replay
    anymore, so we can assume that this is the final touch end and we can clean
    up the touch record.
    
    Note: DeliverTouchEmulatedEvent is called for all listeners and immediately
    bails out if the client is not the owner and thus shouldn't yet get the
    event. Thus, check the return code.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit d08bae297f9d7651edb1923d6b0d6b14b3d674fc)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 2fdeaf4..d075815 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1849,6 +1849,8 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
         listener->type == LISTENER_POINTER_GRAB) {
         rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
                                        grab, xi2mask);
+        if (rc == Success)
+            listener->state = LISTENER_IS_OWNER;
         goto out;
     }
 
@@ -1889,13 +1891,13 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
         rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
                                        grab, xi2mask);
 
-        if (ti->num_listeners > 1) {
-            ev->any.type = ET_TouchUpdate;
-            ev->device_event.flags |= TOUCH_PENDING_END;
-            if (!(ev->device_event.flags & TOUCH_CLIENT_ID))
-                ti->pending_finish = TRUE;
-        }
-
+         /* Once we send a TouchEnd to a legacy listener, we're already well
+          * past the accepting/rejecting stage (can only happen on
+          * GrabModeSync + replay. This listener now gets the end event,
+          * and we can continue.
+          */
+        if (rc == Success)
+            listener->state = LISTENER_HAS_END;
         goto out;
     }
 
commit a7ec834d5e8c351cfa5d87b7902fa061826e3097
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Feb 25 11:21:07 2013 +1000

    Xi: if we delivered a TouchEnd to a passive grab, end it
    
    ef64b5ee97099618cf2e2cbbd3e471095695ae24 (which introduced the
    TOUCH_CLIENT_ID check) has a wrong assumption that generated touch events
    (TOUCH_CLIENT_ID) should not terminate passive grabs.
    This is untrue, a TouchEnd may be generated in response to a TouchReject
    higher up. If we _deliver_ an event to a client, terminate the passive grab.
    
    This requires us to count the actually delivered events too (first hunk).
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 81554d274f04951c55ea7f2e38d0455e2025e08d)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 9a7c1cb..2fdeaf4 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1417,7 +1417,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
             }
 
             if (!deliveries)
-                DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype);
+                deliveries = DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype);
 
             /* We must accept the touch sequence once a pointer listener has
              * received one event past ButtonPress. */
@@ -1425,8 +1425,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
                 !(ev->device_event.flags & TOUCH_CLIENT_ID))
                 TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
 
-            if (ev->any.type == ET_TouchEnd &&
-                !(ev->device_event.flags & TOUCH_CLIENT_ID) &&
+            if (deliveries && ev->any.type == ET_TouchEnd &&
                 !dev->button->buttonsDown &&
                 dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) {
                 (*dev->deviceGrab.DeactivateGrab) (dev);
commit 636647bc7f9ed10918cbb228f7d448c8cf733667
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Feb 13 11:26:11 2013 +1000

    dix: don't prepend an activated passive grab to the listeners
    
    If the device is currently grabbed as the result of a passive grab
    activating, do not prepend that grab to the listeners (unlike active grabs).
    Otherwise, a client with a passive pointer grab will prevent touch grabs
    from activating higher up in the window stack.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 363b6387da6e669099a2da3861c73a29808295a6)

diff --git a/dix/touch.c b/dix/touch.c
index 3027bbb..5d6e2a7 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -874,7 +874,7 @@ TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
     SpritePtr sprite = &ti->sprite;
     WindowPtr win;
 
-    if (dev->deviceGrab.grab)
+    if (dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab)
         TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab);
 
     /* We set up an active touch listener for existing touches, but not any
commit 87e027726f2d9223ce2fef2e4d26c18ae680a05e
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Feb 13 10:49:23 2013 +1000

    Xi: not having an ownership mask does not mean automatic acceptance
    
    If we only have a single touch-grabbing client, setting the client as owner
    would clean up the touch once the TouchEnd was processed. If the client then
    calls XIAllowTouches() it will receive a BadValue for the touch ID (since
    the internal record is already cleaned up).
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    (cherry picked from commit 9cc45c18ad1511adf3fb163dd4cefbef106edb23)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 77c705f..9a7c1cb 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1867,7 +1867,7 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
         if (has_ownershipmask)
             TouchSendOwnershipEvent(dev, ti, 0, listener->listener);
 
-        if (!has_ownershipmask || listener->type == LISTENER_REGULAR)
+        if (listener->type == LISTENER_REGULAR)
             state = LISTENER_HAS_ACCEPTED;
         else
             state = LISTENER_IS_OWNER;
commit 34f5ca3a70e966d6fe232179a47c3dc660773ad5
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Mar 1 08:26:06 2013 +1000

    Xi: use a temp variable for the new listener
    
    Instead of accessing ti->listener[0] all the time.
    
    No functional changes.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Keith Packard <keithp at keithp.com>
    (cherry picked from commit fc504a44d12d537d4e07f659f1863f200a0272ad)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index d39cf89..77c705f 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1126,20 +1126,22 @@ static void
 TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
                      TouchOwnershipEvent *ev)
 {
+    TouchListener *listener = &ti->listeners[0]; /* new owner */
+
     /* Deliver the ownership */
-    if (ti->listeners[0].state == LISTENER_AWAITING_OWNER ||
-        ti->listeners[0].state == LISTENER_EARLY_ACCEPT)
+    if (listener->state == LISTENER_AWAITING_OWNER ||
+        listener->state == LISTENER_EARLY_ACCEPT)
         DeliverTouchEvents(dev, ti, (InternalEvent *) ev,
-                           ti->listeners[0].listener);
-    else if (ti->listeners[0].state == LISTENER_AWAITING_BEGIN) {
+                           listener->listener);
+    else if (listener->state == LISTENER_AWAITING_BEGIN) {
         /* We can't punt to a pointer listener unless all older pointer
          * emulated touches have been seen already. */
-        if ((ti->listeners[0].type == LISTENER_POINTER_GRAB ||
-             ti->listeners[0].type == LISTENER_POINTER_REGULAR) &&
+        if ((listener->type == LISTENER_POINTER_GRAB ||
+             listener->type == LISTENER_POINTER_REGULAR) &&
             ti != FindOldestPointerEmulatedTouch(dev))
             return;
 
-        TouchEventHistoryReplay(ti, dev, ti->listeners[0].listener);
+        TouchEventHistoryReplay(ti, dev, listener->listener);
     }
 
     /* If we've just removed the last grab and the touch has physically
@@ -1150,7 +1152,7 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
         return;
     }
 
-    if (ti->listeners[0].state == LISTENER_EARLY_ACCEPT)
+    if (listener->state == LISTENER_EARLY_ACCEPT)
         ActivateEarlyAccept(dev, ti);
 }
 


More information about the xorg-commit mailing list