xserver: Branch 'master' - 33 commits

Keith Packard keithp at kemper.freedesktop.org
Thu May 23 19:02:20 PDT 2013


Rebased ref, commits from common ancestor:
commit cb3018d8a15add48efb3335e1f79b66378166008
Merge: c76a1b3 6589f3b
Author: Keith Packard <keithp at keithp.com>
Date:   Thu May 23 19:58:46 2013 -0600

    Merge remote-tracking branch 'whot/unreviewed'

commit c76a1b343d6a56aa9529e87f0eda8d61355d562b
Merge: 891123c 9a5ad65
Author: Keith Packard <keithp at keithp.com>
Date:   Thu May 23 19:58:36 2013 -0600

    Merge remote-tracking branch 'whot/touch-grab-race-condition-56578-v3'

commit 6589f3b55e335eef6c658c8ba1fe15a062f7e31c
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue May 14 08:31:19 2013 +1000

    dix: devices must have valuators before touch is initialized
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/devices.c b/dix/devices.c
index 291b767..527eea0 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -1647,6 +1647,7 @@ InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches,
 
     BUG_RETURN_VAL(device == NULL, FALSE);
     BUG_RETURN_VAL(device->touch != NULL, FALSE);
+    BUG_RETURN_VAL(device->valuator == NULL, FALSE);
 
     /* Check the mode is valid, and at least X and Y axes. */
     BUG_RETURN_VAL(mode != XIDirectTouch && mode != XIDependentTouch, FALSE);
