[Xquartz-changes] xserver: Branch 'master' - 46 commits

Jeremy Huddleston jeremyhu at freedesktop.org
Thu Apr 19 17:34:19 PDT 2012


Rebased ref, commits from common ancestor:
commit 58456c3a61ea79af037ad5cf56fc8d8b636236f7
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Thu Apr 19 16:38:06 2012 -0700

    XQuartz: darwinPointer now sends both absolute and relative motion
    
    This should hopefully help out wine clients
    
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/hw/xquartz/X11Application.m b/hw/xquartz/X11Application.m
index f700c67..3c3a9b6 100644
--- a/hw/xquartz/X11Application.m
+++ b/hw/xquartz/X11Application.m
@@ -215,7 +215,8 @@ message_kit_thread(SEL selector, NSObject *arg)
     if (state) {
         if (bgMouseLocationUpdated) {
             DarwinSendPointerEvents(darwinPointer, MotionNotify, 0,
-                                    bgMouseLocation.x, bgMouseLocation.y);
+                                    bgMouseLocation.x, bgMouseLocation.y,
+                                    0.0, 0.0);
             bgMouseLocationUpdated = FALSE;
         }
         DarwinSendDDXEvent(kXquartzActivate, 0);
@@ -1595,14 +1596,16 @@ handle_mouse:
         if (bgMouseLocationUpdated) {
             if (!(ev_type == MotionNotify && ev_button == 0)) {
                 DarwinSendPointerEvents(darwinPointer, MotionNotify, 0,
-                                        location.x, location.y);
+                                        location.x, location.y,
+                                        0.0, 0.0);
             }
             bgMouseLocationUpdated = FALSE;
         }
 
         if (pDev == darwinPointer) {
             DarwinSendPointerEvents(pDev, ev_type, ev_button,
-                                    location.x, location.y);
+                                    location.x, location.y,
+                                    [e deltaX], [e deltaY]);
         } else {
             DarwinSendTabletEvents(pDev, ev_type, ev_button,
                                    location.x, location.y, pressure,
diff --git a/hw/xquartz/darwin.c b/hw/xquartz/darwin.c
index 03030ad..ac7f199 100644
--- a/hw/xquartz/darwin.c
+++ b/hw/xquartz/darwin.c
@@ -309,7 +309,7 @@ static int
 DarwinMouseProc(DeviceIntPtr pPointer, int what)
 {
 #define NBUTTONS 3
-#define NAXES    4
+#define NAXES    6
     // 3 buttons: left, middle, right
     CARD8 map[NBUTTONS + 1] = { 0, 1, 2, 3};
     Atom btn_labels[NBUTTONS] = { 0 };
@@ -323,10 +323,12 @@ DarwinMouseProc(DeviceIntPtr pPointer, int what)
         btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
         btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
 
-        axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
-        axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
-        axes_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_WHEEL);
-        axes_labels[3] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HWHEEL);
+        axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X);
+        axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y);
+        axes_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+        axes_labels[3] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+        axes_labels[4] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_WHEEL);
+        axes_labels[5] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HWHEEL);
 
         // Set button map.
         InitPointerDeviceStruct((DevicePtr)pPointer, map, NBUTTONS,
@@ -334,21 +336,27 @@ DarwinMouseProc(DeviceIntPtr pPointer, int what)
                                 (PtrCtrlProcPtr)NoopDDA,
                                 GetMotionHistorySize(), NAXES,
                                 axes_labels);
-        InitValuatorAxisStruct(pPointer, 0, axes_labels[0], 
+        InitValuatorAxisStruct(pPointer, 0, axes_labels[0],
+                               0, XQUARTZ_VALUATOR_LIMIT,
+                               1, 0, 1, Absolute);
+        InitValuatorAxisStruct(pPointer, 1, axes_labels[1],
+                               0, XQUARTZ_VALUATOR_LIMIT,
+                               1, 0, 1, Absolute);
+        InitValuatorAxisStruct(pPointer, 2, axes_labels[2], 
                                NO_AXIS_LIMITS, NO_AXIS_LIMITS,
                                1, 0, 1, Relative);
-        InitValuatorAxisStruct(pPointer, 1, axes_labels[1], 
+        InitValuatorAxisStruct(pPointer, 3, axes_labels[3], 
                                NO_AXIS_LIMITS, NO_AXIS_LIMITS,
                                1, 0, 1, Relative);
-        InitValuatorAxisStruct(pPointer, 2, axes_labels[2], 
+        InitValuatorAxisStruct(pPointer, 4, axes_labels[4], 
                                NO_AXIS_LIMITS, NO_AXIS_LIMITS,
                                1, 0, 1, Relative);
-        InitValuatorAxisStruct(pPointer, 3, axes_labels[3], 
+        InitValuatorAxisStruct(pPointer, 5, axes_labels[5], 
                                NO_AXIS_LIMITS, NO_AXIS_LIMITS,
                                1, 0, 1, Relative);
 
-        SetScrollValuator(pPointer, 2, SCROLL_TYPE_VERTICAL, -1.0, SCROLL_FLAG_PREFERRED);
-        SetScrollValuator(pPointer, 3, SCROLL_TYPE_HORIZONTAL, -1.0, SCROLL_FLAG_NONE);
+        SetScrollValuator(pPointer, 4, SCROLL_TYPE_VERTICAL, -1.0, SCROLL_FLAG_PREFERRED);
+        SetScrollValuator(pPointer, 5, SCROLL_TYPE_HORIZONTAL, -1.0, SCROLL_FLAG_NONE);
         break;
 
     case DEVICE_ON:
@@ -399,23 +407,24 @@ DarwinTabletProc(DeviceIntPtr pPointer, int what)
                                 axes_labels);
         InitProximityClassDeviceStruct(pPointer);
 
-        InitValuatorAxisStruct(pPointer, 0, axes_labels[0], 0,
-                               XQUARTZ_VALUATOR_LIMIT, 1, 0, 1,
-                               Absolute);
-        InitValuatorAxisStruct(pPointer, 1, axes_labels[1], 0,
-                               XQUARTZ_VALUATOR_LIMIT, 1, 0, 1,
-                               Absolute);
-        InitValuatorAxisStruct(pPointer, 2, axes_labels[2], 0,
-                               XQUARTZ_VALUATOR_LIMIT, 1, 0, 1,
-                               Absolute);
+        InitValuatorAxisStruct(pPointer, 0, axes_labels[0],
+                               0, XQUARTZ_VALUATOR_LIMIT,
+                               1, 0, 1, Absolute);
+        InitValuatorAxisStruct(pPointer, 1, axes_labels[1],
+                               0, XQUARTZ_VALUATOR_LIMIT,
+                               1, 0, 1, Absolute);
+        InitValuatorAxisStruct(pPointer, 2, axes_labels[2],
+                               0, XQUARTZ_VALUATOR_LIMIT,
+                               1, 0, 1, Absolute);
         InitValuatorAxisStruct(pPointer, 3, axes_labels[3],
                                -XQUARTZ_VALUATOR_LIMIT,
-                               XQUARTZ_VALUATOR_LIMIT, 1, 0, 1,
-                               Absolute);
+                               XQUARTZ_VALUATOR_LIMIT,
+                               1, 0, 1, Absolute);
         InitValuatorAxisStruct(pPointer, 4, axes_labels[4],
                                -XQUARTZ_VALUATOR_LIMIT,
-                               XQUARTZ_VALUATOR_LIMIT, 1, 0, 1,
-                               Absolute);
+                               XQUARTZ_VALUATOR_LIMIT,
+                               1, 0, 1, Absolute);
+
         //          pPointer->use = IsXExtensionDevice;
         break;
 
diff --git a/hw/xquartz/darwinEvents.c b/hw/xquartz/darwinEvents.c
index 25f011b..e6f7c14 100644
--- a/hw/xquartz/darwinEvents.c
+++ b/hw/xquartz/darwinEvents.c
@@ -497,12 +497,6 @@ DarwinSendTabletEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
     pointer_x -= darwinMainScreenX + screen->x;
     pointer_y -= darwinMainScreenY + screen->y;
 
-    if (pointer_x < 0.0)
-        pointer_x = 0.0;
-
-    if (pointer_y < 0.0)
-        pointer_y = 0.0;
-    
     /* Adjust our pointer location to the [0,1] range */
     pointer_x = pointer_x / (double)screenInfo.width;
     pointer_y = pointer_y / (double)screenInfo.height;
@@ -528,11 +522,13 @@ DarwinSendTabletEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
 
 void
 DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
-                        double pointer_x, double pointer_y)
+                        double pointer_x, double pointer_y,
+                        double pointer_dx, double pointer_dy)
 {
     static int darwinFakeMouseButtonDown = 0;
     ScreenPtr screen;
-    ValuatorMask valuators;
+    ValuatorMask valuators, deltaValuators;
+    BOOL sendDelta;
 
     if (!darwinEvents) {
         DEBUG_LOG("%s called before darwinEvents was initialized\n",
@@ -553,7 +549,7 @@ DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
             /* We're currently "down" with another button, so release it first */
             DarwinSendPointerEvents(pDev, ButtonRelease,
                                     darwinFakeMouseButtonDown,
-                                    pointer_x, pointer_y);
+                                    pointer_x, pointer_y, 0.0, 0.0);
             darwinFakeMouseButtonDown = 0;
         }
         if (darwin_all_modifier_flags & darwinFakeMouse2Mask) {
@@ -591,22 +587,34 @@ DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
     pointer_x -= darwinMainScreenX + screen->x;
     pointer_y -= darwinMainScreenY + screen->y;
 
-    if (pointer_x < 0.0)
-        pointer_x = 0.0;
-
-    if (pointer_y < 0.0)
-        pointer_y = 0.0;
+    /* Adjust our pointer location to the [0,1] range */
+    pointer_x = pointer_x / (double)screenInfo.width;
+    pointer_y = pointer_y / (double)screenInfo.height;
 
     valuator_mask_zero(&valuators);
-    valuator_mask_set_double(&valuators, 0, pointer_x);
-    valuator_mask_set_double(&valuators, 1, pointer_y);
+    valuator_mask_set_double(&valuators, 0, XQUARTZ_VALUATOR_LIMIT * pointer_x);
+    valuator_mask_set_double(&valuators, 1, XQUARTZ_VALUATOR_LIMIT * pointer_y);
+
+    sendDelta = (pointer_dx != 0.0 || pointer_dy != 0.0) &&
+                (ev_type == MotionNotify);
+
+    if (sendDelta) {
+        valuator_mask_zero(&deltaValuators);
+        valuator_mask_set_double(&deltaValuators, 2, pointer_dx);
+        valuator_mask_set_double(&deltaValuators, 3, pointer_dy);
+    }
 
     darwinEvents_lock();
     {
         QueuePointerEvents(pDev, ev_type, ev_button, POINTER_ABSOLUTE,
                            &valuators);
+        if (sendDelta) {
+            QueuePointerEvents(pDev, ev_type, 0, POINTER_RELATIVE,
+                               &deltaValuators);
+        }
+
         DarwinPokeEQ();
-    } darwinEvents_unlock();
+    } darwinEvents_unlock();   
 }
 
 void
diff --git a/hw/xquartz/darwinEvents.h b/hw/xquartz/darwinEvents.h
index 812a5dc..448e730 100644
--- a/hw/xquartz/darwinEvents.h
+++ b/hw/xquartz/darwinEvents.h
@@ -49,7 +49,8 @@ DarwinSendTabletEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
                        double tilt_x, double tilt_y);
 void
 DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
-                        double pointer_x, double pointer_y);
+                        double pointer_x, double pointer_y,
+                        double pointer_dx, double pointer_dy);
 void
 DarwinSendKeyboardEvents(int ev_type, int keycode);
 void
commit 873acd8e62a2678870e6aae984cd9b6693846757
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Thu Apr 19 16:20:30 2012 -0700

    XQuartz: Use screenInfo.{width,height} instead of grabbing it from the first screen
    
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/hw/xquartz/darwinEvents.c b/hw/xquartz/darwinEvents.c
index 9fc23a3..25f011b 100644
--- a/hw/xquartz/darwinEvents.c
+++ b/hw/xquartz/darwinEvents.c
@@ -504,8 +504,8 @@ DarwinSendTabletEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
         pointer_y = 0.0;
     
     /* Adjust our pointer location to the [0,1] range */
-    pointer_x = pointer_x / (double)screenInfo.screens[0]->width;
-    pointer_y = pointer_y / (double)screenInfo.screens[0]->height;
+    pointer_x = pointer_x / (double)screenInfo.width;
+    pointer_y = pointer_y / (double)screenInfo.height;
 
     valuator_mask_zero(&valuators);
     valuator_mask_set_double(&valuators, 0, XQUARTZ_VALUATOR_LIMIT * pointer_x);
commit 53fe023393cea635ad2093f2aeb5cef7409d3867
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Wed Apr 18 17:50:55 2012 -0700

    XQuartz: Separate out tablet and mouse event delivery into separate functions
    
    This should have no immediate impact aside from fake mouse buttons no longer
    working with tablets (where they aren't needed or desired anyways).  This
    prepares us for future changes.
    
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/hw/xquartz/X11Application.m b/hw/xquartz/X11Application.m
index a203f78..f700c67 100644
--- a/hw/xquartz/X11Application.m
+++ b/hw/xquartz/X11Application.m
@@ -215,9 +215,7 @@ message_kit_thread(SEL selector, NSObject *arg)
     if (state) {
         if (bgMouseLocationUpdated) {
             DarwinSendPointerEvents(darwinPointer, MotionNotify, 0,
-                                    bgMouseLocation.x, bgMouseLocation.y, 0.0,
-                                    0.0,
-                                    0.0);
+                                    bgMouseLocation.x, bgMouseLocation.y);
             bgMouseLocationUpdated = FALSE;
         }
         DarwinSendDDXEvent(kXquartzActivate, 0);
@@ -1549,9 +1547,9 @@ handle_mouse:
             if ([e isEnteringProximity])
                 needsProximityIn = YES;
             else
-                DarwinSendProximityEvents(darwinTabletCurrent, ProximityOut,
-                                          location.x, location.y, pressure,
-                                          tilt.x, tilt.y);
+                DarwinSendTabletEvents(darwinTabletCurrent, ProximityOut, 0,
+                                       location.x, location.y, pressure,
+                                       tilt.x, tilt.y);
             return;
         }
 
@@ -1563,9 +1561,9 @@ handle_mouse:
             pDev = darwinTabletCurrent;
 
             if (needsProximityIn) {
-                DarwinSendProximityEvents(darwinTabletCurrent, ProximityIn,
-                                          location.x, location.y, pressure,
-                                          tilt.x, tilt.y);
+                DarwinSendTabletEvents(darwinTabletCurrent, ProximityIn, 0,
+                                       location.x, location.y, pressure,
+                                       tilt.x, tilt.y);
 
                 needsProximityIn = NO;
             }
@@ -1596,14 +1594,20 @@ handle_mouse:
 
         if (bgMouseLocationUpdated) {
             if (!(ev_type == MotionNotify && ev_button == 0)) {
-                DarwinSendPointerEvents(pDev, MotionNotify, 0, location.x,
-                                        location.y, pressure, tilt.x, tilt.y);
+                DarwinSendPointerEvents(darwinPointer, MotionNotify, 0,
+                                        location.x, location.y);
             }
             bgMouseLocationUpdated = FALSE;
         }
 
-        DarwinSendPointerEvents(pDev, ev_type, ev_button, location.x,
-                                location.y, pressure, tilt.x, tilt.y);
+        if (pDev == darwinPointer) {
+            DarwinSendPointerEvents(pDev, ev_type, ev_button,
+                                    location.x, location.y);
+        } else {
+            DarwinSendTabletEvents(pDev, ev_type, ev_button,
+                                   location.x, location.y, pressure,
+                                   tilt.x, tilt.y);
+        }
 
         break;
 
@@ -1627,9 +1631,9 @@ handle_mouse:
         if ([e isEnteringProximity])
             needsProximityIn = YES;
         else
-            DarwinSendProximityEvents(darwinTabletCurrent, ProximityOut,
-                                      location.x, location.y, pressure,
-                                      tilt.x, tilt.y);
+            DarwinSendTabletEvents(darwinTabletCurrent, ProximityOut, 0,
+                                   location.x, location.y, pressure,
+                                   tilt.x, tilt.y);
         break;
 
     case NSScrollWheel:
@@ -1643,8 +1647,7 @@ handle_mouse:
         if (!XQuartzServerVisible && noTestExtensions) {
             bgMouseLocationUpdated = FALSE;
             DarwinSendPointerEvents(darwinPointer, MotionNotify, 0,
-                                    location.x, location.y, pressure, 
-                                    tilt.x, tilt.y);
+                                    location.x, location.y);
         }
 #endif
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
diff --git a/hw/xquartz/darwinEvents.c b/hw/xquartz/darwinEvents.c
index c62dd44..9fc23a3 100644
--- a/hw/xquartz/darwinEvents.c
+++ b/hw/xquartz/darwinEvents.c
@@ -44,19 +44,20 @@
 #include <dix-config.h>
 #endif
 
-#include   <X11/X.h>
-#include   <X11/Xmd.h>
-#include   <X11/Xproto.h>
-#include   "misc.h"
-#include   "windowstr.h"
-#include   "pixmapstr.h"
-#include   "inputstr.h"
-#include   "inpututils.h"
-#include   "eventstr.h"
-#include   "mi.h"
-#include   "scrnintstr.h"
-#include   "mipointer.h"
-#include   "os.h"
+#include <X11/X.h>
+#include <X11/Xmd.h>
+#include <X11/Xproto.h>
+#include "misc.h"
+#include "windowstr.h"
+#include "pixmapstr.h"
+#include "inputstr.h"
+#include "inpututils.h"
+#include "eventstr.h"
+#include "mi.h"
+#include "scrnintstr.h"
+#include "mipointer.h"
+#include "os.h"
+#include "exglobals.h"
 
 #include "darwin.h"
 #include "quartz.h"
@@ -442,56 +443,6 @@ DarwinPokeEQ(void)
     write(darwinEventWriteFD, &nullbyte, sizeof(nullbyte));
 }
 
-/* Convert from Appkit pointer input values to X input values:
- * Note: pointer_x and pointer_y are relative to the upper-left of primary
- *       display.
- */
-static void
-DarwinPrepareValuators(DeviceIntPtr pDev, ValuatorMask *pmask,
-                       ScreenPtr screen,
-                       double pointer_x, double pointer_y,
-                       double pressure, double tilt_x,
-                       double tilt_y)
-{
-
-    valuator_mask_zero(pmask);
-
-    /* Fix offset between darwin and X screens */
-    pointer_x -= darwinMainScreenX + screen->x;
-    pointer_y -= darwinMainScreenY + screen->y;
-
-    if (pointer_x < 0.0)
-        pointer_x = 0.0;
-
-    if (pointer_y < 0.0)
-        pointer_y = 0.0;
-
-    if (pDev == darwinPointer) {
-        valuator_mask_set_double(pmask, 0, pointer_x);
-        valuator_mask_set_double(pmask, 1, pointer_y);
-    }
-    else {
-        valuator_mask_set_double(pmask, 0, XQUARTZ_VALUATOR_LIMIT *
-                                 (pointer_x /
-                                  (double)screenInfo.screens[0]->width));
-        valuator_mask_set_double(pmask, 1, XQUARTZ_VALUATOR_LIMIT *
-                                 (pointer_y /
-                                  (double)screenInfo.screens[0]->height));
-        valuator_mask_set_double(pmask, 2, XQUARTZ_VALUATOR_LIMIT * pressure);
-        valuator_mask_set_double(pmask, 3, XQUARTZ_VALUATOR_LIMIT * tilt_x);
-        valuator_mask_set_double(pmask, 4, XQUARTZ_VALUATOR_LIMIT * tilt_y);
-        DEBUG_LOG("Pointer (%lf, %lf), Valuators: {%lf,%lf,%lf,%lf,%lf}\n",
-                  pointer_x, pointer_y,
-                  valuator_mask_get_double(pmask,
-                                           0),
-                  valuator_mask_get_double(pmask, 1),
-                  valuator_mask_get_double(pmask,
-                                           2),
-                  valuator_mask_get_double(pmask, 3),
-                  valuator_mask_get_double(pmask, 4));
-    }
-}
-
 void
 DarwinInputReleaseButtonsAndKeys(DeviceIntPtr pDev)
 {
@@ -521,27 +472,78 @@ DarwinInputReleaseButtonsAndKeys(DeviceIntPtr pDev)
 }
 
 void
+DarwinSendTabletEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
+                       double pointer_x, double pointer_y,
+                       double pressure, double tilt_x,
+                       double tilt_y)
+{
+    ScreenPtr screen;
+    ValuatorMask valuators;
+
+    if (!darwinEvents) {
+        DEBUG_LOG("%s called before darwinEvents was initialized\n",
+                  __FUNCTION__);
+        return;
+    }
+
+    screen = miPointerGetScreen(pDev);
+    if (!screen) {
+        DEBUG_LOG("%s called before screen was initialized\n",
+                  __FUNCTION__);
+        return;
+    }
+
+    /* Fix offset between darwin and X screens */
+    pointer_x -= darwinMainScreenX + screen->x;
+    pointer_y -= darwinMainScreenY + screen->y;
+
+    if (pointer_x < 0.0)
+        pointer_x = 0.0;
+
+    if (pointer_y < 0.0)
+        pointer_y = 0.0;
+    
+    /* Adjust our pointer location to the [0,1] range */
+    pointer_x = pointer_x / (double)screenInfo.screens[0]->width;
+    pointer_y = pointer_y / (double)screenInfo.screens[0]->height;
+
+    valuator_mask_zero(&valuators);
+    valuator_mask_set_double(&valuators, 0, XQUARTZ_VALUATOR_LIMIT * pointer_x);
+    valuator_mask_set_double(&valuators, 1, XQUARTZ_VALUATOR_LIMIT * pointer_y);
+    valuator_mask_set_double(&valuators, 2, XQUARTZ_VALUATOR_LIMIT * pressure);
+    valuator_mask_set_double(&valuators, 3, XQUARTZ_VALUATOR_LIMIT * tilt_x);
+    valuator_mask_set_double(&valuators, 4, XQUARTZ_VALUATOR_LIMIT * tilt_y);
+
+    darwinEvents_lock();
+    {
+        if (ev_type == ProximityIn || ev_type == ProximityOut) {
+            QueueProximityEvents(pDev, ev_type, &valuators);
+        } else {
+            QueuePointerEvents(pDev, ev_type, ev_button, POINTER_ABSOLUTE,
+                               &valuators);
+        }
+        DarwinPokeEQ();
+    } darwinEvents_unlock();
+}
+
+void
 DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
-                        double pointer_x, double pointer_y,
-                        double pressure, double tilt_x,
-                        double tilt_y)
+                        double pointer_x, double pointer_y)
 {
     static int darwinFakeMouseButtonDown = 0;
     ScreenPtr screen;
     ValuatorMask valuators;
 
-    //DEBUG_LOG("x=%f, y=%f, p=%f, tx=%f, ty=%f\n", pointer_x, pointer_y, pressure, tilt_x, tilt_y);
-
     if (!darwinEvents) {
-        DEBUG_LOG(
-            "DarwinSendPointerEvents called before darwinEvents was initialized\n");
+        DEBUG_LOG("%s called before darwinEvents was initialized\n",
+                  __FUNCTION__);
         return;
     }
 
     screen = miPointerGetScreen(pDev);
     if (!screen) {
-        DEBUG_LOG(
-            "DarwinSendPointerEvents called before screen was initialized\n");
+        DEBUG_LOG("%s called before screen was initialized\n",
+                  __FUNCTION__);
         return;
     }
 
@@ -550,9 +552,8 @@ DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
         if (darwinFakeMouseButtonDown != 0) {
             /* We're currently "down" with another button, so release it first */
             DarwinSendPointerEvents(pDev, ButtonRelease,
-                                    darwinFakeMouseButtonDown, pointer_x,
-                                    pointer_y, pressure, tilt_x,
-                                    tilt_y);
+                                    darwinFakeMouseButtonDown,
+                                    pointer_x, pointer_y);
             darwinFakeMouseButtonDown = 0;
         }
         if (darwin_all_modifier_flags & darwinFakeMouse2Mask) {
@@ -586,9 +587,20 @@ DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
         darwinFakeMouseButtonDown = 0;
     }
 
-    DarwinPrepareValuators(pDev, &valuators, screen, pointer_x, pointer_y,
-                           pressure, tilt_x,
-                           tilt_y);
+    /* Fix offset between darwin and X screens */
+    pointer_x -= darwinMainScreenX + screen->x;
+    pointer_y -= darwinMainScreenY + screen->y;
+
+    if (pointer_x < 0.0)
+        pointer_x = 0.0;
+
+    if (pointer_y < 0.0)
+        pointer_y = 0.0;
+
+    valuator_mask_zero(&valuators);
+    valuator_mask_set_double(&valuators, 0, pointer_x);
+    valuator_mask_set_double(&valuators, 1, pointer_y);
+
     darwinEvents_lock();
     {
         QueuePointerEvents(pDev, ev_type, ev_button, POINTER_ABSOLUTE,
@@ -615,42 +627,6 @@ DarwinSendKeyboardEvents(int ev_type, int keycode)
     } darwinEvents_unlock();
 }
 
-void
-DarwinSendProximityEvents(DeviceIntPtr pDev, int ev_type, double pointer_x,
-                          double pointer_y,
-                          double pressure, double tilt_x,
-                          double tilt_y)
-{
-    ScreenPtr screen;
-    ValuatorMask valuators;
-
-    DEBUG_LOG("DarwinSendProximityEvents: %d l:%f,%f p:%f t:%f,%f\n", ev_type,
-              pointer_x, pointer_y, pressure, tilt_x,
-              tilt_y);
-
-    if (!darwinEvents) {
-        DEBUG_LOG(
-            "DarwinSendProximityEvents called before darwinEvents was initialized\n");
-        return;
-    }
-
-    screen = miPointerGetScreen(pDev);
-    if (!screen) {
-        DEBUG_LOG(
-            "DarwinSendPointerEvents called before screen was initialized\n");
-        return;
-    }
-
-    DarwinPrepareValuators(pDev, &valuators, screen, pointer_x, pointer_y,
-                           pressure, tilt_x,
-                           tilt_y);
-    darwinEvents_lock();
-    {
-        QueueProximityEvents(pDev, ev_type, &valuators);
-        DarwinPokeEQ();
-    } darwinEvents_unlock();
-}
-
 /* Send the appropriate number of button clicks to emulate scroll wheel */
 void
 DarwinSendScrollEvents(double scroll_x, double scroll_y) {
diff --git a/hw/xquartz/darwinEvents.h b/hw/xquartz/darwinEvents.h
index 61ace6e..812a5dc 100644
--- a/hw/xquartz/darwinEvents.h
+++ b/hw/xquartz/darwinEvents.h
@@ -44,14 +44,12 @@ DarwinEQSwitchScreen(ScreenPtr pScreen, Bool fromDIX);
 void
 DarwinInputReleaseButtonsAndKeys(DeviceIntPtr pDev);
 void
-DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
-                        double pointer_x, double pointer_y, double pressure,
-                        double tilt_x,
-                        double tilt_y);
+DarwinSendTabletEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
+                       double pointer_x, double pointer_y, double pressure,
+                       double tilt_x, double tilt_y);
 void
-DarwinSendProximityEvents(DeviceIntPtr pDev, int ev_type, double pointer_x,
-                          double pointer_y, double pressure, double tilt_x,
-                          double tilt_y);
+DarwinSendPointerEvents(DeviceIntPtr pDev, int ev_type, int ev_button,
+                        double pointer_x, double pointer_y);
 void
 DarwinSendKeyboardEvents(int ev_type, int keycode);
 void
commit 4cb519dd1d4acfe4bb920b8558452152ece9724a
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Thu Apr 19 16:06:45 2012 -0700

    XQuartz: Correct calculation of the size of our file descriptor array in console_redirect
    
    Reported-by: Joe Rohde <joer at valvesoftware.com>
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/hw/xquartz/console_redirect.c b/hw/xquartz/console_redirect.c
index 7b92eca..1e0e56b 100644
--- a/hw/xquartz/console_redirect.c
+++ b/hw/xquartz/console_redirect.c
@@ -336,7 +336,7 @@ xq_asl_log_fd(aslclient asl, aslmsg msg, int level, int fd)
                   {
                       /* Reallocate if we need more space */
                       if (fd >= n_redirect_fds) {
-                          size_t new_n = 1 << (ffs(fd) + 1);
+                          size_t new_n = 1 << (fls(fd) + 1);
                           asl_redirect *new_array =
                               realloc(redirect_fds, new_n *
                                       sizeof(*redirect_fds));
commit 4c44bcbf6208df1de93206f5cb1bdf4eba5b0f72
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Wed Apr 18 01:01:44 2012 -0700

    XQuartz: Fix a deadlock in pre-dispatch code
    
    The fact that this has been in place so long makes me really wonder if
    anybody cares about this running in Tiger or Leopard.
    
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/hw/xquartz/xpr/xprFrame.c b/hw/xquartz/xpr/xprFrame.c
index 4c7aac4..01f1def 100644
--- a/hw/xquartz/xpr/xprFrame.c
+++ b/hw/xquartz/xpr/xprFrame.c
@@ -212,7 +212,7 @@ xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
 #else
     pthread_rwlock_wrlock(&window_hash_rwlock);
     x_hash_table_insert(window_hash, pFrame->wid, pFrame);
-    pthread_rwlock_wrlock(&window_hash_rwlock);
+    pthread_rwlock_unlock(&window_hash_rwlock);
 #endif
 
     xprSetNativeProperty(pFrame);
commit 4ce2be2ed0860ecfa9d7019957ae64dabe2a5ee3
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Sat Apr 7 15:26:53 2012 -0700

    test: Fix make dist
    
    It seems like make dist should be doing te right thing without this commit,
    but it's not in some cases.  Don't ask me to explain why.
    
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/test/Makefile.am b/test/Makefile.am
index 8c7e412..8582397 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -54,8 +54,6 @@ libxservertest_la_LIBADD += \
             $(top_builddir)/hw/xfree86/dixmods/libxorgxkb.la \
             @XORG_LIBS@
 
-EXTRA_DIST = ddxstubs.c
-
 else
 nodist_libxservertest_la_SOURCES = \
             ddxstubs.c \
@@ -111,3 +109,6 @@ endif
 
 libxservertest_la_DEPENDENCIES = $(libxservertest_la_LIBADD)
 endif
+
+EXTRA_DIST = ddxstubs.c
+
commit fc8983279ca06da385d8ce741eeeddd35b3ada9f
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Thu Apr 19 16:39:23 2012 -0700

    os: Annotate OsVendorFatalError as _X_ATTRIBUTE_PRINTF
    
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/include/os.h b/include/os.h
index 166c60c..276eb52 100644
--- a/include/os.h
+++ b/include/os.h
@@ -321,7 +321,8 @@ extern _X_EXPORT void
 OsCleanup(Bool);
 
 extern _X_EXPORT void
-OsVendorFatalError(const char *f, va_list args);
+OsVendorFatalError(const char *f, va_list args)
+_X_ATTRIBUTE_PRINTF(1, 0);
 
 extern _X_EXPORT void
 OsVendorInit(void);
commit 319841fcaaa6e0491658b4b4940bac86ee51ac1a
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Thu Apr 19 16:51:46 2012 -0700

    xres: Fix build without composite
    
    Regression from: b8d0d19a6d410776b53a41e7cae90f68d4b22bb7
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/Xext/xres.c b/Xext/xres.c
index ecef0c0..dbefeeb 100644
--- a/Xext/xres.c
+++ b/Xext/xres.c
@@ -29,7 +29,10 @@
 #include <string.h>
 #include "hashtable.h"
 #include "picturestr.h"
+
+#ifdef COMPOSITE
 #include "compint.h"
+#endif
 
 /** @brief Holds fragments of responses for ConstructClientIds.
  *
commit 31e3c0ff7f5fb36421be8de06e5f6e675ec26ddc
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Apr 19 15:25:41 2012 -0500

    Export CompositeClientWindowType
    
    Make sure CompositeClientWindowType is visible for XResource v1.2
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/composite/compint.h b/composite/compint.h
index 6c4272e..9e2713e 100644
--- a/composite/compint.h
+++ b/composite/compint.h
@@ -71,6 +71,7 @@
 #include "damageextint.h"
 #include "xfixes.h"
 #include <X11/extensions/compositeproto.h>
+#include "compositeext.h"
 #include <assert.h>
 
 /*
@@ -182,7 +183,6 @@ extern DevPrivateKeyRec CompSubwindowsPrivateKeyRec;
 #define GetCompSubwindows(w) ((CompSubwindowsPtr) \
     dixLookupPrivate(&(w)->devPrivates, CompSubwindowsPrivateKey))
 
-extern RESTYPE CompositeClientWindowType;
 extern RESTYPE CompositeClientSubwindowsType;
 extern RESTYPE CompositeClientOverlayType;
 
diff --git a/composite/compositeext.h b/composite/compositeext.h
index 600604d..0b148f0 100644
--- a/composite/compositeext.h
+++ b/composite/compositeext.h
@@ -35,4 +35,6 @@ extern _X_EXPORT Bool CompositeRegisterAlternateVisuals(ScreenPtr pScreen,
                                                         VisualID * vids,
                                                         int nVisuals);
 
+extern _X_EXPORT RESTYPE CompositeClientWindowType;
+
 #endif                          /* _COMPOSITEEXT_H_ */
diff --git a/hw/xfree86/sdksyms.sh b/hw/xfree86/sdksyms.sh
index 40ea7c8..3815525 100755
--- a/hw/xfree86/sdksyms.sh
+++ b/hw/xfree86/sdksyms.sh
@@ -252,6 +252,8 @@ cat > sdksyms.c << EOF
  */
 
 
+#include "compositeext.h"
+
 /* xfixes/Makefile.am */
 #include "xfixes.h"
 
commit e6308e32fe2b5f74133d4d238ffa512257f6327c
Merge: 3720aa3 51a8d8d
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Apr 19 10:45:07 2012 -0500

    Merge remote-tracking branch 'whot/for-keith'
    
    Touch input changes from Chase

commit 51a8d8dd19d7496fe84b37a1f0a7a03658120539
Merge: ebf2148 00cf1c4
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Apr 19 17:03:54 2012 +1000

    Merge branch 'input-fixes' of git://people.freedesktop.org/~cndougla/xserver into for-keith

commit 00cf1c40b28417d7035c2917d048553eb720023c
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Apr 18 18:21:54 2012 -0700

    Replay original touch begin event instead of generated begin event
    
    The generated event does not have axes other than X and Y and has a
    newer timestamp. In particular, the newer timestamp may be newer than
    the real touch end event, which may be stuck in the syncEvents queue. If
    a client uses the timestamps for grabbing bad things may happen.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/touch.c b/dix/touch.c
index 67c4be2..dd16367 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -474,10 +474,22 @@ TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
     flags = TOUCH_CLIENT_ID | TOUCH_REPLAYING;
     if (ti->emulate_pointer)
         flags |= TOUCH_POINTER_EMULATED;
-    /* send fake begin event to next owner */
+    /* Generate events based on a fake touch begin event to get DCCE events if
+     * needed */
+    /* FIXME: This needs to be cleaned up */
     nev = GetTouchEvents(tel, dev, ti->client_id, XI_TouchBegin, flags, mask);
-    for (i = 0; i < nev; i++)
-        DeliverTouchEvents(dev, ti, tel + i, resource);
+    for (i = 0; i < nev; i++) {
+        /* Send saved touch begin event */
+        if (tel[i].any.type == ET_TouchBegin) {
+            DeviceEvent *ev = &ti->history[0];
+            ev->flags |= TOUCH_REPLAYING;
+            DeliverTouchEvents(dev, ti, (InternalEvent*)ev, resource);
+        }
+        else {/* Send DCCE event */
+            tel[i].any.time = ti->history[0].time;
+            DeliverTouchEvents(dev, ti, tel + i, resource);
+        }
+    }
 
     valuator_mask_free(&mask);
     FreeEventList(tel, GetMaximumEventsNum());
commit 312910b4e34215aaa50fc0c6092684d5878dc32f
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Apr 18 11:15:40 2012 -0700

    Update currentTime in dispatch loop
    
    A request, like input device grabs, may check a request timestamp
    against currentTime. It is possible for currentTime to lag a previously
    sent event timestamp. If the client makes a request based on such an
    event timestamp, the request may fail the validity check against
    currentTime unless we always update the time before processing the
    request.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index bce3a0d..9a2e22f 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -393,6 +393,9 @@ Dispatch(void)
                 }
                 /* now, finally, deal with client requests */
 
+                /* Update currentTime so request time checks, such as for input
+                 * device grabs, are calculated correctly */
+                UpdateCurrentTimeIf();
                 result = ReadRequestFromClient(client);
                 if (result <= 0) {
                     if (result < 0)
commit a986f2f30cbe2a00e72ded7315c4951d7703e549
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Tue Apr 17 11:40:15 2012 -0700

    Update device state including when touch record does not exist
    
    If a touch is physically active, the pointer core state should reflect
    that the first button is pressed. Currently, this only occurs when there
    are active listeners of the touch sequence. By moving the device state
    updating to the beginning of touch processing we ensure it is updated
    according to the processed physical state no matter what.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index d2b088c..e9f0207 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1597,6 +1597,9 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
     else
         touchid = ev->device_event.touchid;
 
+    if (emulate_pointer)
+        UpdateDeviceState(dev, &ev->device_event);
+
     if (type == ET_TouchBegin) {
         ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
                              emulate_pointer);
@@ -1996,9 +1999,6 @@ DeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
 
         DeliverTouchEvent(dev, ti, ev, listener, client, win, grab, mask);
     }
-
-    if (ti->emulate_pointer)
-        UpdateDeviceState(dev, &ev->device_event);
 }
 
 int