commit 756ab88d93542f0589c9bf46f40ccc57df64f0fd
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Apr 26 15:10:08 2013 +1000

    dix: fix device scaling to use a [min,max[ range.
    
    defmin/defmax are screen coords and thus use a min-inclusive, max-exclusive
    range. device axes ranges are inclusive, so bump the max up by one to get the
    scaling right.
    
    This fixes off-by-one coordinate errors if the coordinate matrix is used to
    bind the device to a fraction of the screen. It introduces an off-by-one
    scaling error in the device coordinate range, but since most devices have a
    higher resolution than the screen (e.g. a Wacom I4 has 5080 dpi) the effect
    of this should be limited.
    
    This error manifests when we have numScreens > 1, as the scaling from
    desktop size back to screen size drops one device unit.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/devices.c b/dix/devices.c
index 9b6faee..291b767 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -112,8 +112,8 @@ DeviceSetTransform(DeviceIntPtr dev, float *transform_data)
      *  Transform is the user supplied (affine) transform
      *  InvScale scales coordinates back up into their native range
      */
-    sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value;
-    sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value;
+    sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value + 1;
+    sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value + 1;
 
     /* invscale */
     pixman_f_transform_init_scale(&scale, sx, sy);
diff --git a/dix/getevents.c b/dix/getevents.c
index ac0ccb2..51d4fd4 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -298,11 +298,11 @@ rescaleValuatorAxis(double coord, AxisInfoPtr from, AxisInfoPtr to,
 
     if (from && from->min_value < from->max_value) {
         fmin = from->min_value;
-        fmax = from->max_value;
+        fmax = from->max_value + 1;
     }
     if (to && to->min_value < to->max_value) {
         tmin = to->min_value;
-        tmax = to->max_value;
+        tmax = to->max_value + 1;
     }
 
     if (fmin == tmin && fmax == tmax)
@@ -924,9 +924,9 @@ scale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask,
 
     /* scale x&y to desktop coordinates */
     *screenx = rescaleValuatorAxis(x, dev->valuator->axes + 0, NULL,
-                                   screenInfo.x, screenInfo.width - 1);
+                                   screenInfo.x, screenInfo.width);
     *screeny = rescaleValuatorAxis(y, dev->valuator->axes + 1, NULL,
-                                   screenInfo.y, screenInfo.height - 1);
+                                   screenInfo.y, screenInfo.height);
 
     *devx = x;
     *devy = y;
@@ -1366,6 +1366,12 @@ QueuePointerEvents(DeviceIntPtr device, int type,
  * is the last coordinate on the first screen and must be rescaled for the
  * event to be m. XI2 clients that do their own coordinate mapping would
  * otherwise interpret the position of the device elsewere to the cursor.
+ * However, this scaling leads to losses:
+ * if we have two ScreenRecs we scale from e.g. [0..44704]  (Wacom I4) to
+ * [0..2048[. that gives us 2047.954 as desktop coord, or the per-screen
+ * coordinate 1023.954. Scaling that back into the device coordinate range
+ * gives us 44703. So off by one device unit. It's a bug, but we'll have to
+ * live with it because with all this scaling, we just cannot win.
  *
  * @return the number of events written into events.
  */
commit 5cc2c96f824dbb28b9f8da61efc41596f8bd0561
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Sat Mar 9 20:43:51 2013 +1000

    dix: pre-scale x by the screen:device:resolution ratio
    
    commit 61a99aff9d33728a0b67920254d2d4d79f80cf39
        dix: pre-scale relative events from abs devices to desktop ratio (#31636)
    
    added pre-scaling of relative coordinates coming from absolute devices to
    undo uneven scaling based on the screen dimensions.
    
    Devices have their own device width/height ratio as well (in a specific
    resolution) and this must be applied for relative devices as well to avoid
    scaling of the relative events into the device's ratio.
    
    e.g. a Wacom Intuos4 6x9 is in 16:10 format with equal horiz/vert
    resolution (dpi). A movement by 1000/1000 coordinates is a perfect diagonal
    on the tablet and must be reflected as such on the screen.
    
    However, we map the relative device-coordinate events to absolute screen
    coordinates based on the axis ranges. This results in an effective scaling
    of 1000/(1000 * 1.6) and thus an uneven x/y axis movement - the y
    axis is always faster.
    
    So we need to pre-scale not only by the desktop dimenstions but also by the
    device width/height ratio _and_ the resolution ratio.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/getevents.c b/dix/getevents.c
index 241c7ec..ac0ccb2 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -770,6 +770,29 @@ add_to_scroll_valuator(DeviceIntPtr dev, ValuatorMask *mask, int valuator, doubl
 }
 
 
+static void
+scale_for_device_resolution(DeviceIntPtr dev, ValuatorMask *mask)
+{
+    double x;
+    ValuatorClassPtr v = dev->valuator;
+    int xrange = v->axes[0].max_value - v->axes[0].min_value + 1;
+    int yrange = v->axes[1].max_value - v->axes[1].min_value + 1;
+
+    double screen_ratio = 1.0 * screenInfo.width/screenInfo.height;
+    double device_ratio = 1.0 * xrange/yrange;
+    double resolution_ratio = 1.0;
+    double ratio;
+
+    if (!valuator_mask_fetch_double(mask, 0, &x))
+        return;
+
+    if (v->axes[0].resolution != 0 && v->axes[1].resolution != 0)
+        resolution_ratio = 1.0 * v->axes[0].resolution/v->axes[1].resolution;
+
+    ratio = device_ratio/resolution_ratio/screen_ratio;
+    valuator_mask_set_double(mask, 0, x * ratio);
+}
+
 /**
  * Move the device's pointer by the values given in @valuators.
  *
@@ -781,27 +804,14 @@ moveRelative(DeviceIntPtr dev, int flags, ValuatorMask *mask)
 {
     int i;
     Bool clip_xy = IsMaster(dev) || !IsFloating(dev);
+    ValuatorClassPtr v = dev->valuator;
 
     /* for abs devices in relative mode, we've just scaled wrong, since we
        mapped the device's shape into the screen shape. Undo this. */
-    if ((flags & POINTER_ABSOLUTE) == 0 && dev->valuator &&
-        dev->valuator->axes[0].min_value < dev->valuator->axes[0].max_value) {
-
-        double ratio = 1.0 * screenInfo.width/screenInfo.height;
-
-        if (ratio > 1.0) {
-            double y;
-            if (valuator_mask_fetch_double(mask, 1, &y)) {
-                y *= ratio;
-                valuator_mask_set_double(mask, 1, y);
-            }
-        } else {
-            double x;
-            if (valuator_mask_fetch_double(mask, 0, &x)) {
-                x *= ratio;
-                valuator_mask_set_double(mask, 0, x);
-            }
-        }
+    if ((flags & POINTER_ABSOLUTE) == 0 && v && v->numAxes > 1 &&
+        v->axes[0].min_value < v->axes[0].max_value &&
+        v->axes[1].min_value < v->axes[1].max_value) {
+        scale_for_device_resolution(dev, mask);
     }
 
     /* calc other axes, clip, drop back into valuators */
commit 9a5ad65330693b3273972b63d10f2907d9ab954a
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>

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 8124ca9..e5db348 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);
     }
 }
 
@@ -3210,11 +3209,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);
@@ -3293,9 +3291,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;
@@ -4945,9 +4941,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);
@@ -5092,9 +5086,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 a9297f3..8950f97 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
@@ -3323,8 +3321,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;
@@ -3412,8 +3409,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;
@@ -3421,8 +3417,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 d32aac1..860704e 100644
--- a/hw/xfree86/ramdac/xf86Cursor.c
+++ b/hw/xfree86/ramdac/xf86Cursor.c
@@ -271,7 +271,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);
 
@@ -285,7 +285,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,
@@ -322,37 +322,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 90a026b..753d5f7 100644
--- a/xfixes/cursor.c
+++ b/xfixes/cursor.c
@@ -613,12 +613,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 35c2e263db01b2b61354298e5e85aa3cae8ac317
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>

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 8b9dc2628115dcb3f3601ad19b1ae157df21b9ee
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue May 14 07:46:25 2013 +1000

    dix: devices must have valuators before touch is initialized
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/devices.c b/dix/devices.c
index c514d77..c514cfe 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -1647,6 +1647,7 @@ InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches,
 
     BUG_RETURN_VAL(device == NULL, FALSE);
     BUG_RETURN_VAL(device->touch != NULL, FALSE);
+    BUG_RETURN_VAL(device->valuator == NULL, FALSE);
 
     /* Check the mode is valid, and at least X and Y axes. */
     BUG_RETURN_VAL(mode != XIDirectTouch && mode != XIDependentTouch, FALSE);
commit fd5ea0237db6d725a48f76b706135df9d3246b82
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index a99821f..2bbc6f0 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 481702101b86fff003430e952dc65fb41eb56400
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>

diff --git a/dix/events.c b/dix/events.c
index 7464db5..8124ca9 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1491,9 +1491,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;
@@ -1552,8 +1549,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);
@@ -4860,7 +4855,6 @@ ProcGrabPointer(ClientPtr client)
     GrabPtr grab;
     GrabMask mask;
     WindowPtr confineTo;
-    CursorPtr oldCursor;
     BYTE status;
 
     REQUEST(xGrabPointerReq);
@@ -4883,15 +4877,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;
 
@@ -4901,9 +4890,6 @@ ProcGrabPointer(ClientPtr client)
     if (rc != Success)
         return rc;
 
-    if (oldCursor && status == GrabSuccess)
-        FreeCursor(oldCursor, (Cursor) 0);
-
     rep = (xGrabPointerReply) {
         .type = X_Reply,
         .status = status,
@@ -5107,6 +5093,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 3093f78d17e48a506aab170a9089cd10e21af299
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>

diff --git a/dix/events.c b/dix/events.c
index 76bc555..7464db5 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1468,6 +1468,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;
@@ -1500,6 +1501,8 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
     UpdateTouchesForGrab(mouse);
     CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
                       (Bool) grab->keyboardMode);