diff --git a/dix/touch.c b/dix/touch.c
index f8f26c8..67c4be2 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -364,14 +364,6 @@ TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
 {
     if (ti->emulate_pointer) {
         GrabPtr grab;
-        DeviceEvent ev;
-
-        memset(&ev, 0, sizeof(ev));
-        ev.type = ET_TouchEnd;
-        ev.detail.button = 1;
-        ev.touchid = ti->client_id;
-        ev.flags = TOUCH_POINTER_EMULATED | TOUCH_END;
-        UpdateDeviceState(dev, &ev);
 
         if ((grab = dev->deviceGrab.grab)) {
             if (dev->deviceGrab.fromPassiveGrab &&
commit ec9c4295830c3de610e65aca17f4da4a7af3c4c5
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Apr 18 12:04:58 2012 -0700

    Check other clients' core masks properly when adding touch listener
    
    The current code checks the core event mask as though it were an XI
    mask. This change fixes the checks so the proper client and event masks
    are used.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/touch.c b/dix/touch.c
index 572bdfb..f8f26c8 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -811,6 +811,7 @@ TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
     if (mask & EVENT_CORE_MASK) {
         int coretype = GetCoreType(TouchGetPointerEventType(ev));
         Mask core_filter = event_get_filter_from_type(dev, coretype);
+        OtherClients *oclients;
 
         /* window owner */
         if (IsMaster(dev) && (win->eventMask & core_filter)) {
@@ -822,13 +823,12 @@ TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
         }
 
         /* all others */
-        nt_list_for_each_entry(iclients, (InputClients *) wOtherClients(win),
-                               next) {
-            if (!(iclients->mask[XIAllDevices] & core_filter))
+        nt_list_for_each_entry(oclients, wOtherClients(win), next) {
+            if (!(oclients->mask & core_filter))
                 continue;
 
             TouchEventHistoryAllocate(ti);
-            TouchAddListener(ti, iclients->resource, CORE,
+            TouchAddListener(ti, oclients->resource, CORE,
                              type, LISTENER_AWAITING_BEGIN, win);
             return TRUE;
         }
commit e175971a6f44d94aa8306dc6b9228ccb2c8a0b4d
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Tue Apr 17 11:39:10 2012 -0700

    Ensure touch is ended when last listener is rejected
    
    Currently, the touch is only logically ended if the touch has physically
    ended. If the touch hasn't physically ended, the touch record is never
    ended. If there aren't any more listeners, we don't need to keep the dix
    touch record around any more.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index c8bd222..d2b088c 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1234,14 +1234,6 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource,
         }
     }
 
-    /* If there are no other listeners left, and the touchpoint is pending
-     * finish, then we can just kill it now. */
-    if (ti->num_listeners == 1 && ti->pending_finish) {
-        TouchEndTouch(sourcedev, ti);
-        CheckOldestTouch(sourcedev);
-        return;
-    }
-
     /* Remove the resource from the listener list, updating
      * ti->num_listeners, as well as ti->num_grabs if it was a grab. */
     if (TouchRemoveListener(ti, resource)) {
@@ -1254,6 +1246,8 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource,
      * the TouchOwnership or TouchBegin event to the new owner. */
     if (ev && ti->num_listeners > 0 && was_owner)
         TouchPuntToNextOwner(sourcedev, ti, ev);
+    else if (ti->num_listeners == 0)
+        TouchEndTouch(sourcedev, ti);
 
     CheckOldestTouch(sourcedev);
 }
commit d0449851d1233543c3133d77e0ab7233319cdf5f
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Tue Apr 17 10:49:14 2012 -0700

    Create a new dix touch record for an emulated touch with no listeners
    
    As a special case, if a still physically active pointer emulated touch
    has no listeners and the device is explicitly grabbed for pointer
    events, create a new dix touch record for the grab only.
    
    This allows for clients to "hand off" grabs. For example, when dragging
    a window under compiz the window decorator sees the button press and
    then ungrabs the implicit grab. It then tells compiz to grab the device,
    and compiz then moves the window with the pointer motion. This is racy,
    but is allowed by the input protocol for pointer events when there are
    no other clients with a grab on the device.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index ae3652b..c8bd222 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1610,6 +1610,34 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
     else
         ti = TouchFindByClientID(dev, touchid);
 
+    /* Under the following circumstances we create a new touch record for an
+     * existing touch:
+     *
+     * - The touch may be pointer emulated
+     * - An explicit grab is active on the device
+     * - The grab is a pointer grab
+     *
+     * This allows for an explicit grab to receive pointer events for an already
+     * active touch.
+     */
+    if (!ti && type != ET_TouchBegin && emulate_pointer &&
+        dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab &&
+        (dev->deviceGrab.grab->grabtype == CORE ||
+         dev->deviceGrab.grab->grabtype == XI ||
+         !xi2mask_isset(dev->deviceGrab.grab->xi2mask, dev, XI_TouchBegin))) {
+        ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
+                             emulate_pointer);
+        if (!ti) {
+            DebugF("[Xi] %s: Failed to create new dix record for explicitly "
+                   "grabbed touchpoint %d\n",
+                   dev->name, type, touchid);
+            return;
+        }
+
+        TouchBuildSprite(dev, ti, ev);
+        TouchSetupListeners(dev, ti, ev);
+    }
+
     if (!ti) {
         DebugF("[Xi] %s: Failed to get event %d for touchpoint %d\n",
                dev->name, type, touchid);
diff --git a/dix/touch.c b/dix/touch.c
index e638a89..572bdfb 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -864,6 +864,11 @@ TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
     if (dev->deviceGrab.grab)
         TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab);
 
+    /* We set up an active touch listener for existing touches, but not any
+     * passive grab or regular listeners. */
+    if (ev->any.type != ET_TouchBegin)
+        return;
+
     /* First, find all grabbing clients from the root window down
      * to the deepest child window. */
     for (i = 0; i < sprite->spriteTraceGood; i++) {
commit 3d06bfe93d33cfe6150d8fb0058ee7bc8d80622b
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Tue Apr 17 13:56:08 2012 -0700

    Rename TouchEnsureSprite to TouchBuildSprite and event type checks
    
    The function will be used for building a sprite for pointer emulation
    after an explicit device grab. This commit refactors the code so that
    TouchBuildSprite will function with any event type and moves the checks
    to the caller.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 28b288e..ae3652b 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1625,9 +1625,11 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
         CheckMotion(&ev->device_event, dev);
 
     /* Make sure we have a valid window trace for event delivery; must be
-     * called after event type mutation. */
+     * called after event type mutation. Touch end events are always processed
+     * in order to end touch records. */
     /* FIXME: check this */
-    if (!TouchEnsureSprite(dev, ti, ev))
+    if ((type == ET_TouchBegin && !TouchBuildSprite(dev, ti, ev)) ||
+        (type != ET_TouchEnd && ti->sprite.spriteTraceGood == 0))
         return;
 
     /* TouchOwnership events are handled separately from the rest, as they
diff --git a/dix/touch.c b/dix/touch.c
index 72faad5..e638a89 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -542,22 +542,12 @@ TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite)
  * TouchBegin events.
  */
 Bool
-TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
-                  InternalEvent *ev)
+TouchBuildSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
+                 InternalEvent *ev)
 {
     TouchClassPtr t = sourcedev->touch;
     SpritePtr sprite = &ti->sprite;
 
-    /* We may not have a sprite if there are no applicable grabs or
-     * event selections, or if they've disappeared, or if all the grab
-     * owners have rejected the touch.  Don't bother delivering motion
-     * events if not, but TouchEnd events still need to be processed so
-     * we can call FinishTouchPoint and release it for later use. */
-    if (ev->any.type == ET_TouchEnd)
-        return TRUE;
-    else if (ev->any.type != ET_TouchBegin)
-        return (sprite->spriteTraceGood > 0);
-
     if (t->mode == XIDirectTouch) {
         /* Focus immediately under the touchpoint in direct touch mode.
          * XXX: Do we need to handle crossing screens here? */
diff --git a/include/input.h b/include/input.h
index 9a6fdfe..991d648 100644
--- a/include/input.h
+++ b/include/input.h
@@ -563,8 +563,8 @@ extern void TouchAddListener(TouchPointInfoPtr ti, XID resource,
 extern Bool TouchRemoveListener(TouchPointInfoPtr ti, XID resource);
 extern void TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti,
                                 InternalEvent *ev);
-extern Bool TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
-                              InternalEvent *ev);
+extern Bool TouchBuildSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
+                             InternalEvent *ev);
 extern Bool TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite);
 extern int TouchConvertToPointerEvent(const InternalEvent *ev,
                                       InternalEvent *motion,
commit 2efbed23c29020f9994ab7c3155ce7386950dc7a
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Tue Apr 17 08:39:38 2012 -0700

    When activating an explicit grab, update owning listener
    
    Pointer passive grabs may be changed by the grabbing client. This allows
    for a selecting client to change an implicit grab to an active grab,
    which is the mechanism used for pop-up windows like application menus.
    
    We need to do the same thing with touches. If the grabbing client is the
    owner of a touch sequence, change the listener record to reflect the new
    grab. If the grabbing client is not the owner, nothing changes for the
    touch.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/events.c b/dix/events.c
index 52ce0b8..9496b6f 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1409,6 +1409,38 @@ ReattachToOldMaster(DeviceIntPtr dev)
 }
 
 /**
+ * Update touch records when an explicit grab is activated. Any touches owned by
+ * the grabbing client are updated so the listener state reflects the new grab.
+ */
+static void
+UpdateTouchesForGrab(DeviceIntPtr mouse)
+{
+    int i;
+
+    if (!mouse->touch || mouse->deviceGrab.fromPassiveGrab)
+        return;
+
+    for (i = 0; i < mouse->touch->num_touches; i++) {
+        TouchPointInfoPtr ti = mouse->touch->touches + i;
+        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;
+
+            if (grab->grabtype == CORE || grab->grabtype == XI ||
+                !xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin))
+                ti->listeners[0].type = LISTENER_POINTER_GRAB;
+            else
+                ti->listeners[0].type = LISTENER_GRAB;
+        }
+    }
+}
+
+/**
  * Activate a pointer grab on the given device. A pointer grab will cause all
  * core pointer events of this device to be delivered to the grabbing client only.
  * No other device will send core events to the grab client while the grab is
@@ -1457,6 +1489,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
     grabinfo->fromPassiveGrab = isPassive;
     grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
     PostNewCursor(mouse);
+    UpdateTouchesForGrab(mouse);
     CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
                       (Bool) grab->keyboardMode);
 }
commit ef64b5ee97099618cf2e2cbbd3e471095695ae24
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Mon Apr 16 15:53:51 2012 -0700

    Don't deactivate implicit pointer grab on fake touch end event
    
    Fake touch end events are generated by touch acceptance and rejection.
    These should not cause implicit pointer grabs to be deactivated.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 823da2a..28b288e 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1482,6 +1482,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
                 TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
 
             if (ev->any.type == ET_TouchEnd &&
+                !(ev->device_event.flags & TOUCH_CLIENT_ID) &&
                 !dev->button->buttonsDown &&
                 dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) {
                 (*dev->deviceGrab.DeactivateGrab) (dev);
commit fc518cd9f59060cc19bb90361767c0f47f0e25eb
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Mon Apr 16 15:31:47 2012 -0700

    End a pointer emulated touch event only on a "real" end event
    
    Fake end events are generated by touch acceptance or rejection. These
    should not end the touch point.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 3dd3688..823da2a 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1856,7 +1856,8 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
         if (ti->num_listeners > 1) {
             ev->any.type = ET_TouchUpdate;
             ev->device_event.flags |= TOUCH_PENDING_END;
-            ti->pending_finish = TRUE;
+            if (!(ev->device_event.flags & TOUCH_CLIENT_ID))
+                ti->pending_finish = TRUE;
         }
 
         goto out;
commit 80d7d1ec6a9d61aa96e7d019dc1bee29d90cea34
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Mon Apr 16 14:19:59 2012 -0700

    On touch accept, only process end event for owner if it has seen the end
    
    We still need to generate the touch ownership event to process the
    ending of the touch event in the case where the owner has the end
    already.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 4629df3..3dd3688 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1273,9 +1273,18 @@ ProcessTouchOwnershipEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
     if (ev->reason == XIRejectTouch)
         TouchRejected(dev, ti, ev->resource, ev);
     else if (ev->reason == XIAcceptTouch) {
+        int i;
+
+        /* 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. */
+        if (ti->listeners[0].state == LISTENER_HAS_END)
+            EmitTouchEnd(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. */
-        EmitTouchEnd(dev, ti, TOUCH_ACCEPT, 0);
+        for (i = 1; i < ti->num_listeners; i++)
+            EmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[i].listener);
 
         while (ti->num_listeners > 1)
             TouchRemoveListener(ti, ti->listeners[1].listener);
commit 8dfd98245d2c44a1eb4c8b7c275e6cfc10fe40f1
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Apr 11 11:14:51 2012 -0700

    Fix copy/paste error from before git history in UpdateCurrentTimeIf()
    
    See UpdateCurrentTime() for reference. I don't know what bug this might
    trigger, but it wouldn't hurt to fix this.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 104dcc9..bce3a0d 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -214,7 +214,7 @@ UpdateCurrentTimeIf(void)
     systime.milliseconds = GetTimeInMillis();
     if (systime.milliseconds < currentTime.milliseconds)
         systime.months++;
-    if (*checkForInput[0] == *checkForInput[1])
+    if (CompareTimeStamps(systime, currentTime) == LATER)
         currentTime = systime;
 }
 
commit 6ca30cb33e829b4edd01822367e44ffe6f0951b0
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Apr 11 08:17:25 2012 -0700

    When deactivating an explicit pointer grab, reject all grabs on touches
    
    Explicit pointer grabs are placed at the head of the touch listener
    array for pointer emulated touches. If the grab is deactivated, we must
    remove it from all touches for the device.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/events.c b/dix/events.c
index a137d6f..52ce0b8 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1473,6 +1473,8 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
     DeviceIntPtr dev;
     Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
                         mouse->deviceGrab.implicitGrab);
+    XID grab_resource = grab->resource;
+    int i;
 
     TouchRemovePointerGrab(mouse);
 
@@ -1497,6 +1499,15 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
         ReattachToOldMaster(mouse);
 
     ComputeFreezes();
+
+    /* If an explicit grab was deactivated, we must remove it from the head of
+     * all the touches' listener lists. */
+    for (i = 0; mouse->touch && i < mouse->touch->num_touches; i++) {
+        TouchPointInfoPtr ti = mouse->touch->touches + i;
+
+        if (ti->active && TouchResourceIsOwner(ti, grab_resource))
+            TouchListenerAcceptReject(mouse, ti, 0, XIRejectTouch);
+    }
 }
 
 /**
commit cacdb9a74065ccba7d50a82e14abdf04b36c5309
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Apr 11 08:13:17 2012 -0700

    Accept touch sequence for pointer listener after second event delivery
    
    This is a bit of unimplemented code for touchscreen pointer emulation. A
    pointer grabbing client currently never accepts the touch sequence. The
    sequence must be accepted once any touch-derived event is irrevocably
    delivered to a client.
    
    The first pointer event, derived from a touch begin event, may be caught
    in a sync grab and then replayed. This is essentially a revocable
    delivery of an event. Thus, we must wait till a non-begin event is
    delivered.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index ab2f044..4629df3 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1466,6 +1466,12 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
             if (!deliveries)
                 DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype);
 
+            /* We must accept the touch sequence once a pointer listener has
+             * received one event past ButtonPress. */
+            if (deliveries && ev->any.type != ET_TouchBegin &&
+                !(ev->device_event.flags & TOUCH_CLIENT_ID))
+                TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
+
             if (ev->any.type == ET_TouchEnd &&
                 !dev->button->buttonsDown &&
                 dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) {
commit 447fe7a1a72513aa68145962c47894242c589cc9
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Apr 11 08:12:08 2012 -0700

    Split out helper function TouchListenerAcceptReject()
    
    This will be used for accepting and rejecting touches in the future.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/events.c b/dix/events.c
index b9f9cfa..a137d6f 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1273,18 +1273,11 @@ ComputeFreezes(void)
                        event->root_x, event->root_y);
         if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin)) {
             if (IsTouchEvent((InternalEvent *) event)) {
-                InternalEvent *events = InitEventList(GetMaximumEventsNum());
-                int i, nev;
                 TouchPointInfoPtr ti =
                     TouchFindByClientID(replayDev, event->touchid);
                 BUG_WARN(!ti);
-                nev =
-                    GetTouchOwnershipEvents(events, replayDev, ti,
-                                            XIRejectTouch,
-                                            ti->listeners[0].listener, 0);
-                for (i = 0; i < nev; i++)
-                    mieqProcessDeviceEvent(replayDev, events + i, NULL);
-                ProcessInputEvents();
+
+                TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
             }
             else if (replayDev->focus &&
                      !IsPointerEvent((InternalEvent *) event))
diff --git a/dix/touch.c b/dix/touch.c
index 0829b65..72faad5 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -960,15 +960,48 @@ TouchListenerGone(XID resource)
 }
 
 int
+TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti, int listener,
+                          int mode)
+{
+    InternalEvent *events;
+    int nev;
+    int i;
+
+    if (listener > 0) {
+        if (mode == XIRejectTouch)
+            TouchRejected(dev, ti, ti->listeners[listener].listener, NULL);
+        else
+            ti->listeners[listener].state = LISTENER_EARLY_ACCEPT;
+
+        return Success;
+    }
+
+    events = InitEventList(GetMaximumEventsNum());
+    if (!events) {
+        BUG_WARN_MSG(TRUE, "Failed to allocate touch ownership events\n");
+        return BadAlloc;
+    }
+
+    nev = GetTouchOwnershipEvents(events, dev, ti, mode,
+                                  ti->listeners[0].listener, 0);
+    BUG_WARN_MSG(nev == 0, "Failed to get touch ownership events\n");
+
+    for (i = 0; i < nev; i++)
+        mieqProcessDeviceEvent(dev, events + i, NULL);
+
+    ProcessInputEvents();
+
+    FreeEventList(events, GetMaximumEventsNum());
+
+    return nev ? Success : BadMatch;
+}
+
+int
 TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
                   uint32_t touchid, Window grab_window, XID *error)
 {
     TouchPointInfoPtr ti;
-    int nev, i;
-    InternalEvent *events = InitEventList(GetMaximumEventsNum());
-
-    if (!events)
-        return BadAlloc;
+    int i;
 
     if (!dev->touch) {
         *error = dev->id;
@@ -989,24 +1022,5 @@ TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
     if (i == ti->num_listeners)
         return BadAccess;
 
-    if (i > 0) {
-        if (mode == XIRejectTouch)
-            TouchRejected(dev, ti, ti->listeners[i].listener, NULL);
-        else
-            ti->listeners[i].state = LISTENER_EARLY_ACCEPT;
-
-        return Success;
-    }
-
-    nev = GetTouchOwnershipEvents(events, dev, ti, mode,
-                                  ti->listeners[0].listener, 0);
-    if (nev == 0)
-        return BadAlloc;
-    for (i = 0; i < nev; i++)
-        mieqProcessDeviceEvent(dev, events + i, NULL);
-
-    ProcessInputEvents();
-
-    FreeEventList(events, GetMaximumEventsNum());
-    return Success;
+    return TouchListenerAcceptReject(dev, ti, i, mode);
 }
diff --git a/include/input.h b/include/input.h
index d891fe5..9a6fdfe 100644
--- a/include/input.h
+++ b/include/input.h
@@ -572,6 +572,8 @@ extern int TouchConvertToPointerEvent(const InternalEvent *ev,
 extern int TouchGetPointerEventType(const InternalEvent *ev);
 extern void TouchRemovePointerGrab(DeviceIntPtr dev);
 extern void TouchListenerGone(XID resource);
+extern int TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                                     int listener, int mode);
 extern int TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
                              uint32_t touchid, Window grab_window, XID *error);
 
commit 93c33403642a3de3c9d141ad7940a7b880846aad
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Apr 4 12:59:55 2012 -0700

    Only set XI2 mask if pointer emulation is for XI2 client
    
    The current code returns a reference to memory that may not actually be
    an XI2 mask. Instead, only return a value when an XI2 client has
    selected for events.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Jeremy Huddleston <jeremyhu at apple.com>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 7da80aa..ab2f044 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1327,6 +1327,7 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
 {
     int rc;
     InputClients *iclients = NULL;
+    *mask = NULL;
 
     if (listener->type == LISTENER_GRAB ||
         listener->type == LISTENER_POINTER_GRAB) {
@@ -1378,6 +1379,7 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
             if (!iclients)
                 return FALSE;
 
+            *mask = iclients->xi2mask;
             *client = rClient(iclients);
         }
         else if (listener->level == XI) {
@@ -1409,7 +1411,6 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
             *client = oclients ? rClient(oclients) : wClient(*win);
         }
 
-        *mask = iclients ? iclients->xi2mask : NULL;
         *grab = NULL;
     }
 
commit 4c1dfd21937efc6a85fb204a73dd7d7151d54daa
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Apr 4 12:57:40 2012 -0700

    Check core event mask properly for pointer emulated touch events
    
    The current code checks the core event mask as though it were an XI2
    mask. This change fixes the checks so the proper client and event masks
    are used.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Jeremy Huddleston <jeremyhu at apple.com>
    Acked-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index c05c226..7da80aa 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1377,6 +1377,8 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
             BUG_WARN(!iclients);
             if (!iclients)
                 return FALSE;
+
+            *client = rClient(iclients);
         }
         else if (listener->level == XI) {
             int xi_type = GetXIType(TouchGetPointerEventType(ev));
@@ -1389,20 +1391,24 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
             BUG_WARN(!iclients);
             if (!iclients)
                 return FALSE;
+
+            *client = rClient(iclients);
         }
         else {
             int coretype = GetCoreType(TouchGetPointerEventType(ev));
             Mask core_filter = event_get_filter_from_type(dev, coretype);
+            OtherClients *oclients;
 
             /* all others */
-            nt_list_for_each_entry(iclients,
-                                   (InputClients *) wOtherClients(*win), next)
-                if (iclients->mask[XIAllDevices] & core_filter)
-                break;
-            /* if owner selected, iclients is NULL */
+            nt_list_for_each_entry(oclients,
+                                   (OtherClients *) wOtherClients(*win), next)
+                if (oclients->mask & core_filter)
+                    break;
+
+            /* if owner selected, oclients is NULL */
+            *client = oclients ? rClient(oclients) : wClient(*win);
         }
 
-        *client = iclients ? rClient(iclients) : wClient(*win);
         *mask = iclients ? iclients->xi2mask : NULL;
         *grab = NULL;
     }
commit 3720aa33ee50788dd3d4acc9bbf8dfcb72c8f5ce
Author: Erkki Seppälä <erkki.seppala at vincit.fi>
Date:   Thu Apr 7 12:53:51 2011 +0300

    Added resourceproto version dependency, >= 1.2.0 now required
    
    Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>

diff --git a/configure.ac b/configure.ac
index 65d29f2..ea1d286 100644
--- a/configure.ac
+++ b/configure.ac
@@ -759,7 +759,7 @@ VIDEOPROTO="videoproto"
 COMPOSITEPROTO="compositeproto >= 0.4"
 RECORDPROTO="recordproto >= 1.13.99.1"
 SCRNSAVERPROTO="scrnsaverproto >= 1.1"
-RESOURCEPROTO="resourceproto"
+RESOURCEPROTO="resourceproto >= 1.2.0"
 DRIPROTO="xf86driproto >= 2.1.0"
 DRI2PROTO="dri2proto >= 2.6"
 XINERAMAPROTO="xineramaproto"