+    if (oldgrab)
+        FreeGrab(oldgrab);
 }
 
 /**
@@ -1570,6 +1573,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. */
@@ -1595,12 +1599,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 2566bdd8bc996cccde77b846819808c6239a89d2
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index ae2e5ae..a99821f 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1919,7 +1919,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 5b00fc52270e9cfdfe7ac1838a21defe50fc3d31
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>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 1363f22..51d0de2 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -3399,6 +3399,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 34c9b39d9937c2e19c2dffc9748605f90d40f965
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>

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 395124bd2782823de37e5c5b2f15dba49cff05f6
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 2feddd3..ae2e5ae 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 cd2d939..76bc555 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1442,7 +1442,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 925e35122ebad877395bcf13676e9dbeb254bdfa
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 2495ade..2feddd3 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -2844,7 +2844,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 dc50311..cd2d939 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1492,8 +1492,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);
@@ -1596,8 +1595,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,
@@ -1991,7 +1989,7 @@ ActivateImplicitGrab(DeviceIntPtr dev, ClientPtr client, WindowPtr win,
     else
         return FALSE;
 
-    tempGrab = AllocGrab();
+    tempGrab = AllocGrab(NULL);
     if (!tempGrab)
         return FALSE;
     tempGrab->next = NULL;
@@ -3898,7 +3896,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 */
@@ -5087,7 +5085,7 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev,
     else {
         GrabPtr tempGrab;
 
-        tempGrab = AllocGrab();
+        tempGrab = AllocGrab(NULL);
 
         tempGrab->next = NULL;
         tempGrab->window = pWin;
@@ -5443,7 +5441,7 @@ ProcUngrabKey(ClientPtr client)
         client->errorValue = stuff->modifiers;
         return BadValue;
     }
-    tempGrab = AllocGrab();
+    tempGrab = AllocGrab(NULL);
     if (!tempGrab)
         return BadAlloc;
     tempGrab->resource = client->clientAsMask;
@@ -5637,7 +5635,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 4980bcef9973ba1f90f53028f061669ee5d2661b
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>

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 ccfa0f2d5de557546815a5e4f59552e2af46b578
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>

diff --git a/dix/events.c b/dix/events.c
index e2e94a5..dc50311 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1427,21 +1427,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 5363433a5cc64e2f83859aa1c32a89e5e1ddf9e4
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>

diff --git a/dix/devices.c b/dix/devices.c
index 9b6faee..c514d77 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 da9bd38..e2e94a5 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1490,8 +1490,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);
@@ -1554,6 +1555,8 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
         ReattachToOldMaster(mouse);
 
     ComputeFreezes();
+
+    FreeGrab(grab);
 }
 
 /**
@@ -1591,8 +1594,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,
@@ -1638,6 +1642,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 7dbf61817d3bd4b1fc71710677e56c5d8cfcdb4e
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>

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 a71a283934406d870bcd8dc376eb1c9ce1c8bbb4
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>

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 5174b1f98204beee79eba74c4cda5f2be0a60a8f
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>

diff --git a/dix/events.c b/dix/events.c
index 0512052..da9bd38 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1742,6 +1742,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 ef8191b..1745e9a 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 e7f79c48b0faea910dc881034c00eb807fcd6210
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index f500669..2495ade 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 304895f..ef8191b 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 0eb9390f6048049136347d5a5834d88bfc67cc09
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index f480473..f500669 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 a7d989d335f903ffd8b168cd2beeb82c78d30c21
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 9d999de..f480473 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 214d11d3fcdac51fc7afbf3770516ec14f9e13c1
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 97fec35..9d999de 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 026627fe19aad007544eccf209f0dea05e67a7a7
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 0f37d6b..97fec35 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 d905348134c80f19793eefb761731b00559ddf3a
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index b1df0cb..0f37d6b 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 8b0d21044956f3810199d5e2f38ce33069e97be7
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 27551dd..b1df0cb 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 d08bae297f9d7651edb1923d6b0d6b14b3d674fc
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 0cadf43..27551dd 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 81554d274f04951c55ea7f2e38d0455e2025e08d
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index fae747c..0cadf43 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 363b6387da6e669099a2da3861c73a29808295a6
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>

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 9cc45c18ad1511adf3fb163dd4cefbef106edb23
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>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 3088257..fae747c 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;


More information about the xorg-commit mailing list