commit 233eab4d05cae1fdb4129a2e9905961b78693f74
Author: Erkki Seppälä <erkki.seppala at vincit.fi>
Date:   Wed Dec 8 17:09:30 2010 +0200

    dix: add reference count of the resource to ResourceSizeRec
    
    The ResourceSizeRec now contains the number of references to the
    resource. For example a Pixmap knows this value and it can be useful
    for determining the "weight" of the resource. Typically this value
    is 1.
    
    Reviewed-by: Rami Ylimäki <rami.ylimaki at vincit.fi>
    Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>

diff --git a/Xext/xres.c b/Xext/xres.c
index b7933f2..ecef0c0 100644
--- a/Xext/xres.c
+++ b/Xext/xres.c
@@ -27,6 +27,7 @@
 #include "list.h"
 #include "misc.h"
 #include <string.h>
+#include "hashtable.h"
 #include "picturestr.h"
 #include "compint.h"
 
@@ -39,6 +40,8 @@ typedef struct {
     /* data follows */
 } FragmentList;
 
+#define FRAGMENT_DATA(ptr) ((void*) ((char*) (ptr) + sizeof(FragmentList)))
+
 /** @brief Holds structure for the generated response to
            ProcXResQueryClientIds; used by ConstructClientId* -functions */
 typedef struct {
@@ -48,6 +51,41 @@ typedef struct {
     int           sentClientMasks[MAXCLIENTS];
 } ConstructClientIdCtx;
 
+/** @brief Holds the structure for information required to
+           generate the response to XResQueryResourceBytes. In addition
+           to response it contains information on the query as well,
+           as well as some volatile information required by a few
+           functions that cannot take that information directly
+           via a parameter, as they are called via already-existing
+           higher order functions. */
+typedef struct {
+    ClientPtr     sendClient;
+    int           numSizes;
+    int           resultBytes;
+    struct xorg_list response;
+    int           status;
+    long          numSpecs;
+    xXResResourceIdSpec *specs;
+    HashTable     visitedResources;
+
+    /* Used by AddSubResourceSizeSpec when AddResourceSizeValue is
+       handling crossreferences */
+    HashTable     visitedSubResources;
+
+    /* used when ConstructResourceBytesCtx is passed to
+       AddResourceSizeValue2 via FindClientResourcesByType */
+    RESTYPE       resType;
+
+    /* used when ConstructResourceBytesCtx is passed to
+       AddResourceSizeValueByResource from ConstructResourceBytesByResource */
+    xXResResourceIdSpec       *curSpec;
+
+    /** Used when iterating through a single resource's subresources
+
+        @see AddSubResourceSizeSpec */
+    xXResResourceSizeValue    *sizeValue;
+} ConstructResourceBytesCtx;
+
 /** @brief Allocate and add a sequence of bytes at the end of a fragment list.
            Call DestroyFragments to release the list.
 
@@ -118,6 +156,37 @@ DestroyConstructClientIdCtx(ConstructClientIdCtx *ctx)
     DestroyFragments(&ctx->response);
 }
 
+static Bool
+InitConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx,
+                              ClientPtr                  sendClient,
+                              long                       numSpecs,
+                              xXResResourceIdSpec       *specs)
+{
+    ctx->sendClient = sendClient;
+    ctx->numSizes = 0;
+    ctx->resultBytes = 0;
+    xorg_list_init(&ctx->response);
+    ctx->status = Success;
+    ctx->numSpecs = numSpecs;
+    ctx->specs = specs;
+    ctx->visitedResources = ht_create(sizeof(XID), 0,
+                                      ht_resourceid_hash, ht_resourceid_compare,
+                                      NULL);
+
+    if (!ctx->visitedResources) {
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+
+static void
+DestroyConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx)
+{
+    DestroyFragments(&ctx->response);
+    ht_destroy(ctx->visitedResources);
+}
+
 static int
 ProcXResQueryVersion(ClientPtr client)
 {
@@ -293,7 +362,7 @@ static void
 ResFindResourcePixmaps(pointer value, XID id, RESTYPE type, pointer cdata)
 {
     SizeType sizeFunc = GetResourceTypeSizeFunc(type);
-    ResourceSizeRec size = { 0, 0 };
+    ResourceSizeRec size = { 0, 0, 0 };
     unsigned long *bytes = cdata;
 
     sizeFunc(value, id, &size);
@@ -616,6 +685,388 @@ ProcXResQueryClientIds (ClientPtr client)
     return rc;
 }
 
+/** @brief Swaps xXResResourceIdSpec endianess */
+static void
+SwapXResResourceIdSpec(xXResResourceIdSpec *spec)
+{
+    swapl(&spec->resource);
+    swapl(&spec->type);
+}
+
+/** @brief Swaps xXResResourceSizeSpec endianess */
+static void
+SwapXResResourceSizeSpec(xXResResourceSizeSpec *size)
+{
+    SwapXResResourceIdSpec(&size->spec);
+    swapl(&size->bytes);
+    swapl(&size->refCount);
+    swapl(&size->useCount);
+}
+
+/** @brief Swaps xXResResourceSizeValue endianess */
+static void
+SwapXResResourceSizeValue(xXResResourceSizeValue *rep)
+{
+    SwapXResResourceSizeSpec(&rep->size);
+    swapl(&rep->numCrossReferences);
+}
+
+/** @brief Swaps the response bytes */
+static void
+SwapXResQueryResourceBytes(struct xorg_list *response)
+{
+    struct xorg_list *it = response->next;
+    int c;
+
+    while (it != response) {
+        xXResResourceSizeValue *value = FRAGMENT_DATA(it);
+        it = it->next;
+        for (c = 0; c < value->numCrossReferences; ++c) {
+            xXResResourceSizeSpec *spec = FRAGMENT_DATA(it);
+            SwapXResResourceSizeSpec(spec);
+            it = it->next;
+        }
+        SwapXResResourceSizeValue(value);
+    }
+}
+
+/** @brief Adds xXResResourceSizeSpec describing a resource's size into
+           the buffer contained in the context. The resource is considered
+           to be a subresource.
+
+   @see AddResourceSizeValue
+
+   @param[in] value     The X resource object on which to add information
+                        about to the buffer
+   @param[in] id        The ID of the X resource
+   @param[in] type      The type of the X resource
+   @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
+                        Void pointer type is used here to satisfy the type
+                        FindRes
+*/
+static void
+AddSubResourceSizeSpec(pointer value,
+                       XID id,
+                       RESTYPE type,
+                       pointer cdata)
+{
+    ConstructResourceBytesCtx *ctx = cdata;
+
+    if (ctx->status == Success) {
+        xXResResourceSizeSpec **prevCrossRef =
+          ht_find(ctx->visitedSubResources, &value);
+        if (!prevCrossRef) {
+            Bool ok = TRUE;
+            xXResResourceSizeSpec *crossRef =
+                AddFragment(&ctx->response, sizeof(xXResResourceSizeSpec));
+            ok = ok && crossRef != NULL;
+            if (ok) {
+                xXResResourceSizeSpec **p;
+                p = ht_add(ctx->visitedSubResources, &value);
+                if (!p) {
+                    ok = FALSE;
+                } else {
+                    *p = crossRef;
+                }
+            }
+            if (!ok) {
+                ctx->status = BadAlloc;
+            } else {
+                SizeType sizeFunc = GetResourceTypeSizeFunc(type);
+                ResourceSizeRec size = { 0, 0, 0 };
+                sizeFunc(value, id, &size);
+
+                crossRef->spec.resource = id;
+                crossRef->spec.type = type;
+                crossRef->bytes = size.resourceSize;
+                crossRef->refCount = size.refCnt;
+                crossRef->useCount = 1;
+
+                ++ctx->sizeValue->numCrossReferences;
+
+                ctx->resultBytes += sizeof(*crossRef);
+            }
+        } else {
+            /* if we have visited the subresource earlier (from current parent
+               resource), just increase its use count by one */
+            ++(*prevCrossRef)->useCount;
+        }
+    }
+}
+
+/** @brief Adds xXResResourceSizeValue describing a resource's size into
+           the buffer contained in the context. In addition, the
+           subresources are iterated and added as xXResResourceSizeSpec's
+           by using AddSubResourceSizeSpec
+
+   @see AddSubResourceSizeSpec
+
+   @param[in] value     The X resource object on which to add information
+                        about to the buffer
+   @param[in] id        The ID of the X resource
+   @param[in] type      The type of the X resource
+   @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
+                        Void pointer type is used here to satisfy the type
+                        FindRes
+*/
+static void
+AddResourceSizeValue(pointer ptr, XID id, RESTYPE type, pointer cdata)
+{
+    ConstructResourceBytesCtx *ctx = cdata;
+    if (ctx->status == Success &&
+        !ht_find(ctx->visitedResources, &id)) {
+        Bool ok = TRUE;
+        HashTable ht;
+        HtGenericHashSetupRec htSetup = {
+            .keySize = sizeof(void*)
+        };
+
+        /* it doesn't matter that we don't undo the work done here
+         * immediately. All but ht_init will be undone at the end
+         * of the request and there can happen no failure after
+         * ht_init, so we don't need to clean it up here in any
+         * special way */
+
+        xXResResourceSizeValue *value =
+            AddFragment(&ctx->response, sizeof(xXResResourceSizeValue));
+        if (!value) {
+            ok = FALSE;
+        }
+        ok = ok && ht_add(ctx->visitedResources, &id);
+        if (ok) {
+            ht = ht_create(htSetup.keySize,
+                           sizeof(xXResResourceSizeSpec*),
+                           ht_generic_hash, ht_generic_compare,
+                           &htSetup);
+            ok = ok && ht;
+        }
+
+        if (!ok) {
+            ctx->status = BadAlloc;
+        } else {
+            SizeType sizeFunc = GetResourceTypeSizeFunc(type);
+            ResourceSizeRec size = { 0, 0, 0 };
+
+            sizeFunc(ptr, id, &size);
+
+            value->size.spec.resource = id;
+            value->size.spec.type = type;
+            value->size.bytes = size.resourceSize;
+            value->size.refCount = size.refCnt;
+            value->size.useCount = 1;
+            value->numCrossReferences = 0;
+
+            ctx->sizeValue = value;
+            ctx->visitedSubResources = ht;
+            FindSubResources(ptr, type, AddSubResourceSizeSpec, ctx);
+            ctx->visitedSubResources = NULL;
+            ctx->sizeValue = NULL;
+
+            ctx->resultBytes += sizeof(*value);
+            ++ctx->numSizes;
+
+            ht_destroy(ht);
+        }
+    }
+}
+
+/** @brief A variant of AddResourceSizeValue that passes the resource type
+           through the context object to satisfy the type FindResType
+
+   @see AddResourceSizeValue
+
+   @param[in] ptr        The resource
+   @param[in] id         The resource ID
+   @param[in/out] cdata  The context object that contains the resource type
+*/
+static void
+AddResourceSizeValueWithResType(pointer ptr, XID id, pointer cdata)
+{
+    ConstructResourceBytesCtx *ctx = cdata;
+    AddResourceSizeValue(ptr, id, ctx->resType, cdata);
+}
+
+/** @brief Adds the information of a resource into the buffer if it matches
+           the match condition.
+
+   @see AddResourceSizeValue
+
+   @param[in] ptr        The resource
+   @param[in] id         The resource ID
+   @param[in] type       The resource type
+   @param[in/out] cdata  The context object as a void pointer to satisfy the
+                         type FindAllRes
+*/
+static void
+AddResourceSizeValueByResource(pointer ptr, XID id, RESTYPE type, pointer cdata)
+{
+    ConstructResourceBytesCtx *ctx = cdata;
+    xXResResourceIdSpec *spec = ctx->curSpec;
+
+    if ((!spec->type || spec->type == type) &&
+        (!spec->resource || spec->resource == id)) {
+        AddResourceSizeValue(ptr, id, type, ctx);
+    }
+}
+
+/** @brief Add all resources of the client into the result buffer
+           disregarding all those specifications that specify the
+           resource by its ID. Those are handled by
+           ConstructResourceBytesByResource
+
+   @see ConstructResourceBytesByResource
+
+   @param[in] aboutClient  Which client is being considered
+   @param[in/out] ctx      The context that contains the resource id
+                           specifications as well as the result buffer
+*/
+static void
+ConstructClientResourceBytes(ClientPtr aboutClient,
+                             ConstructResourceBytesCtx *ctx)
+{
+    int specIdx;
+    for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
+        xXResResourceIdSpec* spec = ctx->specs + specIdx;
+        if (spec->resource) {
+            /* these specs are handled elsewhere */
+        } else if (spec->type) {
+            ctx->resType = spec->type;
+            FindClientResourcesByType(aboutClient, spec->type,
+                                      AddResourceSizeValueWithResType, ctx);
+        } else {
+            FindAllClientResources(aboutClient, AddResourceSizeValue, ctx);
+        }
+    }
+}
+
+/** @brief Add the sizes of all such resources that can are specified by
+           their ID in the resource id specification. The scan can
+           by limited to a client with the aboutClient parameter
+
+   @see ConstructResourceBytesByResource
+
+   @param[in] aboutClient  Which client is being considered. This may be None
+                           to mean all clients.
+   @param[in/out] ctx      The context that contains the resource id
+                           specifications as well as the result buffer. In
+                           addition this function uses the curSpec field to
+                           keep a pointer to the current resource id
+                           specification in it, which can be used by
+                           AddResourceSizeValueByResource .
+*/
+static void
+ConstructResourceBytesByResource(XID aboutClient, ConstructResourceBytesCtx *ctx)
+{
+    int specIdx;
+    for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
+        xXResResourceIdSpec *spec = ctx->specs + specIdx;
+        if (spec->resource) {
+            int cid = CLIENT_ID(spec->resource);
+            if (cid < currentMaxClients &&
+                (aboutClient == None || cid == aboutClient)) {
+                ClientPtr client = clients[cid];
+                if (client) {
+                    ctx->curSpec = spec;
+                    FindAllClientResources(client,
+                                           AddResourceSizeValueByResource,
+                                           ctx);
+                }
+            }
+        }
+    }
+}
+
+/** @brief Build the resource size response for the given client
+           (or all if not specified) per the parameters set up
+           in the context object.
+
+  @param[in] aboutClient  Which client to consider or None for all clients
+  @param[in/out] ctx      The context object that contains the request as well
+                          as the response buffer.
+*/
+static int
+ConstructResourceBytes(XID aboutClient,
+                       ConstructResourceBytesCtx *ctx)
+{
+    if (aboutClient) {
+        int clientIdx = CLIENT_ID(aboutClient);
+        ClientPtr client = NullClient;
+
+        if ((clientIdx >= currentMaxClients) || !clients[clientIdx]) {
+            ctx->sendClient->errorValue = aboutClient;
+            return BadValue;
+        }
+
+        client = clients[clientIdx];
+
+        ConstructClientResourceBytes(client, ctx);
+        ConstructResourceBytesByResource(aboutClient, ctx);
+    } else {
+        int clientIdx;
+
+        ConstructClientResourceBytes(NULL, ctx);
+
+        for (clientIdx = 0; clientIdx < currentMaxClients; ++clientIdx) {
+            ClientPtr client = clients[clientIdx];
+
+            if (client) {
+                ConstructClientResourceBytes(client, ctx);
+            }
+        }
+
+        ConstructResourceBytesByResource(None, ctx);
+    }
+
+
+    return ctx->status;
+}
+
+/** @brief Implements the XResQueryResourceBytes of XResProto v1.2 */
+static int
+ProcXResQueryResourceBytes (ClientPtr client)
+{
+    REQUEST(xXResQueryResourceBytesReq);
+
+    xXResQueryResourceBytesReply rep;
+    int                          rc;
+    ConstructResourceBytesCtx    ctx;
+
+    REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
+    REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
+                       stuff->numSpecs * sizeof(ctx.specs[0]));
+
+    if (!InitConstructResourceBytesCtx(&ctx, client,
+                                       stuff->numSpecs,
+                                       (void*) ((char*) stuff +
+                                                sz_xXResQueryResourceBytesReq))) {
+        return BadAlloc;
+    }
+
+    rc = ConstructResourceBytes(stuff->client, &ctx);
+
+    if (rc == Success) {
+        rep.type = X_Reply;
+        rep.sequenceNumber = client->sequence;
+        rep.numSizes = ctx.numSizes;
+        rep.length = bytes_to_int32(ctx.resultBytes);
+
+        if (client->swapped) {
+            swaps (&rep.sequenceNumber);
+            swapl (&rep.length);
+            swapl (&rep.numSizes);
+
+            SwapXResQueryResourceBytes(&ctx.response);
+        }
+
+        WriteToClient(client,sizeof(rep),(char*)&rep);
+        WriteFragmentsToClient(client, &ctx.response);
+    }
+
+    DestroyConstructResourceBytesCtx(&ctx);
+
+    return rc;
+}
+
 static int
 ProcResDispatch(ClientPtr client)
 {
@@ -632,8 +1083,7 @@ ProcResDispatch(ClientPtr client)
     case X_XResQueryClientIds:
         return ProcXResQueryClientIds(client);
     case X_XResQueryResourceBytes:
-        /* not implemented yet */
-        return BadRequest;
+        return ProcXResQueryResourceBytes(client);
     default: break;
     }
 
@@ -676,6 +1126,28 @@ SProcXResQueryClientIds (ClientPtr client)
     return ProcXResQueryClientIds(client);
 }
 
+/** @brief Implements the XResQueryResourceBytes of XResProto v1.2.
+    This variant byteswaps request contents before issuing the
+    rest of the work to ProcXResQueryResourceBytes */
+static int
+SProcXResQueryResourceBytes (ClientPtr client)
+{
+    REQUEST(xXResQueryResourceBytesReq);
+    int c;
+    xXResResourceIdSpec *specs = (void*) ((char*) stuff + sizeof(*stuff));
+
+    swapl(&stuff->numSpecs);
+    REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
+    REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
+                       stuff->numSpecs * sizeof(specs[0]));
+
+    for (c = 0; c < stuff->numSpecs; ++c) {
+        SwapXResResourceIdSpec(specs + c);
+    }
+
+    return ProcXResQueryResourceBytes(client);
+}
+
 static int
 SProcResDispatch (ClientPtr client)
 {
@@ -694,8 +1166,7 @@ SProcResDispatch (ClientPtr client)
     case X_XResQueryClientIds:
         return SProcXResQueryClientIds(client);
     case X_XResQueryResourceBytes:
-        /* not implemented yet */
-        return BadRequest;
+        return SProcXResQueryResourceBytes(client);
     default: break;
     }
 
diff --git a/dix/resource.c b/dix/resource.c
index cdbe547..2aafa34 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -207,6 +207,7 @@ GetDefaultBytes(pointer value, XID id, ResourceSizePtr size)
 {
     size->resourceSize = 0;
     size->pixmapRefSize = 0;
+    size->refCnt = 1;
 }
 
 /**
@@ -273,6 +274,7 @@ GetPixmapBytes(pointer value, XID id, ResourceSizePtr size)
 
     size->resourceSize = 0;
     size->pixmapRefSize = 0;
+    size->refCnt = pixmap->refcnt;
 
     if (pixmap && pixmap->refcnt)
     {
@@ -298,7 +300,7 @@ static void
 GetWindowBytes(pointer value, XID id, ResourceSizePtr size)
 {
     SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
-    ResourceSizeRec pixmapSize = { 0, 0 };
+    ResourceSizeRec pixmapSize = { 0, 0, 0 };
     WindowPtr window = value;
 
     /* Currently only pixmap bytes are reported to clients. */
@@ -306,6 +308,9 @@ GetWindowBytes(pointer value, XID id, ResourceSizePtr size)
 
     /* Calculate pixmap reference sizes. */
     size->pixmapRefSize = 0;
+
+    size->refCnt = 1;
+
     if (window->backgroundState == BackgroundPixmap)
     {
         PixmapPtr pixmap = window->background.pixmap;
@@ -368,7 +373,7 @@ static void
 GetGcBytes(pointer value, XID id, ResourceSizePtr size)
 {
     SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
-    ResourceSizeRec pixmapSize = { 0, 0 };
+    ResourceSizeRec pixmapSize = { 0, 0, 0 };
     GCPtr gc = value;
 
     /* Currently only pixmap bytes are reported to clients. */
@@ -376,6 +381,8 @@ GetGcBytes(pointer value, XID id, ResourceSizePtr size)
 
     /* Calculate pixmap reference sizes. */
     size->pixmapRefSize = 0;
+
+    size->refCnt = 1;
     if (gc->stipple)
     {
         PixmapPtr pixmap = gc->stipple;
diff --git a/include/resource.h b/include/resource.h
index ae5dd51..19f46d1 100644
--- a/include/resource.h
+++ b/include/resource.h
@@ -162,6 +162,8 @@ typedef struct {
     unsigned long resourceSize;
     /* Size attributed to pixmap references from the resource. */
     unsigned long pixmapRefSize;
+    /* Number of references to this resource; typically 1 */
+    unsigned long refCnt;
 } ResourceSizeRec, *ResourceSizePtr;
 
 typedef void (*SizeType)(pointer /*value*/,
diff --git a/render/picture.c b/render/picture.c
index 24b6ba0..da3e499 100644
--- a/render/picture.c
+++ b/render/picture.c
@@ -600,12 +600,14 @@ GetPictureBytes(pointer value, XID id, ResourceSizePtr size)
     /* Currently only pixmap bytes are reported to clients. */
     size->resourceSize = 0;
 
+    size->refCnt = picture->refcnt;
+
     /* Calculate pixmap reference sizes. */
     size->pixmapRefSize = 0;
     if (picture->pDrawable && (picture->pDrawable->type == DRAWABLE_PIXMAP))
     {
         SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
-        ResourceSizeRec pixmapSize = { 0, 0 };
+        ResourceSizeRec pixmapSize = { 0, 0, 0 };
         PixmapPtr pixmap = (PixmapPtr)picture->pDrawable;
         pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
         size->pixmapRefSize += pixmapSize.pixmapRefSize;
commit ccb3e78124fb05defd0c9b438746b79d84dfc3ae
Author: Erkki Seppälä <erkki.seppala at vincit.fi>
Date:   Tue Dec 14 12:18:23 2010 +0200

    Xext: add a generic hashtable implementation
    
    The generic hashtable implementation adds a key-value container, that
    keeps the key and value inside the hashtable structure and manages
    their memory by itself. This data structure is best suited for
    fixed-length keys and values.
    
    One creates a new hash table with ht_create and disposes it with
    ht_destroy. ht_create accepts the key and value sizes (in bytes) in
    addition to the hashing and comparison functions to use. When adding
    keys with ht_add, they will be copied into the hash and a pointer to
    the value will be returned: data may be put into this structure (or if
    the hash table is to be used as a set, one can just not put anything
    in).
    
    The hash table comes also with one generic hashing function plus a
    comparison function to facilitate ease of use. It also has a custom
    hashing and comparison functions for hashing resource IDs with
    HashXID.
    
    Reviewed-by: Rami Ylimäki <rami.ylimaki at vincit.fi>
    Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>

diff --git a/Xext/Makefile.am b/Xext/Makefile.am
index cb432e0..5929a3e 100644
--- a/Xext/Makefile.am
+++ b/Xext/Makefile.am
@@ -50,7 +50,7 @@ MODULE_SRCS  += $(XV_SRCS)
 endif
 
 # XResource extension: lets clients get data about per-client resource usage
-RES_SRCS = xres.c
+RES_SRCS = hashtable.c xres.c
 if RES
 MODULE_SRCS  += $(RES_SRCS)
 endif
diff --git a/Xext/hashtable.c b/Xext/hashtable.c
new file mode 100644
index 0000000..2adf92e
--- /dev/null
+++ b/Xext/hashtable.c
@@ -0,0 +1,291 @@
+#include <stdlib.h>
+#include "misc.h"
+#include "hashtable.h"
+
+/* HashResourceID */
+#include "resource.h"
+
+#define INITHASHSIZE 6
+#define MAXHASHSIZE 11
+
+struct HashTableRec {
+    int             keySize;
+    int             dataSize;
+
+    int             elements;   /* number of elements inserted */
+    int             bucketBits; /* number of buckets is 1 << bucketBits */
+    struct xorg_list *buckets;  /* array of bucket list heads */
+
+    HashFunc        hash;
+    HashCompareFunc compare;
+
+    pointer         cdata;
+};
+
+typedef struct {
+    struct xorg_list l;
+    void *key;
+    void *data;
+} BucketRec, *BucketPtr;
+
+HashTable
+ht_create(int             keySize,
+          int             dataSize,
+          HashFunc        hash,
+          HashCompareFunc compare,
+          pointer         cdata)
+{
+    int c;
+    int numBuckets;
+    HashTable ht = malloc(sizeof(struct HashTableRec));
+
+    if (!ht) {
+        return NULL;
+    }
+
+    ht->keySize = keySize;
+    ht->dataSize = dataSize;
+    ht->hash = hash;
+    ht->compare = compare;
+    ht->elements = 0;
+    ht->bucketBits = INITHASHSIZE;
+    numBuckets = 1 << ht->bucketBits;
+    ht->buckets = malloc(numBuckets * sizeof(*ht->buckets));
+    ht->cdata = cdata;
+
+    if (ht->buckets) {
+        for (c = 0; c < numBuckets; ++c) {
+            xorg_list_init(&ht->buckets[c]);
+        }
+        return ht;
+    } else {
+        free(ht);
+        return NULL;
+    }
+}
+
+void
+ht_destroy(HashTable ht)
+{
+    int c;
+    BucketPtr it, tmp;
+    int numBuckets = 1 << ht->bucketBits;
+    for (c = 0; c < numBuckets; ++c) {
+        xorg_list_for_each_entry_safe(it, tmp, &ht->buckets[c], l) {
+            xorg_list_del(&it->l);
+            free(it);
+        }
+    }
+    free(ht->buckets);
+}
+
+static Bool
+double_size(HashTable ht)
+{
+    struct xorg_list *newBuckets;
+    int numBuckets = 1 << ht->bucketBits;
+    int newBucketBits = ht->bucketBits + 1;
+    int newNumBuckets = 1 << newBucketBits;
+    int c;
+
+    newBuckets = malloc(newNumBuckets * sizeof(*ht->buckets));
+    if (newBuckets) {
+        for (c = 0; c < newNumBuckets; ++c) {
+            xorg_list_init(&newBuckets[c]);
+        }
+
+        for (c = 0; c < numBuckets; ++c) {
+            BucketPtr it, tmp;
+            xorg_list_for_each_entry_safe(it, tmp, &ht->buckets[c], l) {
+                struct xorg_list *newBucket =
+                    &newBuckets[ht->hash(ht->cdata, it->key, newBucketBits)];
+                xorg_list_del(&it->l);
+                xorg_list_add(&it->l, newBucket);
+            }
+        }
+        free(ht->buckets);
+
+        ht->buckets = newBuckets;
+        ht->bucketBits = newBucketBits;
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+pointer
+ht_add(HashTable ht, pointer key)
+{
+    unsigned index = ht->hash(ht->cdata, key, ht->bucketBits);
+    struct xorg_list *bucket = &ht->buckets[index];
+    BucketRec *elem = calloc(1, sizeof(BucketRec));
+    if (!elem) {
+        goto outOfMemory;
+    }
+    elem->key = malloc(ht->keySize);
+    if (!elem->key) {
+        goto outOfMemory;
+    }
+    /* we avoid signaling an out-of-memory error if dataSize is 0 */
+    elem->data = calloc(1, ht->dataSize);
+    if (ht->dataSize && !elem->data) {
+        goto outOfMemory;
+    }
+    xorg_list_add(&elem->l, bucket);
+    ++ht->elements;
+
+    memcpy(elem->key, key, ht->keySize);
+
+    if (ht->elements > 4 * (1 << ht->bucketBits) &&
+        ht->bucketBits < MAXHASHSIZE) {
+        if (!double_size(ht)) {
+            --ht->elements;
+            xorg_list_del(&elem->l);
+            goto outOfMemory;
+        }
+    }
+
+    /* if memory allocation has failed due to dataSize being 0, return
+       a "dummy" pointer pointing at the of the key */
+    return elem->data ? elem->data : ((char*) elem->key + ht->keySize);
+
+ outOfMemory:
+    if (elem) {
+        free(elem->key);
+        free(elem->data);
+        free(elem);
+    }
+
+    return NULL;
+}
+
+void
+ht_remove(HashTable ht, pointer key)
+{
+    unsigned index = ht->hash(ht->cdata, key, ht->bucketBits);
+    struct xorg_list *bucket = &ht->buckets[index];
+    BucketPtr it;
+
+    xorg_list_for_each_entry(it, bucket, l) {
+        if (ht->compare(ht->cdata, key, it->key) == 0) {
+            xorg_list_del(&it->l);
+            --ht->elements;
+            free(it->key);
+            free(it->data);
+            free(it);
+            return;
+        }
+    }
+}
+
+pointer
+ht_find(HashTable ht, pointer key)
+{
+    unsigned index = ht->hash(ht->cdata, key, ht->bucketBits);
+    struct xorg_list *bucket = &ht->buckets[index];
+    BucketPtr it;
+
+    xorg_list_for_each_entry(it, bucket, l) {
+        if (ht->compare(ht->cdata, key, it->key) == 0) {
+            return it->data ? it->data : ((char*) it->key + ht->keySize);
+        }
+    }
+
+    return NULL;
+}
+
+void
+ht_dump_distribution(HashTable ht)
+{
+    int c;
+    int numBuckets = 1 << ht->bucketBits;
+    for (c = 0; c < numBuckets; ++c) {
+        BucketPtr it;
+        int n = 0;
+
+        xorg_list_for_each_entry(it, &ht->buckets[c], l) {
+            ++n;
+        }
+        printf("%d: %d\n", c, n);
+    }
+}
+
+/* Picked the function from http://burtleburtle.net/bob/hash/doobs.html by
+   Bob Jenkins, which is released in public domain */
+static CARD32
+one_at_a_time_hash(const void *data, int len)
+{
+    CARD32 hash;
+    int i;
+    const char *key = data;
+    for (hash=0, i=0; i<len; ++i) {
+        hash += key[i];
+        hash += (hash << 10);
+        hash ^= (hash >> 6);
+    }
+    hash += (hash << 3);
+    hash ^= (hash >> 11);
+    hash += (hash << 15);
+    return hash;
+}
+
+unsigned
+ht_generic_hash(void *cdata, const void *ptr, int numBits)
+{
+    HtGenericHashSetupPtr setup = cdata;
+    return one_at_a_time_hash(ptr, setup->keySize) & ~((~0) << numBits);
+}
+
+int
+ht_generic_compare(void *cdata, const void *l, const void *r)
+{
+    HtGenericHashSetupPtr setup = cdata;
+    return memcmp(l, r, setup->keySize);
+}
+
+unsigned
+ht_resourceid_hash(void * cdata, const void * data, int numBits)
+{
+    const XID* idPtr = data;
+    XID id = *idPtr & RESOURCE_ID_MASK;
+    (void) cdata;
+    return HashResourceID(id, numBits);
+}
+
+int
+ht_resourceid_compare(void* cdata, const void* a, const void* b)
+{
+    const XID* xa = a;
+    const XID* xb = b;
+    (void) cdata;
+    return
+        *xa < *xb ? -1 :
+        *xa > *xb ? 1 :
+        0;
+}
+
+void
+ht_dump_contents(HashTable ht,
+                 void (*print_key)(void *opaque, void *key),
+                 void (*print_value)(void *opaque, void *value),
+                 void* opaque)
+{
+    int c;
+    int numBuckets = 1 << ht->bucketBits;
+    for (c = 0; c < numBuckets; ++c) {
+        BucketPtr it;
+        int n = 0;
+
+        printf("%d: ", c);
+        xorg_list_for_each_entry(it, &ht->buckets[c], l) {
+            if (n > 0) {
+                printf(", ");
+            }
+            print_key(opaque, it->key);
+            printf("->");
+            print_value(opaque, it->data);
+            ++n;
+        }
+        printf("\n");
+    }
+}
diff --git a/Xext/hashtable.h b/Xext/hashtable.h
new file mode 100644
index 0000000..5d15984
--- /dev/null
+++ b/Xext/hashtable.h
@@ -0,0 +1,137 @@
+#ifndef HASHTABLE_H
+#define HASHTABLE_H 1
+
+#include <dix-config.h>
+#include <X11/Xfuncproto.h>
+#include <X11/Xdefs.h>
+#include "list.h"
+
+/** @brief A hashing function.
+
+  @param[in/out] cdata  Opaque data that can be passed to HtInit that will
+                        eventually end up here
+  @param[in] ptr        The data to be hashed. The size of the data, if
+                        needed, can be configured via a record that can be
+                        passed via cdata.
+  @param[in] numBits    The number of bits this hash needs to have in the
+                        resulting hash
+
+  @return  A numBits-bit hash of the data
+*/
+typedef unsigned (*HashFunc)(void * cdata, const void * ptr, int numBits);
+
+/** @brief A comparison function for hashed keys.
+
+  @param[in/out] cdata  Opaque data that ca be passed to Htinit that will
+                        eventually end up here
+  @param[in] l          The left side data to be compared
+  @param[in] r          The right side data to be compared
+
+  @return -1 if l < r, 0 if l == r, 1 if l > r
+*/
+typedef int (*HashCompareFunc)(void * cdata, const void * l, const void * r);
+
+struct HashTableRec;
+
+typedef struct HashTableRec *HashTable;
+
+/** @brief  A configuration for HtGenericHash */
+typedef struct {
+    int             keySize;
+} HtGenericHashSetupRec, *HtGenericHashSetupPtr;
+
+/** @brief  ht_create initalizes a hash table for a certain hash table
+            configuration
+
+    @param[out] ht       The hash table structure to initialize
+    @param[in] keySize   The key size in bytes
+    @param[in] dataSize  The data size in bytes
+    @param[in] hash      The hash function to use for hashing keys
+    @param[in] compare   The comparison function for hashing keys
+    @param[in] cdata     Opaque data that will be passed to hash and
+                         comparison functions
+*/
+extern _X_EXPORT HashTable ht_create(int             keySize,
+                                     int             dataSize,
+                                     HashFunc        hash,
+                                     HashCompareFunc compare,
+                                     pointer         cdata);
+/** @brief  HtDestruct deinitializes the structure. It does not free the
+            memory allocated to HashTableRec
+*/
+extern _X_EXPORT void ht_destroy(HashTable ht);
+
+/** @brief  Adds a new key to the hash table. The key will be copied
+            and a pointer to the value will be returned. The data will
+            be initialized with zeroes.
+
+  @param[in/out] ht  The hash table
+  @param[key] key    The key. The contents of the key will be copied.
+
+  @return On error NULL is returned, otherwise a pointer to the data
+          associated with the newly inserted key.
+
+  @note  If dataSize is 0, a pointer to the end of the key may be returned
+         to avoid returning NULL. Obviously the data pointed cannot be
+         modified, as implied by dataSize being 0.
+*/
+extern _X_EXPORT pointer ht_add(HashTable ht, pointer key);
+
+/** @brief  Removes a key from the hash table along with its
+            associated data, which will be free'd.
+*/
+extern _X_EXPORT void ht_remove(HashTable ht, pointer key);
+
+/** @brief  Finds the associated data of a key from the hash table.
+
+   @return  If the key cannot be found, the function returns NULL.
+            Otherwise it returns a pointer to the data associated
+            with the key.
+
+   @note  If dataSize == 0, this function may return NULL
+          even if the key has been inserted! If dataSize == NULL,
+          use HtMember instead to determine if a key has been
+          inserted.
+*/
+extern _X_EXPORT pointer ht_find(HashTable ht, pointer key);
+
+/** @brief  A generic hash function */
+extern _X_EXPORT unsigned ht_generic_hash(void *cdata,
+                                          const void *ptr,
+                                          int numBits);
+
+/** @brief  A generic comparison function. It compares data byte-wise. */
+extern _X_EXPORT int ht_generic_compare(void *cdata,
+                                        const void *l,
+                                        const void *r);
+
+/** @brief  A debugging function that dumps the distribution of the
+            hash table: for each bucket, list the number of elements
+            contained within. */
+extern _X_EXPORT void ht_dump_distribution(HashTable ht);
+
+/** @brief  A debugging function that dumps the contents of the hash
+            table: for each bucket, list the elements contained
+            within. */
+extern _X_EXPORT void ht_dump_contents(HashTable ht,
+                                       void (*print_key)(void *opaque, void *key),
+                                       void (*print_value)(void *opaque, void *value),
+                                       void* opaque);
+
+/** @brief  A hashing function to be used for hashing resource IDs when
+            used with HashTables. It makes no use of cdata, so that can
+            be NULL. It uses HashXID underneath, and should HashXID be
+            unable to hash the value, it switches into using the generic
+            hash function. */
+extern _X_EXPORT unsigned ht_resourceid_hash(void *cdata,
+                                             const void * data,
+                                             int numBits);
+
+/** @brief  A comparison function to be used for comparing resource
+            IDs when used with HashTables. It makes no use of cdata,
+            so that can be NULL. */
+extern _X_EXPORT int ht_resourceid_compare(void *cdata,
+                                           const void *a,
+                                           const void *b);
+
+#endif // HASHTABLE_H
diff --git a/test/Makefile.am b/test/Makefile.am
index eb61470..8c7e412 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -5,7 +5,7 @@ if XORG
 # Tests that require at least some DDX functions in order to fully link
 # For now, requires xf86 ddx, could be adjusted to use another
 SUBDIRS += xi2
-noinst_PROGRAMS += xkb input xtest misc fixes xfree86
+noinst_PROGRAMS += xkb input xtest misc fixes xfree86  hashtabletest
 endif
 check_LTLIBRARIES = libxservertest.la
 
@@ -36,6 +36,7 @@ misc_LDADD=$(TEST_LDADD)
 fixes_LDADD=$(TEST_LDADD)
 xfree86_LDADD=$(TEST_LDADD)
 touch_LDADD=$(TEST_LDADD)
+hashtabletest_LDADD=$(TEST_LDADD) ../Xext/hashtable.c
 
 libxservertest_la_LIBADD = $(XSERVER_LIBS)
 if XORG
diff --git a/test/hashtabletest.c b/test/hashtabletest.c
new file mode 100644
index 0000000..64c7091
--- /dev/null
+++ b/test/hashtabletest.c
@@ -0,0 +1,162 @@
+#include <misc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "hashtable.h"
+#include "resource.h"
+
+static void
+print_xid(void* ptr, void* v)
+{
+    XID *x = v;
+    printf("%ld", *x);
+}
+
+static void
+print_int(void* ptr, void* v)
+{
+    int *x = v;
+    printf("%d", *x);
+}
+
+static int
+test1(void)
+{
+    HashTable h;
+    XID id;
+    int c;
+    int ok = 1;
+    const int numKeys = 420;
+
+    printf("test1\n");
+    h = ht_create(sizeof(XID), sizeof(int), ht_resourceid_hash, ht_resourceid_compare, NULL);
+
+    for (c = 0; c < numKeys; ++c) {
+      int *dest;
+      id = c;
+      dest = ht_add(h, &id);
+      if (dest) {
+        *dest = 2 * c;
+      }
+    }
+
+    printf("Distribution after insertion\n");
+    ht_dump_distribution(h);
+    ht_dump_contents(h, print_xid, print_int, NULL);
+
+    for (c = 0; c < numKeys; ++c) {
+      XID id = c;
+      int* v = ht_find(h, &id);
+      if (v) {
+        if (*v == 2 * c) {
+          // ok
+        } else {
+          printf("Key %d doesn't have expected value %d but has %d instead\n",
+                 c, 2 * c, *v);
+          ok = 0;
+        }
+      } else {
+        ok = 0;
+        printf("Cannot find key %d\n", c);
+      }
+    }
+
+    if (ok) {
+      printf("%d keys inserted and found\n", c);
+
+      for (c = 0; c < numKeys; ++c) {
+        XID id = c;
+        ht_remove(h, &id);
+      }
+
+      printf("Distribution after deletion\n");
+      ht_dump_distribution(h);
+    }
+
+    ht_destroy(h);
+
+    return ok;
+}
+
+static int
+test2(void)
+{
+    HashTable h;
+    XID id;
+    int c;
+    int ok = 1;
+    const int numKeys = 420;
+
+    printf("test2\n");
+    h = ht_create(sizeof(XID), 0, ht_resourceid_hash, ht_resourceid_compare, NULL);
+
+    for (c = 0; c < numKeys; ++c) {
+      id = c;
+      ht_add(h, &id);
+    }
+
+    for (c = 0; c < numKeys; ++c) {
+      XID id = c;
+      if (!ht_find(h, &id)) {
+        ok = 0;
+        printf("Cannot find key %d\n", c);
+      }
+    }
+
+    {
+        XID id = c + 1;
+        if (ht_find(h, &id)) {
+            ok = 0;
+            printf("Could find a key that shouldn't be there\n");
+        }
+    }
+
+    ht_destroy(h);
+
+    if (ok) {
+        printf("Test with empty keys OK\n");
+    } else {
+        printf("Test with empty keys FAILED\n");
+    }
+
+    return ok;
+}
+
+static int
+test3(void)
+{
+    int ok = 1;
+    HtGenericHashSetupRec hashSetup = {
+        .keySize = 4
+    };
+    HashTable h;
+    printf("test3\n");
+    h = ht_create(4, 0, ht_generic_hash, ht_generic_compare, &hashSetup);
+
+    if (!ht_add(h, "helo") ||
+        !ht_add(h, "wrld")) {
+        printf("Could not insert keys\n");
+    }
+
+    if (!ht_find(h, "helo") ||
+        !ht_find(h, "wrld")) {
+        ok = 0;
+        printf("Could not find inserted keys\n");
+    }
+
+    printf("Hash distribution with two strings\n");
+    ht_dump_distribution(h);
+
+    ht_destroy(h);
+
+    return ok;
+}
+
+int
+main(void)
+{
+    int ok = test1();
+    ok = ok && test2();
+    ok = ok && test3();
+
+    return ok ? 0 : 1;
+}
commit a2ac01a8ea8508ed35aa844a589672c1165e05e4
Author: Erkki Seppälä <erkki.seppala at vincit.fi>
Date:   Wed Apr 6 10:16:53 2011 +0300

    dix: don't use a local wrapper for calling HashResourceID
    
    Calls to Hash(client, id) were replaced with calls directly to
    HashResourceID(id, clientTable[client].hashsize) and the Hash-function
    was removed.
    
    Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>

diff --git a/dix/resource.c b/dix/resource.c
index 9714061..cdbe547 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -655,13 +655,13 @@ HashResourceID(XID id, int numBits)
         case 11:
             return ((int)(0x7FF & (id ^ (id>>11))));
     }
-    return -1;
-}
-
-static int
-Hash(int client, XID id)
-{
-    return HashResourceID(id, clientTable[client].hashsize);
+    if (numBits >= 11)
+        return ((int)(0x7FF & (id ^ (id>>11))));
+    else
+    {
+        assert(numBits >= 0);
+        return id & ~((~0) << numBits);
+    }
 }
 
 static XID
@@ -672,7 +672,7 @@ AvailableID(int client, XID id, XID maxid, XID goodid)
     if ((goodid >= id) && (goodid <= maxid))
         return goodid;
     for (; id <= maxid; id++) {
-        res = clientTable[client].resources[Hash(client, id)];
+        res = clientTable[client].resources[HashResourceID(id, clientTable[client].hashsize)];
         while (res && (res->id != id))
             res = res->next;
         if (!res)
@@ -798,7 +798,7 @@ AddResource(XID id, RESTYPE type, pointer value)
     }
     if ((rrec->elements >= 4 * rrec->buckets) && (rrec->hashsize < MAXHASHSIZE))
         RebuildTable(client);
-    head = &rrec->resources[Hash(client, id)];
+    head = &rrec->resources[HashResourceID(id, clientTable[client].hashsize)];
     res = malloc(sizeof(ResourceRec));
     if (!res) {
         (*resourceTypes[type & TypeMask].deleteFunc) (value, id);
@@ -846,7 +846,7 @@ RebuildTable(int client)
         for (res = *rptr; res; res = next) {
             next = res->next;
             res->next = NULL;
-            tptr = &tails[Hash(client, res->id)];
+            tptr = &tails[HashResourceID(res->id, clientTable[client].hashsize)];
             **tptr = res;
             *tptr = &res->next;
         }
@@ -878,7 +878,7 @@ FreeResource(XID id, RESTYPE skipDeleteFuncType)
     int elements;
 
     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) {
-        head = &clientTable[cid].resources[Hash(cid, id)];
+        head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
         eltptr = &clientTable[cid].elements;
 
         prev = head;
@@ -912,7 +912,7 @@ FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
     ResourcePtr *prev, *head;
 
     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) {
-        head = &clientTable[cid].resources[Hash(cid, id)];
+        head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
 
         prev = head;
         while ((res = *prev)) {
@@ -947,7 +947,7 @@ ChangeResourceValue(XID id, RESTYPE rtype, pointer value)
     ResourcePtr res;
 
     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) {
-        res = clientTable[cid].resources[Hash(cid, id)];
+        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
 
         for (; res; res = res->next)
             if ((res->id == id) && (res->type == rtype)) {
@@ -1185,7 +1185,7 @@ dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype,
         return BadImplementation;
 
     if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
-        res = clientTable[cid].resources[Hash(cid, id)];
+        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
 
         for (; res; res = res->next)
             if (res->id == id && res->type == rtype)
@@ -1218,7 +1218,7 @@ dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass,
     *result = NULL;
 
     if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
-        res = clientTable[cid].resources[Hash(cid, id)];
+        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
 
         for (; res; res = res->next)
             if (res->id == id && (res->type & rclass))
diff --git a/include/resource.h b/include/resource.h
index e8f2637..ae5dd51 100644
--- a/include/resource.h
+++ b/include/resource.h
@@ -275,10 +275,12 @@ extern _X_EXPORT RESTYPE TypeMask;
 /** @brief A hashing function to be used for hashing resource IDs
 
     @param id The resource ID to hash
-    @param numBits The number of bits in the resulting hash
+    @param numBits The number of bits in the resulting hash. Must be >=0.
 
-    @note This function can only handle INITHASHSIZE..MAXHASHSIZE bit
-    hashes and will return -1 if numBits is not within those bounds.
+    @note This function is really only for handling
+    INITHASHSIZE..MAXHASHSIZE bit hashes, but will handle any number
+    of bits by either masking numBits lower bits of the ID or by
+    providing at most MAXHASHSIZE hashes.
 */
 extern _X_EXPORT int HashResourceID(XID id,
                                     int numBits);
commit a0b0fb83f91bb82534a0d83fdd6c0222567b098d
Author: Erkki Seppälä <erkki.seppala at vincit.fi>
Date:   Mon Dec 20 12:58:37 2010 +0200

    dix: add hashing functions to resource.h for others to use.
    
    The public hashing function HashResourceID uses the same hashing
    hashing algorithm as resource.c uses internally, but it provides an
    interface that will is usable by external modules. It provides a
    parameter for the number of bits for the hash, instead of finding the
    size from its internal hash table.
    
    Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>

diff --git a/dix/resource.c b/dix/resource.c
index 5691b16..9714061 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -636,27 +636,34 @@ InitClientResources(ClientPtr client)
     return TRUE;
 }
 
-static int
-Hash(int client, XID id)
+int
+HashResourceID(XID id, int numBits)
 {
     id &= RESOURCE_ID_MASK;
-    switch (clientTable[client].hashsize) {
-    case 6:
-        return ((int) (0x03F & (id ^ (id >> 6) ^ (id >> 12))));
-    case 7:
-        return ((int) (0x07F & (id ^ (id >> 7) ^ (id >> 13))));
-    case 8:
-        return ((int) (0x0FF & (id ^ (id >> 8) ^ (id >> 16))));
-    case 9:
-        return ((int) (0x1FF & (id ^ (id >> 9))));
-    case 10:
-        return ((int) (0x3FF & (id ^ (id >> 10))));
-    case 11:
-        return ((int) (0x7FF & (id ^ (id >> 11))));
+    switch (numBits)
+    {
+        case 6:
+            return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
+        case 7:
+            return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
+        case 8:
+            return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
+        case 9:
+            return ((int)(0x1FF & (id ^ (id>>9))));
+        case 10:
+            return ((int)(0x3FF & (id ^ (id>>10))));
+        case 11:
+            return ((int)(0x7FF & (id ^ (id>>11))));
     }
     return -1;
 }
 
+static int
+Hash(int client, XID id)
+{
+    return HashResourceID(id, clientTable[client].hashsize);
+}
+
 static XID
 AvailableID(int client, XID id, XID maxid, XID goodid)
 {
diff --git a/include/resource.h b/include/resource.h
index 663fac4..e8f2637 100644
--- a/include/resource.h
+++ b/include/resource.h
@@ -272,4 +272,15 @@ extern _X_EXPORT unsigned int GetXIDList(ClientPtr /*client */ ,
 extern _X_EXPORT RESTYPE lastResourceType;
 extern _X_EXPORT RESTYPE TypeMask;
 
-#endif                          /* RESOURCE_H */
+/** @brief A hashing function to be used for hashing resource IDs
+
+    @param id The resource ID to hash
+    @param numBits The number of bits in the resulting hash
+
+    @note This function can only handle INITHASHSIZE..MAXHASHSIZE bit
+    hashes and will return -1 if numBits is not within those bounds.
+*/
+extern _X_EXPORT int HashResourceID(XID id,
+                                    int numBits);
+
+#endif /* RESOURCE_H */
commit 3ba0decb4b55a1fd122d269e15b2b2da8ced8624
Author: Erkki Seppälä <erkki.seppala at vincit.fi>
Date:   Wed Dec 8 15:30:57 2010 +0200

    dix: add a mechanism for iterating through all subresources
    
    The mechanism allows iterating even through subresources that don't
    have specific XID's. When such 'resources' are iterated, the XID for
    them will be zero. A resource type can assign an iteration function
    for its subresources with SetResourceTypeFindSubResFunc; by default
    resources are assumed not to contain subresources.
    
    The purpose of this extension is to enable accurate accounting of
    the resources a resource consumes or uses.
    
    This patch provides the subresource iteration functions for Windows
    and GCs.
    
    Reviewed-by: Rami Ylimäki <rami.ylimaki at vincit.fi>
    Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>

diff --git a/dix/resource.c b/dix/resource.c
index 89dfb5b..5691b16 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -184,6 +184,7 @@ RESTYPE TypeMask;
 struct ResourceType {
     DeleteType deleteFunc;
     SizeType sizeFunc;
+    FindTypeSubResources findSubResFunc;
     int errorValue;
 };
 
@@ -209,6 +210,25 @@ GetDefaultBytes(pointer value, XID id, ResourceSizePtr size)
 }
 
 /**
+ * Used by all resources that don't specify a function to iterate
+ * through subresources. Currently this is used for all resources with
+ * insignificant memory usage.
+ *
+ * @see FindSubResources, SetResourceTypeFindSubResFunc
+ *
+ * @param[in] value Pointer to resource object.
+ *
+ * @param[in] func Function to call for each subresource.
+
+ * @param[out] cdata Pointer to opaque data.
+ */
+static void
+DefaultFindSubRes(pointer value, FindAllRes func, pointer cdata)
+{
+    /* do nothing */
+}
+
+/**
  * Calculate drawable size in bytes. Reference counting is not taken
  * into account.
  *
@@ -301,13 +321,45 @@ GetWindowBytes(pointer value, XID id, ResourceSizePtr size)
 }
 
 /**
+ * Iterate through subresources of a window. The purpose of this
+ * function is to gather accurate information on what resources
+ * a resource uses.
+ *
+ * @note Currently only sub-pixmaps are iterated
+ *
+ * @param[in] value  Pointer to a window
+ *
+ * @param[in] func   Function to call with each subresource
+ *
+ * @param[out] cdata Pointer to opaque data
+ */
+static void
+FindWindowSubRes(pointer value, FindAllRes func, pointer cdata)
+{
+    WindowPtr window = value;
+
+    /* Currently only pixmap subresources are reported to clients. */
+
+    if (window->backgroundState == BackgroundPixmap)
+    {
+        PixmapPtr pixmap = window->background.pixmap;
+        func(window->background.pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
+    }
+    if (window->border.pixmap && !window->borderIsPixel)
+    {
+        PixmapPtr pixmap = window->border.pixmap;
+        func(window->background.pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
+    }
+}
+
+/**
  * Calculate graphics context size in bytes. The purpose of this
  * function is to estimate memory usage that can be attributed to all
  * pixmap references of the graphics context.
  *
  * @param[in] value Pointer to a graphics context.
  *
- * @param[in] id Resource ID of graphics context.
+ * @param[in] id    Resource ID of graphics context.
  *
  * @param[out] size Estimate of memory usage attributed to a all
  *                  pixmap references of a graphics context.
@@ -338,57 +390,99 @@ GetGcBytes(pointer value, XID id, ResourceSizePtr size)
     }
 }
 
+/**
+ * Iterate through subresources of a graphics context. The purpose of
+ * this function is to gather accurate information on what resources a
+ * resource uses.
+ *
+ * @note Currently only sub-pixmaps are iterated
+ *
+ * @param[in] value  Pointer to a window
+ *
+ * @param[in] func   Function to call with each subresource
+ *
+ * @param[out] cdata Pointer to opaque data
+ */
+static void
+FindGCSubRes(pointer value, FindAllRes func, pointer cdata)
+{
+    GCPtr gc = value;
+
+    /* Currently only pixmap subresources are reported to clients. */
+
+    if (gc->stipple)
+    {
+        PixmapPtr pixmap = gc->stipple;
+        func(pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
+    }
+    if (gc->tile.pixmap && !gc->tileIsPixel)
+    {
+        PixmapPtr pixmap = gc->tile.pixmap;
+        func(pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
+    }
+}
+
 static struct ResourceType *resourceTypes;
 
 static const struct ResourceType predefTypes[] = {
     [RT_NONE & (RC_LASTPREDEF - 1)] = {
                                        .deleteFunc = (DeleteType) NoopDDA,
                                        .sizeFunc = GetDefaultBytes,
+                                       .findSubResFunc = DefaultFindSubRes,
                                        .errorValue = BadValue,
                                        },
     [RT_WINDOW & (RC_LASTPREDEF - 1)] = {
                                          .deleteFunc = DeleteWindow,
                                          .sizeFunc = GetWindowBytes,
+                                         .findSubResFunc = FindWindowSubRes,
                                          .errorValue = BadWindow,
                                          },
     [RT_PIXMAP & (RC_LASTPREDEF - 1)] = {
                                          .deleteFunc = dixDestroyPixmap,
                                          .sizeFunc = GetPixmapBytes,
+                                         .findSubResFunc = DefaultFindSubRes,
                                          .errorValue = BadPixmap,
                                          },
     [RT_GC & (RC_LASTPREDEF - 1)] = {
                                      .deleteFunc = FreeGC,
                                      .sizeFunc = GetGcBytes,
+                                     .findSubResFunc = FindGCSubRes,
                                      .errorValue = BadGC,
                                      },
     [RT_FONT & (RC_LASTPREDEF - 1)] = {
                                        .deleteFunc = CloseFont,
                                        .sizeFunc = GetDefaultBytes,
+                                       .findSubResFunc = DefaultFindSubRes,
                                        .errorValue = BadFont,
                                        },
     [RT_CURSOR & (RC_LASTPREDEF - 1)] = {
                                          .deleteFunc = FreeCursor,
                                          .sizeFunc = GetDefaultBytes,
+                                         .findSubResFunc = DefaultFindSubRes,
                                          .errorValue = BadCursor,
                                          },
     [RT_COLORMAP & (RC_LASTPREDEF - 1)] = {
                                            .deleteFunc = FreeColormap,
                                            .sizeFunc = GetDefaultBytes,
+                                           .findSubResFunc = DefaultFindSubRes,
                                            .errorValue = BadColor,
                                            },
     [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = {
                                             .deleteFunc = FreeClientPixels,
                                             .sizeFunc = GetDefaultBytes,
+                                            .findSubResFunc = DefaultFindSubRes,
                                             .errorValue = BadColor,
                                             },
     [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = {
                                               .deleteFunc = OtherClientGone,
                                               .sizeFunc = GetDefaultBytes,
+                                              .findSubResFunc = DefaultFindSubRes,
                                               .errorValue = BadValue,
                                               },
     [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = {
                                               .deleteFunc = DeletePassiveGrab,
                                               .sizeFunc = GetDefaultBytes,
+                                              .findSubResFunc = DefaultFindSubRes,
                                               .errorValue = BadValue,
                                               },
 };
@@ -420,6 +514,7 @@ CreateNewResourceType(DeleteType deleteFunc, const char *name)
     resourceTypes = types;
     resourceTypes[next].deleteFunc = deleteFunc;
     resourceTypes[next].sizeFunc = GetDefaultBytes;
+    resourceTypes[next].findSubResFunc = DefaultFindSubRes;
     resourceTypes[next].errorValue = BadValue;
 
     /* Called even if name is NULL, to remove any previous entry */
@@ -461,6 +556,24 @@ SetResourceTypeSizeFunc(RESTYPE type, SizeType sizeFunc)
     resourceTypes[type & TypeMask].sizeFunc = sizeFunc;
 }
 
+/**
+ * Provide a function for iterating the subresources of a resource.
+ * This allows for example more accurate accounting of the (memory)
+ * resources consumed by a resource.
+ *
+ * @see FindSubResources
+ *
+ * @param[in] type     Resource type used in size calculations.
+ *
+ * @param[in] sizeFunc Function to calculate the size of a single
+ *                     resource.
+ */
+void
+SetResourceTypeFindSubResFunc(RESTYPE type, FindTypeSubResources findFunc)
+{
+    resourceTypes[type & TypeMask].findSubResFunc = findFunc;
+}
+
 void
 SetResourceTypeErrorValue(RESTYPE type, int errorValue)
 {
@@ -871,6 +984,15 @@ FindClientResourcesByType(ClientPtr client,
     }
 }
 
+void FindSubResources(pointer    resource,
+                      RESTYPE    type,
+                      FindAllRes func,
+                      pointer    cdata)
+{
+    struct ResourceType rtype = resourceTypes[type & TypeMask];
+    rtype.findSubResFunc(resource, func, cdata);
+}
+
 void
 FindAllClientResources(ClientPtr client, FindAllRes func, pointer cdata)
 {
diff --git a/include/resource.h b/include/resource.h
index 8e58952..663fac4 100644
--- a/include/resource.h
+++ b/include/resource.h
@@ -171,12 +171,19 @@ typedef void (*SizeType)(pointer /*value*/,
 extern _X_EXPORT RESTYPE CreateNewResourceType(DeleteType /*deleteFunc */ ,
                                                const char * /*name */ );
 
+typedef void (*FindTypeSubResources)(pointer /* value */,
+                                     FindAllRes /* func */,
+                                     pointer /* cdata */);
+
 extern _X_EXPORT void SetResourceTypeErrorValue(RESTYPE /*type */ ,
                                                 int /*errorValue */ );
 
 extern _X_EXPORT SizeType GetResourceTypeSizeFunc(
     RESTYPE /*type*/);
 
+extern _X_EXPORT void SetResourceTypeFindSubResFunc(
+    RESTYPE /*type*/, FindTypeSubResources /*findFunc*/);
+
 extern _X_EXPORT void SetResourceTypeSizeFunc(
     RESTYPE /*type*/, SizeType /*sizeFunc*/);
 
@@ -218,6 +225,15 @@ extern _X_EXPORT void FindAllClientResources(ClientPtr /*client */ ,
                                              FindAllRes /*func */ ,
                                              pointer /*cdata */ );
 
+/** @brief Iterate through all subresources of a resource.
+
+    @note The XID argument provided to the FindAllRes function
+          may be 0 for subresources that don't have an XID */
+extern _X_EXPORT void FindSubResources(pointer /*resource*/,
+                                       RESTYPE /*type*/,
+                                       FindAllRes /*func*/,
+                                       pointer /*cdata*/);
+
 extern _X_EXPORT void FreeClientNeverRetainResources(ClientPtr /*client */ );
 
 extern _X_EXPORT void FreeClientResources(ClientPtr /*client */ );
commit b8d0d19a6d410776b53a41e7cae90f68d4b22bb7
Author: Rami Ylimäki <rami.ylimaki at vincit.fi>
Date:   Wed Oct 27 17:25:50 2010 +0300

    composite: Report pixmap usage of client windows to resource extension.
    
    Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>
    Signed-off-by: Rami Ylimäki <rami.ylimaki at vincit.fi>
    Reviewed-by: Mikhail Gusarov <dottedmag at dottedmag.net>
    Reviewed-by: Tiago Vignatti <tiago.vignatti at nokia.com>

diff --git a/Xext/xres.c b/Xext/xres.c
index a073409..b7933f2 100644
--- a/Xext/xres.c
+++ b/Xext/xres.c
@@ -28,6 +28,7 @@
 #include "misc.h"
 #include <string.h>
 #include "picturestr.h"
+#include "compint.h"
 
 /** @brief Holds fragments of responses for ConstructClientIds.
  *
@@ -342,6 +343,14 @@ ResFindPicturePixmaps(pointer value, XID id, pointer cdata)
 #endif
 }
 
+static void
+ResFindCompositeClientWindowPixmaps (pointer value, XID id, pointer cdata)
+{
+#ifdef COMPOSITE
+    ResFindResourcePixmaps(value, id, CompositeClientWindowType, cdata);
+#endif
+}
+
 static int
 ProcXResQueryClientPixmapBytes(ClientPtr client)
 {
@@ -384,7 +393,10 @@ ProcXResQueryClientPixmapBytes(ClientPtr client)
 #endif
 
 #ifdef COMPOSITE
-    /* FIXME: include composite pixmaps too */
+    /* Composite extension client window pixmaps. */
+    FindClientResourcesByType(clients[clientID], CompositeClientWindowType,
+                              ResFindCompositeClientWindowPixmaps,
+                              (pointer)(&bytes));
 #endif
 
     rep.type = X_Reply;
diff --git a/composite/compext.c b/composite/compext.c
index 940eed1..1d4d8bf 100644
--- a/composite/compext.c
+++ b/composite/compext.c
@@ -497,6 +497,28 @@ SProcCompositeDispatch(ClientPtr client)
         return BadRequest;
 }
 
+/** @see GetDefaultBytes */
+static void
+GetCompositeClientWindowBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    WindowPtr window = value;
+
+    /* Currently only pixmap bytes are reported to clients. */
+    size->resourceSize = 0;
+
+    /* Calculate pixmap reference sizes. */
+    size->pixmapRefSize = 0;
+    if (window->redirectDraw != RedirectDrawNone)
+    {
+        SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
+        ResourceSizeRec pixmapSize = { 0, 0 };
+        ScreenPtr screen = window->drawable.pScreen;
+        PixmapPtr pixmap = screen->GetWindowPixmap(window);
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+}
+
 void
 CompositeExtensionInit(void)
 {
@@ -529,6 +551,9 @@ CompositeExtensionInit(void)
     if (!CompositeClientWindowType)
         return;
 
+    SetResourceTypeSizeFunc(CompositeClientWindowType,
+                            GetCompositeClientWindowBytes);
+
     CompositeClientSubwindowsType = CreateNewResourceType
         (FreeCompositeClientSubwindows, "CompositeClientSubwindows");
     if (!CompositeClientSubwindowsType)
commit e83388cc70e21e7f377ed2e417d04469e23eb706
Author: Rami Ylimäki <rami.ylimaki at vincit.fi>
Date:   Wed Oct 27 16:59:06 2010 +0300

    render: Report pixmap usage of pictures to resource extension.
    
    Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>
    Signed-off-by: Rami Ylimäki <rami.ylimaki at vincit.fi>
    Reviewed-by: Mikhail Gusarov <dottedmag at dottedmag.net>
    Reviewed-by: Tiago Vignatti <tiago.vignatti at nokia.com>

diff --git a/Xext/xres.c b/Xext/xres.c
index 4989d3e..a073409 100644
--- a/Xext/xres.c
+++ b/Xext/xres.c
@@ -27,6 +27,7 @@
 #include "list.h"
 #include "misc.h"
 #include <string.h>
+#include "picturestr.h"
 
 /** @brief Holds fragments of responses for ConstructClientIds.
  *
@@ -288,6 +289,17 @@ ResGetApproxPixmapBytes(PixmapPtr pix)
 }
 
 static void
+ResFindResourcePixmaps(pointer value, XID id, RESTYPE type, pointer cdata)
+{
+    SizeType sizeFunc = GetResourceTypeSizeFunc(type);
+    ResourceSizeRec size = { 0, 0 };
+    unsigned long *bytes = cdata;
+
+    sizeFunc(value, id, &size);
+    *bytes += size.pixmapRefSize;
+}
+
+static void 
 ResFindPixmaps(pointer value, XID id, pointer cdata)
 {
     unsigned long *bytes = (unsigned long *) cdata;
@@ -322,6 +334,14 @@ ResFindGCPixmaps(pointer value, XID id, pointer cdata)
         *bytes += ResGetApproxPixmapBytes(pGC->tile.pixmap);
 }
 
+static void
+ResFindPicturePixmaps(pointer value, XID id, pointer cdata)
+{
+#ifdef RENDER
+    ResFindResourcePixmaps(value, id, PictureType, cdata);
+#endif
+}
+
 static int
 ProcXResQueryClientPixmapBytes(ClientPtr client)
 {
@@ -356,6 +376,13 @@ ProcXResQueryClientPixmapBytes(ClientPtr client)
     FindClientResourcesByType(clients[clientID], RT_GC,
                               ResFindGCPixmaps, (pointer) (&bytes));
 
+#ifdef RENDER
+    /* Render extension picture pixmaps. */
+    FindClientResourcesByType(clients[clientID], PictureType,
+                              ResFindPicturePixmaps,
+                              (pointer)(&bytes));
+#endif
+
 #ifdef COMPOSITE
     /* FIXME: include composite pixmaps too */
 #endif
diff --git a/dix/resource.c b/dix/resource.c
index 89d0776..89dfb5b 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -141,6 +141,7 @@ Equipment Corporation.
 #include "xace.h"
 #include <assert.h>
 #include "registry.h"
+#include "gcstruct.h"
 
 #ifdef XSERVER_DTRACE
 #include <sys/types.h>
@@ -182,50 +183,212 @@ RESTYPE TypeMask;
 
 struct ResourceType {
     DeleteType deleteFunc;
+    SizeType sizeFunc;
     int errorValue;
 };
 
+/**
+ * Used by all resources that don't specify a function to calculate
+ * resource size. Currently this is used for all resources with
+ * insignificant memory usage.
+ *
+ * @see GetResourceTypeSizeFunc, SetResourceTypeSizeFunc
+ *
+ * @param[in] value Pointer to resource object.
+ *
+ * @param[in] id Resource ID for the object.
+ *
+ * @param[out] size Fill all fields to zero to indicate that size of
+ *                  resource can't be determined.
+ */
+static void
+GetDefaultBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    size->resourceSize = 0;
+    size->pixmapRefSize = 0;
+}
+
+/**
+ * Calculate drawable size in bytes. Reference counting is not taken
+ * into account.
+ *
+ * @param[in] drawable Pointer to a drawable.
+ *
+ * @return Estimate of total memory usage for the drawable.
+ */
+static unsigned long
+GetDrawableBytes(DrawablePtr drawable)
+{
+    int bytes = 0;
+
+    if (drawable)
+    {
+        int bytesPerPixel = drawable->bitsPerPixel >> 3;
+        int numberOfPixels = drawable->width * drawable->height;
+        bytes = numberOfPixels * bytesPerPixel;
+    }
+
+    return bytes;
+}
+
+/**
+ * Calculate pixmap size in bytes. Reference counting is taken into
+ * account. Any extra data attached by extensions and drivers is not
+ * taken into account. The purpose of this function is to estimate
+ * memory usage that can be attributed to single reference of the
+ * pixmap.
+ *
+ * @param[in] value Pointer to a pixmap.
+ *
+ * @param[in] id Resource ID of pixmap. If the pixmap hasn't been
+ *               added as resource, just pass value->drawable.id.
+ *
+ * @param[out] size Estimate of memory usage attributed to a single
+ *                  pixmap reference.
+ */
+static void
+GetPixmapBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    PixmapPtr pixmap = value;
+
+    size->resourceSize = 0;
+    size->pixmapRefSize = 0;
+
+    if (pixmap && pixmap->refcnt)
+    {
+        DrawablePtr drawable = &pixmap->drawable;
+        size->resourceSize = GetDrawableBytes(drawable);
+        size->pixmapRefSize = size->resourceSize / pixmap->refcnt;
+    }
+}
+
+/**
+ * Calculate window size in bytes. The purpose of this function is to
+ * estimate memory usage that can be attributed to all pixmap
+ * references of the window.
+ *
+ * @param[in] value Pointer to a window.
+ *
+ * @param[in] id Resource ID of window.
+ *
+ * @param[out] size Estimate of memory usage attributed to a all
+ *                  pixmap references of a window.
+ */
+static void
+GetWindowBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
+    ResourceSizeRec pixmapSize = { 0, 0 };
+    WindowPtr window = value;
+
+    /* Currently only pixmap bytes are reported to clients. */
+    size->resourceSize = 0;
+
+    /* Calculate pixmap reference sizes. */
+    size->pixmapRefSize = 0;
+    if (window->backgroundState == BackgroundPixmap)
+    {
+        PixmapPtr pixmap = window->background.pixmap;
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+    if (window->border.pixmap && !window->borderIsPixel)
+    {
+        PixmapPtr pixmap = window->border.pixmap;
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+}
+
+/**
+ * Calculate graphics context size in bytes. The purpose of this
+ * function is to estimate memory usage that can be attributed to all
+ * pixmap references of the graphics context.
+ *
+ * @param[in] value Pointer to a graphics context.
+ *
+ * @param[in] id Resource ID of graphics context.
+ *
+ * @param[out] size Estimate of memory usage attributed to a all
+ *                  pixmap references of a graphics context.
+ */
+static void
+GetGcBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
+    ResourceSizeRec pixmapSize = { 0, 0 };
+    GCPtr gc = value;
+
+    /* Currently only pixmap bytes are reported to clients. */
+    size->resourceSize = 0;
+
+    /* Calculate pixmap reference sizes. */
+    size->pixmapRefSize = 0;
+    if (gc->stipple)
+    {
+        PixmapPtr pixmap = gc->stipple;
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+    if (gc->tile.pixmap && !gc->tileIsPixel)
+    {
+        PixmapPtr pixmap = gc->tile.pixmap;
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+}
+
 static struct ResourceType *resourceTypes;
 
 static const struct ResourceType predefTypes[] = {
     [RT_NONE & (RC_LASTPREDEF - 1)] = {
                                        .deleteFunc = (DeleteType) NoopDDA,
+                                       .sizeFunc = GetDefaultBytes,
                                        .errorValue = BadValue,
                                        },
     [RT_WINDOW & (RC_LASTPREDEF - 1)] = {
                                          .deleteFunc = DeleteWindow,
+                                         .sizeFunc = GetWindowBytes,
                                          .errorValue = BadWindow,
                                          },
     [RT_PIXMAP & (RC_LASTPREDEF - 1)] = {
                                          .deleteFunc = dixDestroyPixmap,
+                                         .sizeFunc = GetPixmapBytes,
                                          .errorValue = BadPixmap,
                                          },
     [RT_GC & (RC_LASTPREDEF - 1)] = {
                                      .deleteFunc = FreeGC,
+                                     .sizeFunc = GetGcBytes,
                                      .errorValue = BadGC,
                                      },
     [RT_FONT & (RC_LASTPREDEF - 1)] = {
                                        .deleteFunc = CloseFont,
+                                       .sizeFunc = GetDefaultBytes,
                                        .errorValue = BadFont,
                                        },
     [RT_CURSOR & (RC_LASTPREDEF - 1)] = {
                                          .deleteFunc = FreeCursor,
+                                         .sizeFunc = GetDefaultBytes,
                                          .errorValue = BadCursor,
                                          },
     [RT_COLORMAP & (RC_LASTPREDEF - 1)] = {
                                            .deleteFunc = FreeColormap,
+                                           .sizeFunc = GetDefaultBytes,
                                            .errorValue = BadColor,
                                            },
     [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = {
                                             .deleteFunc = FreeClientPixels,
+                                            .sizeFunc = GetDefaultBytes,
                                             .errorValue = BadColor,
                                             },
     [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = {
                                               .deleteFunc = OtherClientGone,
+                                              .sizeFunc = GetDefaultBytes,
                                               .errorValue = BadValue,
                                               },
     [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = {
                                               .deleteFunc = DeletePassiveGrab,
+                                              .sizeFunc = GetDefaultBytes,
                                               .errorValue = BadValue,
                                               },
 };
@@ -256,6 +419,7 @@ CreateNewResourceType(DeleteType deleteFunc, const char *name)
     lastResourceType = next;
     resourceTypes = types;
     resourceTypes[next].deleteFunc = deleteFunc;
+    resourceTypes[next].sizeFunc = GetDefaultBytes;
     resourceTypes[next].errorValue = BadValue;
 
     /* Called even if name is NULL, to remove any previous entry */
@@ -264,6 +428,39 @@ CreateNewResourceType(DeleteType deleteFunc, const char *name)
     return next;
 }
 
+/**
+ * Get the function used to calculate resource size. Extensions and
+ * drivers need to be able to determine the current size calculation
+ * function if they want to wrap or override it.
+ *
+ * @param[in] type     Resource type used in size calculations.
+ *
+ * @return Function to calculate the size of a single
+ *                     resource.
+ */
+SizeType
+GetResourceTypeSizeFunc(RESTYPE type)
+{
+    return resourceTypes[type & TypeMask].sizeFunc;
+}
+
+/**
+ * Override the default function that calculates resource size. For
+ * example, video driver knows better how to calculate pixmap memory
+ * usage and can therefore wrap or override size calculation for
+ * RT_PIXMAP.
+ *
+ * @param[in] type     Resource type used in size calculations.
+ *
+ * @param[in] sizeFunc Function to calculate the size of a single
+ *                     resource.
+ */
+void
+SetResourceTypeSizeFunc(RESTYPE type, SizeType sizeFunc)
+{
+    resourceTypes[type & TypeMask].sizeFunc = sizeFunc;
+}
+
 void
 SetResourceTypeErrorValue(RESTYPE type, int errorValue)
 {
diff --git a/include/resource.h b/include/resource.h
index 0680570..8e58952 100644
--- a/include/resource.h
+++ b/include/resource.h
@@ -152,12 +152,37 @@ typedef Bool (*FindComplexResType) (pointer /*value */ ,
                                     XID /*id */ ,
                                     pointer /*cdata */ );
 
+/* Structure for estimating resource memory usage. Memory usage
+ * consists of space allocated for the resource itself and of
+ * references to other resources. Currently the most important use for
+ * this structure is to estimate pixmap usage of different resources
+ * more accurately. */
+typedef struct {
+    /* Size of resource itself. Zero if not implemented. */
+    unsigned long resourceSize;
+    /* Size attributed to pixmap references from the resource. */
+    unsigned long pixmapRefSize;
+} ResourceSizeRec, *ResourceSizePtr;
+
+typedef void (*SizeType)(pointer /*value*/,
+                         XID /*id*/,
+                         ResourceSizePtr /*size*/);
+
 extern _X_EXPORT RESTYPE CreateNewResourceType(DeleteType /*deleteFunc */ ,
                                                const char * /*name */ );
 
 extern _X_EXPORT void SetResourceTypeErrorValue(RESTYPE /*type */ ,
                                                 int /*errorValue */ );
 
+extern _X_EXPORT SizeType GetResourceTypeSizeFunc(
+    RESTYPE /*type*/);
+
+extern _X_EXPORT void SetResourceTypeSizeFunc(
+    RESTYPE /*type*/, SizeType /*sizeFunc*/);
+
+extern _X_EXPORT void SetResourceTypeErrorValue(
+    RESTYPE /*type*/, int /*errorValue*/);
+
 extern _X_EXPORT RESTYPE CreateNewResourceClass(void);
 
 extern _X_EXPORT Bool InitClientResources(ClientPtr /*client */ );
diff --git a/render/picture.c b/render/picture.c
index 2fd13fc..24b6ba0 100644
--- a/render/picture.c
+++ b/render/picture.c
@@ -591,6 +591,27 @@ PictureParseCmapPolicy(const char *name)
         return PictureCmapPolicyInvalid;
 }
 
+/** @see GetDefaultBytes */
+static void
+GetPictureBytes(pointer value, XID id, ResourceSizePtr size)
+{
+    PicturePtr picture = value;
+
+    /* Currently only pixmap bytes are reported to clients. */
+    size->resourceSize = 0;
+
+    /* Calculate pixmap reference sizes. */
+    size->pixmapRefSize = 0;
+    if (picture->pDrawable && (picture->pDrawable->type == DRAWABLE_PIXMAP))
+    {
+        SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
+        ResourceSizeRec pixmapSize = { 0, 0 };
+        PixmapPtr pixmap = (PixmapPtr)picture->pDrawable;
+        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
+        size->pixmapRefSize += pixmapSize.pixmapRefSize;
+    }
+}
+
 Bool
 PictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
 {
@@ -602,6 +623,7 @@ PictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
         PictureType = CreateNewResourceType(FreePicture, "PICTURE");
         if (!PictureType)
             return FALSE;
+        SetResourceTypeSizeFunc(PictureType, GetPictureBytes);
         PictFormatType = CreateNewResourceType(FreePictFormat, "PICTFORMAT");
         if (!PictFormatType)
             return FALSE;
commit 96864bfa951ea8bf4ab697753fc62c6a97598bc0
Author: Erkki Seppälä <erkki.seppala at vincit.fi>
Date:   Mon Nov 29 12:40:56 2010 +0200

    Implemented first part of XResource extension v1.2: X_XResQueryClientIds
    
    This patch implements a part of the XResource extension v1.2 (as specified in
    http://patchwork.freedesktop.org/patch/2720/ ). The request implemented is
    X_XResQueryClientIds.
    
    This patch depends on the feature introduced by
    1e933665bef26c74196bb7c59910e6a78bcacf0e "dix: Add facilities for
    client ID tracking." .
    
    This latest version also adds Doxygen-formatted comments and takes a better
    notice of coding conventions (as in http://www.x.org/wiki/CodingStyle ).
    
    Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>

diff --git a/Xext/xres.c b/Xext/xres.c
index 9d89b65..4989d3e 100644
--- a/Xext/xres.c
+++ b/Xext/xres.c
@@ -10,6 +10,7 @@
 #include <string.h>
 #include <X11/X.h>
 #include <X11/Xproto.h>
+#include <assert.h>
 #include "misc.h"
 #include "os.h"
 #include "dixstruct.h"
@@ -22,6 +23,98 @@
 #include "gcstruct.h"
 #include "modinit.h"
 #include "protocol-versions.h"
+#include "client.h"
+#include "list.h"
+#include "misc.h"
+#include <string.h>
+
+/** @brief Holds fragments of responses for ConstructClientIds.
+ *
+ *  note: there is no consideration for data alignment */
+typedef struct {
+    struct xorg_list l;
+    int   bytes;
+    /* data follows */
+} FragmentList;
+
+/** @brief Holds structure for the generated response to
+           ProcXResQueryClientIds; used by ConstructClientId* -functions */
+typedef struct {
+    int           numIds;
+    int           resultBytes;
+    struct xorg_list   response;
+    int           sentClientMasks[MAXCLIENTS];
+} ConstructClientIdCtx;
+
+/** @brief Allocate and add a sequence of bytes at the end of a fragment list.
+           Call DestroyFragments to release the list.
+
+    @param frags A pointer to head of an initialized linked list
+    @param bytes Number of bytes to allocate
+    @return Returns a pointer to the allocated non-zeroed region
+            that is to be filled by the caller. On error (out of memory)
+            returns NULL and makes no changes to the list.
+*/
+static void *
+AddFragment(struct xorg_list *frags, int bytes)
+{
+    FragmentList *f = malloc(sizeof(FragmentList) + bytes);
+    if (!f) {
+        return NULL;
+    } else {
+        f->bytes = bytes;
+        xorg_list_add(&f->l, frags->prev);
+        return (char*) f + sizeof(*f);
+    }
+}
+
+/** @brief Sends all fragments in the list to the client. Does not
+           free anything.
+
+    @param client The client to send the fragments to
+    @param frags The head of the list of fragments
+*/
+static void
+WriteFragmentsToClient(ClientPtr client, struct xorg_list *frags)
+{
+    FragmentList *it;
+    xorg_list_for_each_entry(it, frags, l) {
+        WriteToClient(client, it->bytes, (char*) it + sizeof(*it));
+    }
+}
+
+/** @brief Frees a list of fragments. Does not free() root node.
+
+    @param frags The head of the list of fragments
+*/
+static void
+DestroyFragments(struct xorg_list *frags)
+{
+    FragmentList *it, *tmp;
+    xorg_list_for_each_entry_safe(it, tmp, frags, l) {
+        xorg_list_del(&it->l);
+        free(it);
+    }
+}
+
+/** @brief Constructs a context record for ConstructClientId* functions
+           to use */
+static void
+InitConstructClientIdCtx(ConstructClientIdCtx *ctx)
+{
+    ctx->numIds = 0;
+    ctx->resultBytes = 0;
+    xorg_list_init(&ctx->response);
+    memset(ctx->sentClientMasks, 0, sizeof(ctx->sentClientMasks));
+}
+
+/** @brief Destroys a context record, releases all memory (except the storage
+           for *ctx itself) */
+static void
+DestroyConstructClientIdCtx(ConstructClientIdCtx *ctx)
+{
+    DestroyFragments(&ctx->response);
+}
 
 static int
 ProcXResQueryVersion(ClientPtr client)
@@ -288,6 +381,202 @@ ProcXResQueryClientPixmapBytes(ClientPtr client)
     return Success;
 }
 
+/** @brief Finds out if a client's information need to be put into the
+    response; marks client having been handled, if that is the case.
+
+    @param client   The client to send information about
+    @param mask     The request mask (0 to send everything, otherwise a
+                    bitmask of X_XRes*Mask)
+    @param ctx      The context record that tells which clients and id types
+                    have been already handled
+    @param sendMask Which id type are we now considering. One of X_XRes*Mask.
+
+    @return Returns TRUE if the client information needs to be on the
+            response, otherwise FALSE.
+*/
+static Bool
+WillConstructMask(ClientPtr client, CARD32 mask,
+                  ConstructClientIdCtx *ctx, int sendMask)
+{
+    if ((!mask || (mask & sendMask))
+        && !(ctx->sentClientMasks[client->index] & sendMask)) {
+        ctx->sentClientMasks[client->index] |= sendMask;
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+/** @brief Constructs a response about a single client, based on a certain
+           client id spec
+
+    @param sendClient Which client wishes to receive this answer. Used for
+                      byte endianess.
+    @param client     Which client are we considering.
+    @param mask       The client id spec mask indicating which information
+                      we want about this client.
+    @param ctx        The context record containing the constructed response
+                      and information on which clients and masks have been
+                      already handled.
+
+    @return Return TRUE if everything went OK, otherwise FALSE which indicates
+            a memory allocation problem.
+*/
+static Bool
+ConstructClientIdValue(ClientPtr sendClient, ClientPtr client, CARD32 mask,
+                       ConstructClientIdCtx *ctx)
+{
+    xXResClientIdValue rep;
+
+    rep.spec.client = client->clientAsMask;
+    if (client->swapped) {
+        swapl (&rep.spec.client);
+    }
+
+    if (WillConstructMask(client, mask, ctx, X_XResClientXIDMask)) {
+        void *ptr = AddFragment(&ctx->response, sizeof(rep));
+        if (!ptr) {
+            return FALSE;
+        }
+
+        rep.spec.mask = X_XResClientXIDMask;
+        rep.length = 0;
+        if (sendClient->swapped) {
+            swapl (&rep.spec.mask);
+            /* swapl (&rep.length, n); - not required for rep.length = 0 */
+        }
+
+        memcpy(ptr, &rep, sizeof(rep));
+
+        ctx->resultBytes += sizeof(rep);
+        ++ctx->numIds;
+    }
+    if (WillConstructMask(client, mask, ctx, X_XResLocalClientPIDMask)) {
+        pid_t pid = GetClientPid(client);
+
+        if (pid != -1) {
+            void *ptr = AddFragment(&ctx->response,
+                                    sizeof(rep) + sizeof(CARD32));
+            CARD32 *value = (void*) ((char*) ptr + sizeof(rep));
+
+            if (!ptr) {
+                return FALSE;
+            }
+
+            rep.spec.mask = X_XResLocalClientPIDMask;
+            rep.length = 4;
+
+            if (sendClient->swapped) {
+                swapl (&rep.spec.mask);
+                swapl (&rep.length);
+            }
+
+            if (sendClient->swapped) {
+                swapl (value);
+            }
+            memcpy(ptr, &rep, sizeof(rep));
+            *value = pid;
+
+            ctx->resultBytes += sizeof(rep) + sizeof(CARD32);
+            ++ctx->numIds;
+        }
+    }
+
+    /* memory allocation errors earlier may return with FALSE */
+    return TRUE;
+}
+
+/** @brief Constructs a response about all clients, based on a client id specs
+
+    @param client   Which client which we are constructing the response for.
+    @param numSpecs Number of client id specs in specs
+    @param specs    Client id specs
+
+    @return Return Success if everything went OK, otherwise a Bad* (currently
+            BadAlloc or BadValue)
+*/
+static int
+ConstructClientIds(ClientPtr client,
+                   int numSpecs, xXResClientIdSpec* specs,
+                   ConstructClientIdCtx *ctx)
+{
+    int specIdx;
+
+    for (specIdx = 0; specIdx < numSpecs; ++specIdx) {
+        if (specs[specIdx].client == 0) {
+            int c;
+            for (c = 0; c < currentMaxClients; ++c) {
+                if (clients[c]) {
+                    if (!ConstructClientIdValue(client, clients[c],
+                                                specs[specIdx].mask, ctx)) {
+                        return BadAlloc;
+                    }
+                }
+            }
+        } else {
+            int clientID = CLIENT_ID(specs[specIdx].client);
+
+            if ((clientID < currentMaxClients) && clients[clientID]) {
+                if (!ConstructClientIdValue(client, clients[clientID],
+                                            specs[specIdx].mask, ctx)) {
+                    return BadAlloc;
+                }
+            }
+        }
+    }
+
+    /* memory allocation errors earlier may return with BadAlloc */
+    return Success;
+}
+
+/** @brief Response to XResQueryClientIds request introduced in XResProto v1.2
+
+    @param client Which client which we are constructing the response for.
+
+    @return Returns the value returned from ConstructClientIds with the same
+            semantics
+*/
+static int
+ProcXResQueryClientIds (ClientPtr client)
+{
+    REQUEST(xXResQueryClientIdsReq);
+
+    xXResQueryClientIdsReply  rep;
+    xXResClientIdSpec        *specs = (void*) ((char*) stuff + sizeof(*stuff));
+    int                       rc;
+    ConstructClientIdCtx      ctx;
+
+    InitConstructClientIdCtx(&ctx);
+
+    REQUEST_AT_LEAST_SIZE(xXResQueryClientIdsReq);
+    REQUEST_FIXED_SIZE(xXResQueryClientIdsReq,
+                       stuff->numSpecs * sizeof(specs[0]));
+
+    rc = ConstructClientIds(client, stuff->numSpecs, specs, &ctx);
+
+    if (rc == Success) {
+        rep.type = X_Reply;
+        rep.sequenceNumber = client->sequence;
+
+        assert((ctx.resultBytes & 3) == 0);
+        rep.length = bytes_to_int32(ctx.resultBytes);
+        rep.numIds = ctx.numIds;
+
+        if (client->swapped) {
+            swaps (&rep.sequenceNumber);
+            swapl (&rep.length);
+            swapl (&rep.numIds);
+        }
+
+        WriteToClient(client,sizeof(rep),(char*)&rep);
+        WriteFragmentsToClient(client, &ctx.response);
+    }
+
+    DestroyConstructClientIdCtx(&ctx);
+
+    return rc;
+}
+
 static int
 ProcResDispatch(ClientPtr client)
 {
@@ -301,8 +590,12 @@ ProcResDispatch(ClientPtr client)
         return ProcXResQueryClientResources(client);
     case X_XResQueryClientPixmapBytes:
         return ProcXResQueryClientPixmapBytes(client);
-    default:
-        break;
+    case X_XResQueryClientIds:
+        return ProcXResQueryClientIds(client);
+    case X_XResQueryResourceBytes:
+        /* not implemented yet */
+        return BadRequest;
+    default: break;
     }
 
     return BadRequest;
@@ -335,7 +628,17 @@ SProcXResQueryClientPixmapBytes(ClientPtr client)
 }
 
 static int
-SProcResDispatch(ClientPtr client)
+SProcXResQueryClientIds (ClientPtr client)
+{
+    REQUEST(xXResQueryClientIdsReq);
+
+    REQUEST_AT_LEAST_SIZE (xXResQueryClientIdsReq);
+    swapl(&stuff->numSpecs);
+    return ProcXResQueryClientIds(client);
+}
+
+static int
+SProcResDispatch (ClientPtr client)
 {
     REQUEST(xReq);
     swaps(&stuff->length);
@@ -349,8 +652,12 @@ SProcResDispatch(ClientPtr client)
         return SProcXResQueryClientResources(client);
     case X_XResQueryClientPixmapBytes:
         return SProcXResQueryClientPixmapBytes(client);
-    default:
-        break;
+    case X_XResQueryClientIds:
+        return SProcXResQueryClientIds(client);
+    case X_XResQueryResourceBytes:
+        /* not implemented yet */
+        return BadRequest;
+    default: break;
     }
 
     return BadRequest;
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index 479ac2f..cb8e213 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -135,7 +135,7 @@
 
 /* Resource */
 #define SERVER_XRES_MAJOR_VERSION		1
-#define SERVER_XRES_MINOR_VERSION		0
+#define SERVER_XRES_MINOR_VERSION		2
 
 /* XvMC */
 #define SERVER_XVMC_MAJOR_VERSION		1
commit ebf214876a4885a98ded4f5525925b69005fae05
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Apr 18 15:56:37 2012 +1000

    dix: indentation fix
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 104dcc9..62f8ea3 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -413,8 +413,8 @@ Dispatch(void)
                 if (XSERVER_REQUEST_START_ENABLED())
                     XSERVER_REQUEST_START(LookupMajorName(client->majorOp),
                                           client->majorOp,
-                                          ((xReq *) client->requestBuffer)->
-                                          length, client->index,
+                                          ((xReq *) client->requestBuffer)->length,
+                                          client->index,
                                           client->requestBuffer);
 #endif
                 if (result > (maxBigRequestSize << 2))
commit 80fefc42f5e67e6b4a4b440d8991bee7e5f38359
Merge: 9779b90 12188c8
Author: Keith Packard <keithp at keithp.com>
Date:   Sun Apr 15 21:05:30 2012 -0700

    Merge remote-tracking branch 'whot/for-keith'

commit 12188c8a8a537b38b1ca4cf8c0de5447e19c886a
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Tue Apr 3 17:31:01 2012 -0700

    Use touch state when querying pointer through core protocol
    
    QueryPointer is part of the core protocol. As such, it knows nothing
    about touch devices. Touches are converted to button 1 press, pointer
    motion, and button 1 release for core clients, so we should ensure the
    pointer state mask has button 1 set when XQueryPointer is used.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/events.c b/dix/events.c
index 4470947..b9f9cfa 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -5098,8 +5098,7 @@ ProcQueryPointer(ClientPtr client)
     memset(&rep, 0, sizeof(xQueryPointerReply));
     rep.type = X_Reply;
     rep.sequenceNumber = client->sequence;
-    rep.mask = mouse->button ? (mouse->button->state) : 0;
-    rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state);
+    rep.mask = event_get_corestate(mouse, keyboard);
     rep.length = 0;
     rep.root = (GetCurrentRootWindow(mouse))->drawable.id;
     rep.rootX = pSprite->hot.x;
commit 32ece7c09bf0ebc3d99b4078aacebbd44314776a
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Tue Apr 10 17:12:42 2012 -0700

    Ensure sequential touches are pointer emulated sequentially
    
    Issue:
    * Two sequential touches (i.e. down, up, down, up)
    * Both are grabbed by a touch grab
    * Both have a second listener in the form of a pointer grab or selection
    * The second and first touches are rejected in that order
    
    The first touch must be pointer emulated before the second touch, so the
    second touch must be paused until the first touch is rejected or
    accepted and all events are delivered to pointer clients.
    
    This change ensures all pointer emulated events are emitted
    sequentially. It necessarily imposes a delay on further touch events
    when pointer grabs and selections are used, but there is no way around
    it.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index a843e03..c05c226 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1111,6 +1111,48 @@ EmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource)
 }
 
 /**
+ * Find the oldest touch that still has a pointer emulation client.
+ *
+ * Pointer emulation can only be performed for the oldest touch. Otherwise, the
+ * order of events seen by the client will be wrong. This function helps us find
+ * the next touch to be emulated.
+ *
+ * @param dev The device to find touches for.
+ */
+static TouchPointInfoPtr
+FindOldestPointerEmulatedTouch(DeviceIntPtr dev)
+{
+    TouchPointInfoPtr oldest = NULL;
+    int i;
+
+    for (i = 0; i < dev->touch->num_touches; i++) {
+        TouchPointInfoPtr ti = dev->touch->touches + i;
+        int j;
+
+        if (!ti->active || !ti->emulate_pointer)
+            continue;
+
+        for (j = 0; j < ti->num_listeners; j++) {
+            if (ti->listeners[j].type == LISTENER_POINTER_GRAB ||
+                ti->listeners[j].type == LISTENER_POINTER_REGULAR)
+                break;
+        }
+        if (j == ti->num_listeners)
+            continue;
+
+        if (!oldest) {
+            oldest = ti;
+            continue;
+        }
+
+        if (oldest->client_id - ti->client_id < UINT_MAX / 2)
+            oldest = ti;
+    }
+
+    return oldest;
+}
+
+/**
  * If the current owner has rejected the event, deliver the
  * TouchOwnership/TouchBegin to the next item in the sprite stack.
  */
@@ -1123,8 +1165,16 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
         ti->listeners[0].state == LISTENER_EARLY_ACCEPT)
         DeliverTouchEvents(dev, ti, (InternalEvent *) ev,
                            ti->listeners[0].listener);
-    else if (ti->listeners[0].state == LISTENER_AWAITING_BEGIN)
+    else if (ti->listeners[0].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) &&
+            ti != FindOldestPointerEmulatedTouch(dev))
+            return;
+
         TouchEventHistoryReplay(ti, dev, ti->listeners[0].listener);
+    }
 
     /* If we've just removed the last grab and the touch has physically
      * ended, send a TouchEnd event too and finalise the touch. */
@@ -1139,6 +1189,25 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
 }
 
 /**
+ * Check the oldest touch to see if it needs to be replayed to its pointer
+ * owner.
+ *
+ * Touch event propagation is paused if it hits a pointer listener while an
+ * older touch with a pointer listener is waiting on accept or reject. This
+ * function will restart propagation of a paused touch if needed.
+ *
+ * @param dev The device to check touches for.
+ */
+static void
+CheckOldestTouch(DeviceIntPtr dev)
+{
+    TouchPointInfoPtr oldest = FindOldestPointerEmulatedTouch(dev);
+
+    if (oldest && oldest->listeners[0].state == LISTENER_AWAITING_BEGIN)
+        TouchPuntToNextOwner(dev, oldest, NULL);
+}
+
+/**
  * Process a touch rejection.
  *
  * @param sourcedev The source device of the touch sequence.
@@ -1169,6 +1238,7 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource,
      * finish, then we can just kill it now. */
     if (ti->num_listeners == 1 && ti->pending_finish) {
         TouchEndTouch(sourcedev, ti);
+        CheckOldestTouch(sourcedev);
         return;
     }
 
@@ -1184,6 +1254,8 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource,
      * the TouchOwnership or TouchBegin event to the new owner. */
     if (ev && ti->num_listeners > 0 && was_owner)
         TouchPuntToNextOwner(sourcedev, ti, ev);
+
+    CheckOldestTouch(sourcedev);
 }
 
 /**
@@ -1391,6 +1463,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
                 !dev->button->buttonsDown &&
                 dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) {
                 (*dev->deviceGrab.DeactivateGrab) (dev);
+                CheckOldestTouch(dev);
                 return Success;
             }
         }
commit 163b0f375d73c05873fb341652de3ed347337828
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Tue Apr 10 17:12:41 2012 -0700

    Update event type when delivering end event to a pointer listener
    
    Just like when we deliver to a touch listener, we must convert a touch
    end event to an update event for further clients. This also ensures that
    the touch record is not deleted at the end of ProcessTouchEvent().
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 3117123..a843e03 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1757,6 +1757,13 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
         listener->type == LISTENER_POINTER_GRAB) {
         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;
+            ti->pending_finish = TRUE;
+        }
+
         goto out;
     }
 
commit 210cd12c47d063f97915ff23292b61d09abfd73a
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Tue Apr 10 17:12:40 2012 -0700

    Don't update listener after deactivating implicit pointer grab
    
    After the pointer grab is deactivated, the touch listener record is
    updated at the end of DeliverTouchEmulatedEvent. However, the touch
    record is ended when the grab is deactivated, so the update to the
    listener record is in an array of memory that has been freed.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index ff22240..3117123 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1389,8 +1389,10 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
 
             if (ev->any.type == ET_TouchEnd &&
                 !dev->button->buttonsDown &&
-                dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab))
+                dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) {
                 (*dev->deviceGrab.DeactivateGrab) (dev);
+                return Success;
+            }
         }
     }
     else {
commit 82a1ae0af3b136371638659c3e909880a99f721c
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Apr 12 15:54:00 2012 +1000

    xfree86: after VT switching back, only enable previously enabled devices
    
    If a device was enabled before the VT switch, re-enabled it. Otherwise leave
    it as is, there was probably a reason why it was disabled.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Daniel Stone <daniel at fooishbar.org>

diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c
index 058057e..5896f22 100644
--- a/hw/xfree86/common/xf86Events.c
+++ b/hw/xfree86/common/xf86Events.c
@@ -449,6 +449,8 @@ xf86VTSwitch(void)
             xf86DisableInputHandler(ih);
         for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) {
             if (pInfo->dev) {
+                if (!pInfo->dev->enabled)
+                    pInfo->flags |= XI86_DEVICE_DISABLED;
                 xf86ReleaseKeys(pInfo->dev);
                 ProcessInputEvents();
                 DisableDevice(pInfo->dev, TRUE);
@@ -482,8 +484,9 @@ xf86VTSwitch(void)
 
             pInfo = xf86InputDevs;
             while (pInfo) {
-                if (pInfo->dev)
+                if (pInfo->dev && (pInfo->flags & XI86_DEVICE_DISABLED) == 0)
                     EnableDevice(pInfo->dev, TRUE);
+                pInfo->flags &= ~XI86_DEVICE_DISABLED;
                 pInfo = pInfo->next;
             }
             for (ih = InputHandlers; ih; ih = ih->next)
@@ -537,8 +540,9 @@ xf86VTSwitch(void)
 
         pInfo = xf86InputDevs;
         while (pInfo) {
-            if (pInfo->dev)
+            if (pInfo->dev && (pInfo->flags & XI86_DEVICE_DISABLED) == 0)
                 EnableDevice(pInfo->dev, TRUE);
+            pInfo->flags &= ~XI86_DEVICE_DISABLED;
             pInfo = pInfo->next;
         }
 
diff --git a/hw/xfree86/common/xf86Xinput.h b/hw/xfree86/common/xf86Xinput.h
index 3731a34..1d4363a 100644
--- a/hw/xfree86/common/xf86Xinput.h
+++ b/hw/xfree86/common/xf86Xinput.h
@@ -61,6 +61,9 @@
 #define XI86_ALWAYS_CORE	0x04    /* device always controls the pointer */
 /* the device sends Xinput and core pointer events */
 #define XI86_SEND_CORE_EVENTS	XI86_ALWAYS_CORE
+/* 0x08 is reserved for legacy XI86_SEND_DRAG_EVENTS, do not use for now */
+/* server-internal only */
+#define XI86_DEVICE_DISABLED    0x10    /* device was disabled before vt switch */
 
 /* This holds the input driver entry and module information. */
 typedef struct _InputDriverRec {
commit c5a45b0f7658c77725adce2b64a0fbd62f208328
Author: Daniel Kurtz <djkurtz at chromium.org>
Date:   Thu Apr 12 10:11:10 2012 +1000

    dix: don't BUG_WARN for button events from button-only device
    
    Events from button-only devices still need coordinates, and they get them
    from scale_to_desktop().  Therefore, a dev without valuators is not a bug.
    However, a dev with valuators, but less than two of them still is a bug.
    
    This was noticed when unplugging a "Creative Technology SB Arena Headset",
    which has some BTNs and some KEYs, but no REL or ABS valuators.
    It emits [BTN_3] = 0 on unplug, which would trigger the BUG_WARN.
    
    Signed-off-by: Daniel Kurtz <djkurtz at chromium.org>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/getevents.c b/dix/getevents.c
index 3093786..23bbe06 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -848,7 +848,7 @@ scale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask,
     ScreenPtr scr = miPointerGetScreen(dev);
     double x, y;
 
-    BUG_WARN(!dev->valuator || dev->valuator->numAxes < 2);
+    BUG_WARN(dev->valuator && dev->valuator->numAxes < 2);
     if (!dev->valuator || dev->valuator->numAxes < 2) {
         /* if we have no axes, last.valuators must be in screen coords
          * anyway */
commit 72cfc1a097dc1e09d2cd9415ef7855a2cef92351
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Apr 11 09:43:23 2012 +1000

    Xi: fix XITouchClass sourceid assignment
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/xiquerydevice.c b/Xi/xiquerydevice.c
index 749bc24..15c8b2a 100644
--- a/Xi/xiquerydevice.c
+++ b/Xi/xiquerydevice.c
@@ -430,7 +430,7 @@ ListTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
 {
     touch->type = XITouchClass;
     touch->length = sizeof(xXITouchInfo) >> 2;
-    touch->sourceid = touch->sourceid;
+    touch->sourceid = dev->touch->sourceid;
     touch->mode = dev->touch->mode;
     touch->num_touches = dev->touch->num_touches;
 


More information about the Xquartz-changes mailing list