[Xquartz-changes] xserver: Branch 'server-1.12-apple' - 59 commits

Jeremy Huddleston jeremyhu at freedesktop.org
Tue Dec 27 13:12:25 PST 2011


Rebased ref, commits from common ancestor:
commit 9072dc4d2c0fb71f14a6da861aa74885bcfe692c
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Fri Feb 12 19:48:52 2010 -0800

    fb: Revert fb changes that broke XQuartz
    
    http://bugs.freedesktop.org/show_bug.cgi?id=26124
    
    Revert "Fix source pictures getting random transforms after 2d6a8f668342a5190cdf43b5."
    Revert "fb: Adjust transform or composite coordinates for pixman operations"
    
    http://bugs.freedesktop.org/26124
    
    This reverts commit a72c65e9176c51de95db2fdbf4c5d946a4911695.
    This reverts commit a6bd5d2e482a5aa84acb3d4932e2a166d8670ef1.
    
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/fb/fb.h b/fb/fb.h
index eaa21ad..e65a1c0 100644
--- a/fb/fb.h
+++ b/fb/fb.h
@@ -2049,11 +2049,8 @@ fbFillRegionSolid (DrawablePtr	pDrawable,
 		   FbBits	xor);
 
 extern _X_EXPORT pixman_image_t *
-image_from_pict (PicturePtr	pict,
-		 Bool		has_clip,
-		 int		*xoff,
-		 int		*yoff);
-
+image_from_pict (PicturePtr pict,
+		 Bool       has_clip);
 extern _X_EXPORT void free_pixman_pict (PicturePtr, pixman_image_t *);
 
 #endif /* _FB_H_ */
diff --git a/fb/fbpict.c b/fb/fbpict.c
index 57c93fd..127e5c7 100644
--- a/fb/fbpict.c
+++ b/fb/fbpict.c
@@ -50,24 +50,19 @@ fbComposite (CARD8      op,
 	     CARD16     height)
 {
     pixman_image_t *src, *mask, *dest;
-    int src_xoff, src_yoff;
-    int msk_xoff, msk_yoff;
-    int dst_xoff, dst_yoff;
     
     miCompositeSourceValidate (pSrc);
     if (pMask)
 	miCompositeSourceValidate (pMask);
     
-    src = image_from_pict (pSrc, FALSE, &src_xoff, &src_yoff);
-    mask = image_from_pict (pMask, FALSE, &msk_xoff, &msk_yoff);
-    dest = image_from_pict (pDst, TRUE, &dst_xoff, &dst_yoff);
+    src = image_from_pict (pSrc, TRUE);
+    mask = image_from_pict (pMask, TRUE);
+    dest = image_from_pict (pDst, TRUE);
 
     if (src && dest && !(pMask && !mask))
     {
 	pixman_image_composite (op, src, mask, dest,
-				xSrc + src_xoff, ySrc + src_yoff,
-				xMask + msk_xoff, yMask + msk_yoff,
-				xDst + dst_xoff, yDst + dst_yoff,
+				xSrc, ySrc, xMask, yMask, xDst, yDst,
 				width, height);
     }
 
@@ -146,22 +141,22 @@ create_conical_gradient_image (PictGradient *gradient)
 
 static pixman_image_t *
 create_bits_picture (PicturePtr pict,
-		     Bool       has_clip,
-		     int	*xoff,
-		     int	*yoff)
+		     Bool       has_clip)
 {
-    PixmapPtr pixmap;
     FbBits *bits;
     FbStride stride;
-    int bpp;
+    int bpp, xoff, yoff;
     pixman_image_t *image;
     
-    fbGetDrawablePixmap (pict->pDrawable, pixmap, *xoff, *yoff);
-    fbGetPixmapBitsData(pixmap, bits, stride, bpp);
+    fbGetDrawable (pict->pDrawable, bits, stride, bpp, xoff, yoff);
+
+    bits = (FbBits*)((CARD8*)bits +
+		     (pict->pDrawable->y + yoff) * stride * sizeof(FbBits) +
+		     (pict->pDrawable->x + xoff) * (bpp / 8));
 
     image = pixman_image_create_bits (
 	(pixman_format_code_t)pict->format,
-	pixmap->drawable.width, pixmap->drawable.height,
+	pict->pDrawable->width, pict->pDrawable->height,
 	(uint32_t *)bits, stride * sizeof (FbStride));
 
     if (!image)
@@ -189,55 +184,33 @@ create_bits_picture (PicturePtr pict,
 	if (pict->clientClipType != CT_NONE)
 	    pixman_image_set_has_client_clip (image, TRUE);
 
-	if (*xoff || *yoff)
-	    pixman_region_translate (pict->pCompositeClip, *xoff, *yoff);
+	pixman_region_translate (pict->pCompositeClip, - pict->pDrawable->x, - pict->pDrawable->y);
 
 	pixman_image_set_clip_region (image, pict->pCompositeClip);
 
-	if (*xoff || *yoff)
-	    pixman_region_translate (pict->pCompositeClip, -*xoff, -*yoff);
+	pixman_region_translate (pict->pCompositeClip, pict->pDrawable->x, pict->pDrawable->y);
     }
     
     /* Indexed table */
     if (pict->pFormat->index.devPrivate)
 	pixman_image_set_indexed (image, pict->pFormat->index.devPrivate);
 
-    /* Add in drawable origin to position within the image */
-    *xoff += pict->pDrawable->x;
-    *yoff += pict->pDrawable->y;
-
     return image;
 }
 
 static pixman_image_t *
-image_from_pict_internal (PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map);
+image_from_pict_internal (PicturePtr pict, Bool has_clip, Bool is_alpha_map);
 
 static void
-set_image_properties (pixman_image_t *image, PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map)
+set_image_properties (pixman_image_t *image, PicturePtr pict, Bool is_alpha_map)
 {
     pixman_repeat_t repeat;
     pixman_filter_t filter;
     
     if (pict->transform)
     {
-	/* For source images, adjust the transform to account
-	 * for the drawable offset within the pixman image,
-	 * then set the offset to 0 as it will be used
-	 * to compute positions within the transformed image.
-	 */
-	if (!has_clip) {
-	    struct pixman_transform	adjusted;
-
-	    adjusted = *pict->transform;
-	    pixman_transform_translate(&adjusted,
-				       NULL,
-				       pixman_int_to_fixed(*xoff),
-				       pixman_int_to_fixed(*yoff));
-	    pixman_image_set_transform (image, &adjusted);
-	    *xoff = 0;
-	    *yoff = 0;
-	} else
-	    pixman_image_set_transform (image, pict->transform);
+	pixman_image_set_transform (
+	    image, (pixman_transform_t *)pict->transform);
     }
     
     switch (pict->repeatType)
@@ -267,8 +240,7 @@ set_image_properties (pixman_image_t *image, PicturePtr pict, Bool has_clip, int
      */
     if (pict->alphaMap && !is_alpha_map)
     {
-	int alpha_xoff, alpha_yoff;
-	pixman_image_t *alpha_map = image_from_pict_internal (pict->alphaMap, FALSE, &alpha_xoff, &alpha_yoff, TRUE);
+	pixman_image_t *alpha_map = image_from_pict_internal (pict->alphaMap, TRUE, TRUE);
 	
 	pixman_image_set_alpha_map (
 	    image, alpha_map, pict->alphaOrigin.x, pict->alphaOrigin.y);
@@ -301,7 +273,8 @@ set_image_properties (pixman_image_t *image, PicturePtr pict, Bool has_clip, int
 }
 
 static pixman_image_t *
-image_from_pict_internal (PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map)
+image_from_pict_internal (PicturePtr pict,
+		 Bool has_clip, Bool is_alpha_map)
 {
     pixman_image_t *image = NULL;
 
@@ -310,7 +283,7 @@ image_from_pict_internal (PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
 
     if (pict->pDrawable)
     {
-	image = create_bits_picture (pict, has_clip, xoff, yoff);
+	image = create_bits_picture (pict, has_clip);
     }
     else if (pict->pSourcePict)
     {
@@ -331,19 +304,18 @@ image_from_pict_internal (PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
 	    else if (sp->type == SourcePictTypeConical)
 		image = create_conical_gradient_image (gradient);
 	}
-	*xoff = *yoff = 0;
     }
     
     if (image)
-	set_image_properties (image, pict, has_clip, xoff, yoff, is_alpha_map);
+	set_image_properties (image, pict, is_alpha_map);
     
     return image;
 }
 
 pixman_image_t *
-image_from_pict (PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
+image_from_pict (PicturePtr pict, Bool has_clip)
 {
-    return image_from_pict_internal (pict, has_clip, xoff, yoff, FALSE);
+    return image_from_pict_internal (pict, has_clip, FALSE);
 }
 
 void
diff --git a/fb/fbtrap.c b/fb/fbtrap.c
index 0b5a638..fbe2647 100644
--- a/fb/fbtrap.c
+++ b/fb/fbtrap.c
@@ -39,12 +39,11 @@ fbAddTraps (PicturePtr	pPicture,
 	    xTrap	*traps)
 {
     pixman_image_t *image;
-    int dst_xoff, dst_yoff;
 
-    if (!(image = image_from_pict (pPicture, FALSE, &dst_xoff, &dst_yoff)))
+    if (!(image = image_from_pict (pPicture, FALSE)))
 	return;
     
-    pixman_add_traps (image, x_off + dst_xoff, y_off + dst_yoff,
+    pixman_add_traps (image, x_off, y_off,
 		      ntrap, (pixman_trap_t *)traps);
 
     free_pixman_pict (pPicture, image);
@@ -57,14 +56,13 @@ fbRasterizeTrapezoid (PicturePtr    pPicture,
 		      int	    y_off)
 {
     pixman_image_t *image;
-    int	dst_xoff, dst_yoff;
 
-    if (!(image = image_from_pict (pPicture, FALSE, &dst_xoff, &dst_yoff)))
+    if (!(image = image_from_pict (pPicture, FALSE)))
 	return;
 
     pixman_rasterize_trapezoid (image, (pixman_trapezoid_t *)trap,
-				x_off + dst_xoff,
-				y_off + dst_yoff);
+				x_off,
+				y_off);
 
     free_pixman_pict (pPicture, image);
 }
@@ -77,13 +75,12 @@ fbAddTriangles (PicturePtr  pPicture,
 		xTriangle *tris)
 {
     pixman_image_t *image;
-    int dst_xoff, dst_yoff;
 
-    if (!(image = image_from_pict (pPicture, FALSE, &dst_xoff, &dst_yoff)))
+    if (!(image = image_from_pict (pPicture, FALSE)))
 	return;
     
     pixman_add_triangles (image,
-			  dst_xoff + x_off, dst_yoff + y_off,
+			  x_off, y_off,
 			  ntri, (pixman_triangle_t *)tris);
 
     free_pixman_pict (pPicture, image);
@@ -110,13 +107,11 @@ fbShapes (CompositeShapesFunc	composite,
 	  const uint8_t *	shapes)
 {
     pixman_image_t *src, *dst;
-    int src_xoff, src_yoff;
-    int dst_xoff, dst_yoff;
 
     miCompositeSourceValidate (pSrc);
 
-    src = image_from_pict (pSrc, FALSE, &src_xoff, &src_yoff);
-    dst = image_from_pict (pDst, TRUE, &dst_xoff, &dst_yoff);
+    src = image_from_pict (pSrc, FALSE);
+    dst = image_from_pict (pDst, TRUE);
 
     if (src && dst)
     {
@@ -136,10 +131,10 @@ fbShapes (CompositeShapesFunc	composite,
 	    for (i = 0; i < nshapes; ++i)
 	    {
 		composite (op, src, dst, format,
-			   xSrc + src_xoff,
-			   ySrc + src_yoff,
-			   dst_xoff,
-			   dst_yoff,
+			   xSrc,
+			   ySrc,
+			   0,
+			   0,
 			   1, shapes + i * shape_size);
 	    }
 	}
@@ -162,10 +157,10 @@ fbShapes (CompositeShapesFunc	composite,
 	    }
 	    
 	    composite (op, src, dst, format,
-		       xSrc + src_xoff,
-		       ySrc + src_yoff,
-		       dst_xoff,
-		       dst_yoff,
+		       xSrc,
+		       ySrc,
+		       0,
+		       0,
 		       nshapes, shapes);
 	}
 
commit de7fc732b2870c78f14deaf17c6d67a230d24c47
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Fri Apr 30 13:08:25 2010 -0700

    Workaround the GC clipping problem in miPaintWindow and add some debugging output.
    
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>

diff --git a/mi/miexpose.c b/mi/miexpose.c
index 0f1ebe5..dcbfe1c 100644
--- a/mi/miexpose.c
+++ b/mi/miexpose.c
@@ -521,6 +521,7 @@ void RootlessSetPixmapOfAncestors(WindowPtr pWin);
 void RootlessStartDrawing(WindowPtr pWin);
 void RootlessDamageRegion(WindowPtr pWin, RegionPtr prgn);
 Bool IsFramedWindow(WindowPtr pWin);
+#include "../fb/fb.h"
 #endif 
 
 void
@@ -548,24 +549,37 @@ miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what)
     Bool	solid = TRUE;
     DrawablePtr	drawable = &pWin->drawable;
 
+#ifdef XQUARTZ_CLIP_DEBUG
+    ErrorF("START %d BS %d (pR = %ld)\n", what, pWin->backgroundState, ParentRelative);
+    ErrorF("      Rgn: %d %d %d %d\n", prgn->extents.x1, prgn->extents.y1,
+	                               prgn->extents.x2 - prgn->extents.x1,
+	                               prgn->extents.y2 - prgn->extents.y1);
+    ErrorF("      Win: %d %d (%d %d) %d %d\n", pWin->origin.x, pWin->origin.y,
+	                                       pWin->winSize.extents.x1, pWin->winSize.extents.y1,
+	                                       pWin->winSize.extents.x2 - pWin->winSize.extents.x1,
+					       pWin->winSize.extents.y2 - pWin->winSize.extents.y1);
+    ErrorF("     Draw: %d %d %d %d\n", pWin->drawable.x, pWin->drawable.y,
+				       pWin->drawable.width, pWin->drawable.height);
+#endif
+
 #ifdef ROOTLESS
     if(!drawable || drawable->type == UNDRAWABLE_WINDOW)
 	return;
-
-    if(IsFramedWindow(pWin)) {
-        RootlessStartDrawing(pWin);
-        RootlessDamageRegion(pWin, prgn);
-    
-        if(pWin->backgroundState == ParentRelative) {
-            if((what == PW_BACKGROUND) || 
-               (what == PW_BORDER && !pWin->borderIsPixel))
-                RootlessSetPixmapOfAncestors(pWin);
-        }
-    }
 #endif
     
     if (what == PW_BACKGROUND)
     {
+#ifdef ROOTLESS
+	if(IsFramedWindow(pWin)) {
+	    RootlessStartDrawing(pWin);
+	    RootlessDamageRegion(pWin, prgn);
+
+	    if(pWin->backgroundState == ParentRelative) {
+		RootlessSetPixmapOfAncestors(pWin);
+	    }
+	}
+#endif
+
 	while (pWin->backgroundState == ParentRelative)
 	    pWin = pWin->parent;
 
@@ -591,6 +605,18 @@ miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what)
     {
 	PixmapPtr   pixmap;
 
+#ifdef ROOTLESS
+	if(IsFramedWindow(pWin)) {
+	    RootlessStartDrawing(pWin);
+	    RootlessDamageRegion(pWin, prgn);
+	    
+	    if(!pWin->borderIsPixel &&
+		pWin->backgroundState == ParentRelative) {
+		RootlessSetPixmapOfAncestors(pWin);
+	    }
+	}
+#endif
+
 	tile_x_off = drawable->x;
 	tile_y_off = drawable->y;
 	
@@ -599,6 +625,12 @@ miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what)
 	    return;
 	pixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) drawable);
 	drawable = &pixmap->drawable;
+
+#ifdef XQUARTZ_CLIP_DEBUG
+	ErrorF("     Draw: %d %d %d %d\n",
+	       drawable->x, drawable->y, drawable->width, drawable->height);    
+#endif
+	
 #ifdef COMPOSITE
 	draw_x_off = pixmap->screen_x;
 	draw_y_off = pixmap->screen_y;
@@ -661,6 +693,57 @@ miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what)
     ChangeGC (NullClient, pGC, gcmask, gcval);
     ValidateGC (drawable, pGC);
 
+#ifdef XQUARTZ_CLIP_DEBUG
+    ErrorF("       GC: %d %d %d %d\n",
+	   pGC->pCompositeClip->extents.x1, pGC->pCompositeClip->extents.y1,
+	   pGC->pCompositeClip->extents.x2 - pGC->pCompositeClip->extents.x1,
+	   pGC->pCompositeClip->extents.y2 - pGC->pCompositeClip->extents.y1);
+#endif
+    
+#ifdef XQUARTZ
+    /* Looks like our clipping isn't set right for some reason:
+     * http://xquartz.macosforge.org/trac/ticket/290
+     */
+    if(what == PW_BORDER) {
+
+#if 0
+	if(solid) {
+#if 1
+	    fbFillRegionSolid(&pWin->drawable,
+			      prgn,
+			      0,
+			      fbReplicatePixel(fill.pixel,
+					       pWin->drawable.bitsPerPixel));
+#else
+	    fbFillRegionSolid(drawable,
+			      prgn,
+			      0,
+			      fbReplicatePixel(fill.pixel,
+					       drawable->bitsPerPixel));
+#endif
+	    return;
+	}
+#endif
+    
+	pGC->pCompositeClip->extents.x1 += prgn->extents.x1;
+	pGC->pCompositeClip->extents.y1 += prgn->extents.y1;
+	pGC->pCompositeClip->extents.x2 += prgn->extents.x1;
+	pGC->pCompositeClip->extents.y2 += prgn->extents.y1;
+	
+	if(pGC->pCompositeClip->extents.x2 > drawable->pScreen->width)
+	    pGC->pCompositeClip->extents.x2 = drawable->pScreen->width;
+	if(pGC->pCompositeClip->extents.y2 > drawable->pScreen->height)
+	    pGC->pCompositeClip->extents.y2 = drawable->pScreen->height;
+    }
+#endif
+
+#ifdef XQUARTZ_CLIP_DEBUG
+    ErrorF("       GC: %d %d %d %d\n",
+	   pGC->pCompositeClip->extents.x1, pGC->pCompositeClip->extents.y1,
+	   pGC->pCompositeClip->extents.x2 - pGC->pCompositeClip->extents.x1,
+	   pGC->pCompositeClip->extents.y2 - pGC->pCompositeClip->extents.y1);    
+#endif
+
     numRects = RegionNumRects(prgn);
     pbox = RegionRects(prgn);
     for (i= numRects; --i >= 0; pbox++, prect++)
commit c31bf5fa471eef00a58ddf92e5891b45b3778305
Author: Jeremy Huddleston <jeremyhu at apple.com>
Date:   Tue Dec 20 19:49:47 2011 -0800

    XQuartz: GL: Buildfix for recent GLX changes
    
    dispatch.h was leftover from an earlier implementation and is no longer
    needed, so remove it since including it causes a build failure due to
    conflicts between GL/gl.h and OpenGL/gl.h
    
    Signed-off-by: Jeremy Huddleston <jeremyhu at apple.com>
    Reviewed-by: Jamey Sharp <jamey at minilop.net>
    Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>

diff --git a/hw/xquartz/GL/indirect.c b/hw/xquartz/GL/indirect.c
index 27d6dae..e6ff376 100644
--- a/hw/xquartz/GL/indirect.c
+++ b/hw/xquartz/GL/indirect.c
@@ -48,9 +48,6 @@
 #include <glxserver.h>
 #include <glxutil.h>
 
-typedef unsigned long long GLuint64EXT;
-typedef long long GLint64EXT;
-#include <dispatch.h>
 #include <glapi.h>
 
 #include "x-hash.h"
commit a28ff2cf92c2b35e02eacca21af929afabbf6b83
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Thu Dec 22 12:00:37 2011 -0800

    test/xi2: Really fix infinite loop in test_convert_XITouchOwnershipEvent
    
    long i;
    for (i = 1; ; i <<= 1)
      if (i == (1 << 31))
        break;
    
    (1 << 31) is compiled as an int, and thus is equal to -2147483648. We
    are trying to compare it against a long, which on 64-bit machines is
    2147483648. This results in an infinite loop.
    
    Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/test/xi2/protocol-eventconvert.c b/test/xi2/protocol-eventconvert.c
index faa9f40..bf1493c 100644
--- a/test/xi2/protocol-eventconvert.c
+++ b/test/xi2/protocol-eventconvert.c
@@ -1005,7 +1005,7 @@ test_convert_XITouchOwnershipEvent(void)
     {
         in.touchid = i;
         test_XITouchOwnershipEvent(&in);
-	if (i == (1 << 31))
+	if (i == ((long)1 << 31))
 	    break;
     }
 }
commit e7df42ab68e30588a5e32ed543b0711821daf009
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Dec 22 09:35:51 2011 -0800

    test/xi2: Fix infinite loop in test_convert_XITouchOwnershipEvent
    
    The touchid test was using a loop like:
    
    	for(i = 1; i < 0xffffffff; i <<= 1)
    
    When 'i' is a 32-bit variable, this infinite loops as it goes from
    0x80000000 to 0. 'i' is declared as 'long', which is 32-bit in 32-bit mode.
    
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/test/xi2/protocol-eventconvert.c b/test/xi2/protocol-eventconvert.c
index 9872b79..faa9f40 100644
--- a/test/xi2/protocol-eventconvert.c
+++ b/test/xi2/protocol-eventconvert.c
@@ -1001,10 +1001,12 @@ test_convert_XITouchOwnershipEvent(void)
         test_XITouchOwnershipEvent(&in);
     }
 
-    for (i = 1; i <= 0xFFFFFFFF; i <<= 1)
+    for (i = 1; ; i <<= 1)
     {
         in.touchid = i;
         test_XITouchOwnershipEvent(&in);
+	if (i == (1 << 31))
+	    break;
     }
 }
 
commit f75bdf7fbe757f4603e39139acc3c90538a45e15
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 22 10:00:15 2011 +1000

    test: fix grab mode value tests for new XIGrabModeTouch
    
    This test checks that last-valid-mode + 1 returns a BadValue. With the
    addition of XIGrabModeTouch, that value has changed - sync it up again.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/test/input.c b/test/input.c
index d27b3f0..576cd85 100644
--- a/test/input.c
+++ b/test/input.c
@@ -161,22 +161,31 @@ static void dix_check_grab_values(void)
     rc = CheckGrabValues(&client, &param);
     assert(rc == Success);
 
-    param.this_device_mode = GrabModeAsync + 1;
+    param.this_device_mode = XIGrabModeTouch;
+    rc = CheckGrabValues(&client, &param);
+    assert(rc == Success);
+
+    param.this_device_mode = XIGrabModeTouch + 1;
     rc = CheckGrabValues(&client, &param);
     assert(rc == BadValue);
     assert(client.errorValue == param.this_device_mode);
-    assert(client.errorValue == GrabModeAsync + 1);
+    assert(client.errorValue == XIGrabModeTouch + 1);
 
     param.this_device_mode = GrabModeSync;
     param.other_devices_mode = GrabModeAsync;
     rc = CheckGrabValues(&client, &param);
+
+    param.this_device_mode = GrabModeSync;
+    param.other_devices_mode = XIGrabModeTouch;
+    rc = CheckGrabValues(&client, &param);
+    assert(rc == Success);
     assert(rc == Success);
 
-    param.other_devices_mode = GrabModeAsync + 1;
+    param.other_devices_mode = XIGrabModeTouch + 1;
     rc = CheckGrabValues(&client, &param);
     assert(rc == BadValue);
     assert(client.errorValue == param.other_devices_mode);
-    assert(client.errorValue == GrabModeAsync + 1);
+    assert(client.errorValue == XIGrabModeTouch + 1);
 
     param.other_devices_mode = GrabModeSync;
 
commit e395efc25f9fd60377f32c2bf1a9153d70908236
Merge: 2bb282c fcda98c
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 22 09:29:59 2011 +1000

    Merge branch 'master' of git+ssh://git.freedesktop.org/git/xorg/xserver into multitouch
    
    Conflicts:
    	configure.ac
    	dix/inpututils.c
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

commit 2bb282cd45cb8149b39d72397ef5bbcfebca11d2
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 21 14:45:27 2011 +1000

    Xi: only activate the device grab if we don't already have one
    
    If the device is already grabbed, don't activate the passive grab, it screws
    with our event masks. Just deliver to the grabbing client instead.
    
    Reported-by: Carlos Garnacho <carlosg at gnome.org>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 0849690..db49e31 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1385,8 +1385,8 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent
     if (grab)
     {
         /* this side-steps the usual activation mechansims, but... */
-        if (ev->any.type == ET_TouchBegin)
-            ActivatePassiveGrab(dev, grab, ptrev, ev); /* also delivers the event */
+        if (ev->any.type == ET_TouchBegin && !dev->deviceGrab.grab)
+                ActivatePassiveGrab(dev, grab, ptrev, ev); /* also delivers the event */
         else {
             int deliveries = 0;
             /* 'grab' is the passive grab, but if the grab isn't active,
commit 475ef5cc8339fac3696fe654ef683f92f0b0cc2c
Author: Carlos Garnacho <carlosg at gnome.org>
Date:   Wed Dec 21 01:08:40 2011 +0100

    dix: fix xi2 mask/filter when delivering grabbed events
    
    Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/dix/events.c b/dix/events.c
index d802903..5360267 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -4192,8 +4192,8 @@ DeliverOneGrabbedEvent(InternalEvent *event, DeviceIntPtr dev, enum InputLevel l
             if (rc == Success)
             {
                 int evtype = xi2_get_type(xE);
-                mask = xi2mask_isset(grab->xi2mask, dev, evtype);
-                filter = 1;
+                mask = GetXI2MaskByte(grab->xi2mask, dev, evtype);
+                filter = GetEventFilter(dev, xE);
             }
             break;
         case XI:
commit 4551510f752624592f9201f73db89ac1325a234a
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Dec 19 09:08:05 2011 +1000

    test: add a basic test for ownership event values
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/test/xi2/protocol-eventconvert.c b/test/xi2/protocol-eventconvert.c
index dba5cb1..9872b79 100644
--- a/test/xi2/protocol-eventconvert.c
+++ b/test/xi2/protocol-eventconvert.c
@@ -915,12 +915,106 @@ static void test_convert_XIDeviceChangedEvent(void)
     }
 }
 
+static void
+test_values_XITouchOwnershipEvent(TouchOwnershipEvent *in,
+                                  xXITouchOwnershipEvent *out,
+                                  BOOL swap)
+{
+    if (swap)
+    {
+        swaps(&out->sequenceNumber);
+        swapl(&out->length);
+        swaps(&out->evtype);
+        swaps(&out->deviceid);
+        swaps(&out->sourceid);
+        swapl(&out->time);
+        swapl(&out->touchid);
+        swapl(&out->root);
+        swapl(&out->event);
+        swapl(&out->child);
+        swapl(&out->time);
+    }
+
+    assert(out->type == GenericEvent);
+    assert(out->extension == 0); /* IReqCode defaults to 0 */
+    assert(out->evtype == GetXI2Type(in->type));
+    assert(out->time == in->time);
+    assert(out->deviceid == in->deviceid);
+    assert(out->sourceid == in->sourceid);
+    assert(out->touchid == in->touchid);
+    assert(out->flags == in->reason);
+}
+
+static void
+test_XITouchOwnershipEvent(TouchOwnershipEvent *in)
+{
+    xXITouchOwnershipEvent *out, *swapped;
+    int rc;
+
+    rc = EventToXI2((InternalEvent*)in, (xEvent**)&out);
+    assert(rc == Success);
+
+    test_values_XITouchOwnershipEvent(in, out, FALSE);
+
+    swapped = calloc(1, sizeof(xEvent) + out->length * 4);
+    XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)swapped);
+    test_values_XITouchOwnershipEvent(in, swapped, TRUE);
+    free(out);
+    free(swapped);
+}
+
+static void
+test_convert_XITouchOwnershipEvent(void)
+{
+    TouchOwnershipEvent in;
+    long i;
+
+    memset(&in, 0, sizeof(in));
+    in.header           = ET_Internal;
+    in.type             = ET_TouchOwnership;
+    in.length           = sizeof(in);
+    in.time             = 0;
+    in.deviceid         = 1;
+    in.sourceid         = 2;
+    in.touchid          = 0;
+    in.reason           = 0;
+    in.resource         = 0;
+    in.flags            = 0;
+
+    test_XITouchOwnershipEvent(&in);
+
+    in.flags            = XIAcceptTouch;
+    test_XITouchOwnershipEvent(&in);
+
+    in.flags            = XIRejectTouch;
+    test_XITouchOwnershipEvent(&in);
+
+    for (i = 1; i <= 0xFFFF; i <<= 1)
+    {
+        in.deviceid = i;
+        test_XITouchOwnershipEvent(&in);
+    }
+
+    for (i = 1; i <= 0xFFFF; i <<= 1)
+    {
+        in.sourceid = i;
+        test_XITouchOwnershipEvent(&in);
+    }
+
+    for (i = 1; i <= 0xFFFFFFFF; i <<= 1)
+    {
+        in.touchid = i;
+        test_XITouchOwnershipEvent(&in);
+    }
+}
+
 int main(int argc, char** argv)
 {
     test_convert_XIRawEvent();
     test_convert_XIFocusEvent();
     test_convert_XIDeviceEvent();
     test_convert_XIDeviceChangedEvent();
+    test_convert_XITouchOwnershipEvent();
 
     return 0;
 }
commit 0c661dc478b4b436a3e61066d31bc510c7a08456
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Dec 19 08:31:37 2011 +1000

    test: drop printfs from protocol-eventconvert.c
    
    The test outputs are noisy enough, no need having these here too.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/test/xi2/protocol-eventconvert.c b/test/xi2/protocol-eventconvert.c
index e2037f9..dba5cb1 100644
--- a/test/xi2/protocol-eventconvert.c
+++ b/test/xi2/protocol-eventconvert.c
@@ -193,7 +193,6 @@ static void test_convert_XIRawEvent(void)
 
     memset(&in, 0, sizeof(in));
 
-    printf("Testing all event types\n");
     in.header = ET_Internal;
     in.type = ET_RawMotion;
     test_XIRawEvent(&in);
@@ -214,7 +213,6 @@ static void test_convert_XIRawEvent(void)
     in.type = ET_RawButtonRelease;
     test_XIRawEvent(&in);
 
-    printf("Testing details and other fields\n");
     in.detail.button = 1L;
     test_XIRawEvent(&in);
     in.detail.button = 1L << 8;
@@ -246,7 +244,6 @@ static void test_convert_XIRawEvent(void)
     in.deviceid = ~0 & 0xFF;
     test_XIRawEvent(&in);
 
-    printf("Testing valuator masks\n");
     for (i = 0; i < MAX_VALUATORS; i++)
     {
         XISetMask(in.valuators.mask, i);
@@ -432,7 +429,6 @@ static void test_convert_XIDeviceEvent(void)
 
     memset(&in, 0, sizeof(in));
 
-    printf("Testing simple field values\n");
     in.header = ET_Internal;
     in.type = ET_Motion;
     in.length = sizeof(DeviceEvent);
@@ -456,7 +452,6 @@ static void test_convert_XIDeviceEvent(void)
 
     test_XIDeviceEvent(&in);
 
-    printf("Testing field ranges\n");
     /* 32 bit */
     in.detail.button = 1L;
     test_XIDeviceEvent(&in);
@@ -604,7 +599,6 @@ static void test_convert_XIDeviceEvent(void)
     in.mods.effective = ~0 & 0xFF;
     test_XIDeviceEvent(&in);
 
-    printf("Testing button masks\n");
     for (i = 0; i < sizeof(in.buttons) * 8; i++)
     {
         XISetMask(in.buttons, i);
@@ -618,7 +612,6 @@ static void test_convert_XIDeviceEvent(void)
         test_XIDeviceEvent(&in);
     }
 
-    printf("Testing valuator masks\n");
     for (i = 0; i < MAX_VALUATORS; i++)
     {
         XISetMask(in.valuators.mask, i);
@@ -799,7 +792,6 @@ static void test_convert_XIDeviceChangedEvent(void)
     DeviceChangedEvent in;
     int i;
 
-    printf("Testing simple field values\n");
     memset(&in, 0, sizeof(in));
     in.header = ET_Internal;
     in.type = ET_DeviceChanged;
commit 8080d785b2c1e5791312ed0975efd1b8aea58d98
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 21 11:11:48 2011 +1000

    dix: remove requirement for client_id be the first element
    
    Leftover code from an earlier version of GetTouchEvents.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/getevents.c b/dix/getevents.c
index b60ddc0..3b40a5b 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -1738,6 +1738,7 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
     } touchpoint;
     int need_rawevent = TRUE;
     Bool emulate_pointer = FALSE;
+    int client_id = 0;
 
     if (!dev->enabled || !t || !v)
         return 0;
@@ -1761,6 +1762,7 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
         }
 
         need_rawevent = FALSE;
+        client_id = touchpoint.dix_ti->client_id;
     } else /* a DDX-submitted touch */
     {
         touchpoint.ti = TouchFindByDDXID(dev, ddx_touchid, (type == XI_TouchBegin));
@@ -1770,6 +1772,7 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
                     type == XI_TouchBegin ? "begin" : "find", ddx_touchid);
             return 0;
         }
+        client_id = touchpoint.ti->client_id;
     }
 
     if (!(flags & TOUCH_CLIENT_ID))
@@ -1787,7 +1790,7 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
         raw = &events->raw_event;
         events++;
         num_events++;
-        init_raw(dev, raw, ms, type, touchpoint.ti->client_id);
+        init_raw(dev, raw, ms, type, client_id);
         set_raw_valuators(raw, &mask, raw->valuators.data_raw);
     }
 
@@ -1877,7 +1880,7 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
     event->root = scr->root->drawable.id;
 
     event_set_root_coordinates(event, screenx, screeny);
-    event->touchid = touchpoint.ti->client_id;
+    event->touchid = client_id;
     event->flags = flags;
 
     if (emulate_pointer)
diff --git a/include/inputstr.h b/include/inputstr.h
index 9881c7e..518e2f4 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -301,7 +301,6 @@ typedef struct _ValuatorClassRec {
 } ValuatorClassRec;
 
 typedef struct _TouchPointInfo {
-    /* client_id must be first element, see GetTouchEvents */
     uint32_t    client_id;          /* touch ID as seen in client events */
     int         sourceid;           /* Source device's ID for this touchpoint */
     Bool        active;             /* whether or not the touch is active */
@@ -328,7 +327,6 @@ typedef struct _TouchPointInfo {
 typedef struct _TouchListener TouchListener;
 
 typedef struct _DDXTouchPointInfo {
-    /* client_id must be first element, see GetTouchEvents */
     uint32_t    client_id;          /* touch ID as seen in client events */
     Bool        active;             /* whether or not the touch is active */
     uint32_t    ddx_id;             /* touch ID given by the DDX */
commit 552de314bf0c8e4de5d002bdd1c12388c2f42283
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Dec 19 14:52:41 2011 +1000

    dix: don't retrieve the syncEvents tail on an empty list
    
    An empty list points to itself but syncEvents has the list head only and is
    of a different format than the elements. Thus, casting it to a QdEventPtr
    gives us garbage.
    
    Segfaults with XTS test case Xlib13/XGrabKeyboard
    
    Introduced in 7af23259d88f4c28ed21140f82cc03b3724c06bb.
    
    Reported-by: Aaron Plattner <aplattner at nvidia.com>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/events.c b/dix/events.c
index 48cf7a2..d802903 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1116,13 +1116,14 @@ NoticeEventTime(InternalEvent *ev)
 void
 EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
 {
-    QdEventPtr	tail;
+    QdEventPtr	tail = NULL;
     QdEventPtr	qe;
     SpritePtr	pSprite = device->spriteInfo->sprite;
     int		eventlen;
     DeviceEvent *event = &ev->device_event;
 
-    tail = list_last_entry(&syncEvents.pending, QdEventRec, next);
+    if (!list_is_empty(&syncEvents.pending))
+        tail = list_last_entry(&syncEvents.pending, QdEventRec, next);
 
     NoticeTime((InternalEvent*)event);
 
commit 76c11e0872dedcd360cbe02cf62bb9de3b212957
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Dec 16 12:41:08 2011 +1000

    dix: button state must show the logical buttons, not physical buttons
    
    If the device is mapped 3 2 1, a click on physical button 1 sends a button 3
    press, but the state was set for button 1. Fix this, the state must be set
    for that button's logical mapping.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=655928
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/inpututils.c b/dix/inpututils.c
index 50a122f..d279c1d 100644
--- a/dix/inpututils.c
+++ b/dix/inpututils.c
@@ -674,7 +674,7 @@ void event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd, DeviceEvent *event)
 
     for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++)
         if (BitIsOn(mouse->button->down, i))
-            SetBit(event->buttons, i);
+            SetBit(event->buttons, mouse->button->map[i]);
 
     if (mouse && mouse->touch && mouse->touch->buttonsDown > 0)
         SetBit(event->buttons, mouse->button->map[1]);
commit 8a32c39c00789c16006de61112627722ce548be1
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 15 07:59:06 2011 +1000

    mi: handle screen switching on pointer emulated touch events
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/mi/mieq.c b/mi/mieq.c
index 5bdf971..6c46eb9 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -514,6 +514,12 @@ mieqProcessDeviceEvent(DeviceIntPtr dev,
             if (!handler)
                 mieqMoveToNewScreen(dev, screen, &event->device_event);
             break;
+        case ET_TouchBegin:
+        case ET_TouchUpdate:
+        case ET_TouchEnd:
+            if (!handler && (event->device_event.flags & TOUCH_POINTER_EMULATED))
+                mieqMoveToNewScreen(dev, screen, &event->device_event);
+            break;
         default:
             break;
     }
commit 48547068b115b1f5e5f46a70110454a2175fb9a4
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 15 07:57:47 2011 +1000

    mi: split move to new screen logic to a helper function
    
    No functional changes.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/mi/mieq.c b/mi/mieq.c
index ea8bcf0..5bdf971 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -471,6 +471,19 @@ CopyGetMasterEvent(DeviceIntPtr sdev,
 }
 
 
+static void
+mieqMoveToNewScreen(DeviceIntPtr dev, ScreenPtr screen, DeviceEvent *event)
+{
+    if (dev && screen && screen != DequeueScreen(dev))
+    {
+        int x = 0, y = 0;
+        DequeueScreen(dev) = screen;
+        x = event->root_x;
+        y = event->root_y;
+        NewCurrentScreen (dev, DequeueScreen(dev), x, y);
+    }
+}
+
 /**
  * Post the given @event through the device hierarchy, as appropriate.
  * Use this function if an event must be posted for a given device during the
@@ -482,7 +495,6 @@ mieqProcessDeviceEvent(DeviceIntPtr dev,
                        ScreenPtr screen)
 {
     mieqHandler handler;
-    int x = 0, y = 0;
     DeviceIntPtr master;
     InternalEvent mevent; /* master event */
 
@@ -499,12 +511,8 @@ mieqProcessDeviceEvent(DeviceIntPtr dev,
         case ET_KeyRelease:
         case ET_ButtonPress:
         case ET_ButtonRelease:
-            if (dev && screen && screen != DequeueScreen(dev) && !handler) {
-                DequeueScreen(dev) = screen;
-                x = event->device_event.root_x;
-                y = event->device_event.root_y;
-                NewCurrentScreen (dev, DequeueScreen(dev), x, y);
-            }
+            if (!handler)
+                mieqMoveToNewScreen(dev, screen, &event->device_event);
             break;
         default:
             break;
commit 3b1e2035cc4740711360c845cfcdff07f7b60558
Author: Daniel Stone <daniel at fooishbar.org>
Date:   Thu Dec 15 07:52:28 2011 +1000

    dix: Remove touch grabs if the grab disappears
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/grabs.c b/dix/grabs.c
index da014df..701470c 100644
--- a/dix/grabs.c
+++ b/dix/grabs.c
@@ -266,6 +266,9 @@ CreateGrab(
 void
 FreeGrab(GrabPtr pGrab)
 {
+    if (pGrab->grabtype == XI2 && pGrab->type == XI_TouchBegin)
+        TouchListenerGone(pGrab->resource);
+
     free(pGrab->modifiersDetail.pMask);
     free(pGrab->detail.pMask);
 
diff --git a/dix/touch.c b/dix/touch.c
index 9bd07c3..db0bf33 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -37,6 +37,7 @@
 #include "inpututils.h"
 #include "eventconvert.h"
 #include "windowstr.h"
+#include "mi.h"
 
 #define TOUCH_HISTORY_SIZE 100
 
@@ -936,3 +937,46 @@ TouchRemovePointerGrab(DeviceIntPtr dev)
     if (!ti)
         return;
 }
+
+/* As touch grabs don't turn into active grabs with their own resources, we
+ * need to walk all the touches and remove this grab from any delivery
+ * lists. */
+void
+TouchListenerGone(XID resource)
+{
+    TouchPointInfoPtr ti;
+    DeviceIntPtr dev;
+    InternalEvent *events = InitEventList(GetMaximumEventsNum());
+    int i, j, k, nev;
+
+    if (!events)
+        FatalError("TouchListenerGone: couldn't allocate events\n");
+
+    for (dev = inputInfo.devices; dev; dev = dev->next)
+    {
+        if (!dev->touch)
+            continue;
+
+        for (i = 0; i < dev->touch->num_touches; i++)
+        {
+            ti = &dev->touch->touches[i];
+            if (!ti->active)
+                continue;
+
+            for (j = 0; j < ti->num_listeners; j++)
+            {
+                if (ti->listeners[j].listener != resource)
+                    continue;
+
+                nev = GetTouchOwnershipEvents(events, dev, ti, XIRejectTouch,
+                                              resource, 0);
+                for (k = 0; k < nev; k++)
+                    mieqProcessDeviceEvent(dev, events + k, NULL);
+
+                break;
+            }
+        }
+    }
+
+    FreeEventList(events, GetMaximumEventsNum());
+}
diff --git a/include/input.h b/include/input.h
index 4ed9dce..fb45617 100644
--- a/include/input.h
+++ b/include/input.h
@@ -623,6 +623,7 @@ extern int TouchConvertToPointerEvent(const InternalEvent *ev,
                                       InternalEvent *motion, InternalEvent *button);
 extern int TouchGetPointerEventType(const InternalEvent *ev);
 extern void TouchRemovePointerGrab(DeviceIntPtr dev);
+extern void TouchListenerGone(XID resource);
 
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients);
commit cd3de8324e8908955a2e4be3000c8ffee8684c68
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 15 07:48:49 2011 +1000

    dix: hook up passive grabs and pointer emulated passive grabs
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/events.c b/dix/events.c
index d8530ef..48cf7a2 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -152,6 +152,7 @@ typedef const char *string;
 #include "eventstr.h"
 #include "enterleave.h"
 #include "eventconvert.h"
+#include "mi.h"
 
 /* Extension events type numbering starts at EXTENSION_EVENT_BASE.  */
 #define NoSuchEvent 0x80000000	/* so doesn't match NoEventMask */
@@ -1308,7 +1309,17 @@ ComputeFreezes(void)
                        event->root_x, event->root_y);
         if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin))
         {
-            if (replayDev->focus && !IsPointerEvent((InternalEvent*)event))
+            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();
+            } else if (replayDev->focus && !IsPointerEvent((InternalEvent*)event))
                 DeliverFocusedEvent(replayDev, (InternalEvent*)event, w);
             else
                 DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab,
@@ -1513,6 +1524,8 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
     Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
                         mouse->deviceGrab.implicitGrab);
 
+    TouchRemovePointerGrab(mouse);
+
     mouse->valuator->motionHintWindow = NullWindow;
     mouse->deviceGrab.grab = NullGrab;
     mouse->deviceGrab.sync.state = NOT_GRABBED;
@@ -3829,6 +3842,7 @@ CheckPassiveGrab(DeviceIntPtr device, GrabPtr grab, InternalEvent *event,
     DeviceIntPtr gdev;
     XkbSrvInfoPtr xkbi = NULL;
     enum MatchFlags match = 0;
+    int emulated_type = 0;
 
     gdev = grab->modifierDevice;
     if (grab->grabtype == CORE)
@@ -3850,13 +3864,26 @@ CheckPassiveGrab(DeviceIntPtr device, GrabPtr grab, InternalEvent *event,
     tempGrab->modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0;
 
     /* Check for XI2 and XI grabs first */
-    match = MatchForType(grab, tempGrab, XI2, GetXI2Type(event->any.type));
+    match = MatchForType(grab, tempGrab, XI2, event->any.type);
+
+    if (!match && IsTouchEvent(event) && (event->device_event.flags & TOUCH_POINTER_EMULATED))
+    {
+        emulated_type = TouchGetPointerEventType(event);
+        match = MatchForType(grab, tempGrab, XI2, emulated_type);
+    }
 
     if (!match)
-        match = MatchForType(grab, tempGrab, XI, GetXIType(event->any.type));
+        match = MatchForType(grab, tempGrab, XI, event->any.type);
+
+    if (!match && emulated_type)
+        match = MatchForType(grab, tempGrab, XI, emulated_type);
 
     if (!match && checkCore)
-        match = MatchForType(grab, tempGrab, CORE, GetCoreType(event->any.type));
+    {
+        match = MatchForType(grab, tempGrab, CORE, event->any.type);
+        if (!match && emulated_type)
+            match = MatchForType(grab, tempGrab, CORE, emulated_type);
+    }
 
     if (!match || (grab->confineTo &&
                    (!grab->confineTo->realized ||
@@ -3930,6 +3957,8 @@ CheckPassiveGrabsOnWindow(
             break;
         case ET_ButtonPress:
         case ET_ButtonRelease:
+        case ET_TouchBegin:
+        case ET_TouchEnd:
             tempGrab->detail.exact = event->device_event.detail.button;
             break;
         default:
diff --git a/dix/touch.c b/dix/touch.c
index 5731d91..9bd07c3 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -910,3 +910,29 @@ TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
             return;
     }
 }
+
+/**
+ * Remove the touch pointer grab from the device. Called from AllowSome()
+ */
+void
+TouchRemovePointerGrab(DeviceIntPtr dev)
+{
+    TouchPointInfoPtr ti;
+    GrabPtr grab;
+    DeviceEvent *ev;
+
+    if (!dev->touch)
+        return;
+
+    grab = dev->deviceGrab.grab;
+    if (!grab)
+        return;
+
+    ev = dev->deviceGrab.sync.event;
+    if (!IsTouchEvent((InternalEvent*)ev))
+        return;
+
+    ti = TouchFindByClientID(dev, ev->touchid);
+    if (!ti)
+        return;
+}
diff --git a/include/input.h b/include/input.h
index 03eb053..4ed9dce 100644
--- a/include/input.h
+++ b/include/input.h
@@ -622,6 +622,7 @@ extern Bool TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite);
 extern int TouchConvertToPointerEvent(const InternalEvent *ev,
                                       InternalEvent *motion, InternalEvent *button);
 extern int TouchGetPointerEventType(const InternalEvent *ev);
+extern void TouchRemovePointerGrab(DeviceIntPtr dev);
 
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients);
commit 5b169cb695bd450d7f64e3800f00c9237ee67f96
Author: Carlos Garnacho <carlosg at gnome.org>
Date:   Tue Dec 13 15:41:23 2011 +0100

    Xi: assign correct grab_mode/other_device_mode in XI2 passive grabs
    
    CreateGrab() expects the keyboard mode to be stored in grab_mode, and the
    pointer mode in other_device_mode, so respect this in passive XI2 grabs,
    and switch modes if needed.
    
    Signed-off-by: Carlos Garnacho <carlosg at gnome.org>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c
index 5d34abc..c80da80 100644
--- a/Xi/xipassivegrab.c
+++ b/Xi/xipassivegrab.c
@@ -151,11 +151,17 @@ ProcXIPassiveGrabDevice(ClientPtr client)
     memset(&param, 0, sizeof(param));
     param.grabtype = XI2;
     param.ownerEvents = stuff->owner_events;
-    param.this_device_mode = stuff->grab_mode;
-    param.other_devices_mode = stuff->paired_device_mode;
     param.grabWindow = stuff->grab_window;
     param.cursor = stuff->cursor;
 
+    if (IsKeyboardDevice(dev)) {
+        param.this_device_mode = stuff->grab_mode;
+        param.other_devices_mode = stuff->paired_device_mode;
+    } else {
+        param.this_device_mode = stuff->paired_device_mode;
+        param.other_devices_mode = stuff->grab_mode;
+    }
+
     if (stuff->cursor != None)
     {
         ret = dixLookupResourceByType(&tmp, stuff->cursor,
commit 4469430b109fa2da7ba3d2fadf66eca78b7156a0
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 15 07:42:12 2011 +1000

    Xi: add the hooks for passive touch grabs
    
    Co-authored-by: Daniel Stone <daniel at fooishbar.org>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index f1598f7..0849690 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -2253,12 +2253,14 @@ CheckGrabValues(ClientPtr client, GrabParameters* param)
     }
 
     if ((param->this_device_mode != GrabModeSync) &&
-	(param->this_device_mode != GrabModeAsync)) {
+	(param->this_device_mode != GrabModeAsync) &&
+        (param->this_device_mode != XIGrabModeTouch)) {
 	client->errorValue = param->this_device_mode;
 	return BadValue;
     }
     if ((param->other_devices_mode != GrabModeSync) &&
-	(param->other_devices_mode != GrabModeAsync)) {
+	(param->other_devices_mode != GrabModeAsync) &&
+        (param->other_devices_mode != XIGrabModeTouch)) {
 	client->errorValue = param->other_devices_mode;
 	return BadValue;
     }
@@ -2423,6 +2425,34 @@ GrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
     return AddPassiveGrabToList(client, grab);
 }
 
+/* Touch grab */
+int
+GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
+          GrabParameters *param, GrabMask *mask)
+{
+    WindowPtr pWin;
+    GrabPtr grab;
+    int rc;
+
+    rc = CheckGrabValues(client, param);
+    if (rc != Success)
+        return rc;
+
+    rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
+    if (rc != Success)
+       return rc;
+    rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGrabAccess);
+    if (rc != Success)
+       return rc;
+
+    grab = CreateGrab(client->index, dev, mod_dev, pWin, XI2,
+                      mask, param, XI_TouchBegin, 0, NullWindow, NullCursor);
+    if (!grab)
+        return BadAlloc;
+
+    return AddPassiveGrabToList(client, grab);
+}
+
 int
 SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client,
 		Mask mask, Mask exclusivemasks)
diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c
index 713a165..5d34abc 100644
--- a/Xi/xipassivegrab.c
+++ b/Xi/xipassivegrab.c
@@ -108,19 +108,29 @@ ProcXIPassiveGrabDevice(ClientPtr client)
     if (stuff->grab_type != XIGrabtypeButton &&
         stuff->grab_type != XIGrabtypeKeycode &&
         stuff->grab_type != XIGrabtypeEnter &&
-        stuff->grab_type != XIGrabtypeFocusIn)
+        stuff->grab_type != XIGrabtypeFocusIn &&
+        stuff->grab_type != XIGrabtypeTouchBegin)
     {
         client->errorValue = stuff->grab_type;
         return BadValue;
     }
 
     if ((stuff->grab_type == XIGrabtypeEnter ||
-         stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0)
+         stuff->grab_type == XIGrabtypeFocusIn ||
+         stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0)
     {
         client->errorValue = stuff->detail;
         return BadValue;
     }
 
+    if (stuff->grab_type == XIGrabtypeTouchBegin &&
+        (stuff->grab_mode != XIGrabModeTouch ||
+         stuff->paired_device_mode != GrabModeAsync))
+    {
+        client->errorValue = stuff->grab_mode;
+        return BadValue;
+    }
+
     if (XICheckInvalidMaskBits(client, (unsigned char*)&stuff[1],
                                stuff->mask_len * 4) != Success)
         return BadValue;
@@ -194,6 +204,9 @@ ProcXIPassiveGrabDevice(ClientPtr client)
                 status = GrabWindow(client, dev, stuff->grab_type,
                                     &param, &mask);
                 break;
+            case XIGrabtypeTouchBegin:
+                status = GrabTouch(client, dev, mod_dev, &param, &mask);
+                break;
         }
 
         if (status != GrabSuccess)
diff --git a/include/exevents.h b/include/exevents.h
index 0186f53..bd16970 100644
--- a/include/exevents.h
+++ b/include/exevents.h
@@ -222,6 +222,14 @@ GrabWindow(
 	GrabMask*              /* eventMask */);
 
 extern int
+GrabTouch(
+       ClientPtr              /* client */,
+       DeviceIntPtr           /* dev */,
+       DeviceIntPtr           /* mod_dev */,
+       GrabParameters*        /* param */,
+       GrabMask*              /* eventMask */);
+
+extern int
 SelectForWindow(
 	DeviceIntPtr           /* dev */,
 	WindowPtr              /* pWin */,
commit bb0af002dc9ad5b464dc6793aedb6d1ff65d001d
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 15 07:21:38 2011 +1000

    Xi: handle grab accept/reject requests
    
    Consists mostly of generating an ownership event and processing it.
    
    Co-authored-by: Daniel Stone <daniel at fooishbar.org>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/xiallowev.c b/Xi/xiallowev.c
index 0d45b36..a4b2f57 100644
--- a/Xi/xiallowev.c
+++ b/Xi/xiallowev.c
@@ -35,6 +35,8 @@
 
 #include "inputstr.h"	/* DeviceIntPtr      */
 #include "windowstr.h"	/* window structure  */
+#include "mi.h"
+#include "eventstr.h"
 #include <X11/extensions/XI2.h>
 #include <X11/extensions/XI2proto.h>
 
@@ -49,10 +51,53 @@ SProcXIAllowEvents(ClientPtr client)
     swaps(&stuff->length);
     swaps(&stuff->deviceid);
     swapl(&stuff->time);
+    /* FIXME swap touchid */
+    /* FIXME swap window */
 
     return ProcXIAllowEvents(client);
 }
 
+static int
+AllowTouch(ClientPtr client, DeviceIntPtr dev, int mode, uint32_t touchid, XID *error)
+{
+    TouchPointInfoPtr ti;
+    int nev, i;
+    InternalEvent *events = InitEventList(GetMaximumEventsNum());
+
+    if (!events)
+        return BadAlloc;
+
+    if (!dev->touch)
+    {
+        *error = dev->id;
+        return BadDevice;
+    }
+
+    /* FIXME window is unhandled */
+
+    ti = TouchFindByClientID(dev, touchid);
+    if (!ti)
+    {
+        *error = touchid;
+        return BadValue;
+    }
+
+    /* FIXME: Allow for early accept */
+    if (ti->num_listeners == 0 || CLIENT_ID(ti->listeners[0].listener) != client->index)
+        return BadAccess;
+
+    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;
+}
+
 int
 ProcXIAllowEvents(ClientPtr client)
 {
@@ -61,7 +106,7 @@ ProcXIAllowEvents(ClientPtr client)
     int ret = Success;
 
     REQUEST(xXIAllowEventsReq);
-    REQUEST_SIZE_MATCH(xXIAllowEventsReq);
+    /* FIXME: check request length, 12 for XI 2.0+, 20 for XI 2.2+ */
 
     ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess);
     if (ret != Success)
@@ -91,6 +136,12 @@ ProcXIAllowEvents(ClientPtr client)
         if (IsMaster(dev))
             AllowSome(client, time, dev, THAWED_BOTH);
 	break;
+    case XIRejectTouch:
+    case XIAcceptTouch:
+        ret = AllowTouch(client, dev,
+                         stuff->mode, stuff->touchid,
+                         &client->errorValue);
+        break;
     default:
 	client->errorValue = stuff->mode;
 	ret = BadValue;
commit 209b3d613a7bed126c81daedbad6461e4391e9e6
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Dec 20 16:34:43 2011 -0800

    Xi: hook up touch ownership handling
    
    Ownership changes don't get processed directly when they happen, instead the
    DIX submits an ownership event which goes through ProcessTouchEvents and
    ProcessTouchOwnershipEvents.
    Then on the required events are generated and sent to clients.
    
    Co-authored-by: Daniel Stone <daniel at fooishbar.org>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index bbca892..f1598f7 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1089,6 +1089,159 @@ DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
 }
 
 /**
+ * If the current owner has rejected the event, deliver the
+ * TouchOwnership/TouchBegin to the next item in the sprite stack.
+ */
+static void
+TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                     TouchOwnershipEvent *ev)
+{
+    InternalEvent *tel = InitEventList(GetMaximumEventsNum());
+    ValuatorMask *mask = valuator_mask_new(2);
+    int i, nev;
+
+    /* Deliver the ownership */
+    if (ti->listeners[0].state == LISTENER_AWAITING_OWNER)
+        DeliverTouchEvents(dev, ti, (InternalEvent*)ev, ti->listeners[0].listener);
+    else if (ti->listeners[0].state == LISTENER_AWAITING_BEGIN)
+        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. */
+    if (ti->num_listeners == 1 && ti->num_grabs == 0 &&
+            ti->pending_finish)
+    {
+        int flags;
+        valuator_mask_set_double(mask, 0,
+                                 valuator_mask_get_double(ti->valuators, 0));
+        valuator_mask_set_double(mask, 1,
+                                 valuator_mask_get_double(ti->valuators, 1));
+
+        flags = TOUCH_CLIENT_ID;
+        if (ti->emulate_pointer)
+            flags |= TOUCH_POINTER_EMULATED;
+        nev = GetTouchEvents(tel, dev, ti->client_id, XI_TouchEnd, flags, mask);
+        for (i = 0; i < nev; i++)
+            DeliverTouchEvents(dev, ti, tel + i, 0);
+        TouchEndTouch(dev, ti);
+    }
+
+    valuator_mask_free(&mask);
+    FreeEventList(tel, GetMaximumEventsNum());
+}
+
+static void
+TouchEventRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
+                   TouchOwnershipEvent *ev)
+{
+    InternalEvent *tel = InitEventList(GetMaximumEventsNum());
+    ValuatorMask *mask = valuator_mask_new(2);
+    Bool was_owner = (ev->resource == ti->listeners[0].listener);
+    void *grab;
+    int nev, i;
+
+
+    /* Send a TouchEnd event to the resource being removed, but only if they
+     * haven't received one yet already */
+    if (ti->listeners[0].state != LISTENER_HAS_END)
+    {
+        int flags;
+        valuator_mask_set_double(mask, 0,
+                                 valuator_mask_get_double(ti->valuators, 0));
+        valuator_mask_set_double(mask, 1,
+                                 valuator_mask_get_double(ti->valuators, 1));
+
+        flags = TOUCH_CLIENT_ID|TOUCH_REJECT;
+        if (ti->emulate_pointer)
+            flags |= TOUCH_POINTER_EMULATED;
+        nev = GetTouchEvents(tel, sourcedev, ti->client_id, XI_TouchEnd, flags, mask);
+        for (i = 0; i < nev; i++)
+            DeliverTouchEvents(sourcedev, ti, tel + i, ev->resource);
+    }
+
+    /* If there are no other listeners left, then don't bother sending an
+     * ownership change event to no-one; if the touchpoint is pending
+     * finish, then we can just kill it now. */
+    if (ti->num_listeners == 1)
+    {
+        if (ti->pending_finish)
+            TouchEndTouch(sourcedev, ti);
+        goto out;
+    }
+
+    /* 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, ev->resource))
+    {
+        if (dixLookupResourceByType(&grab, ev->resource, RT_PASSIVEGRAB,
+                                    serverClient, DixGetAttrAccess) == Success)
+            ti->num_grabs--;
+    }
+
+    /* If the current owner was removed, deliver the TouchOwnership or TouchBegin
+       event to the new owner. */
+    if (was_owner)
+        TouchPuntToNextOwner(sourcedev, ti, ev);
+
+out:
+    FreeEventList(tel, GetMaximumEventsNum());
+    valuator_mask_free(&mask);
+}
+
+/**
+ * Processes a TouchOwnership event, indicating a grab has accepted the touch
+ * it currently owns, or a grab or selection has been removed.  Will generate
+ * and send TouchEnd events to all clients removed from the delivery list, as
+ * well as possibly sending the new TouchOwnership event.  May end the
+ * touchpoint if it is pending finish.
+ */
+static void
+ProcessTouchOwnershipEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                           TouchOwnershipEvent *ev)
+{
+
+    if (ev->reason == XIRejectTouch)
+        TouchEventRejected(dev, ti, ev);
+    else if (ev->reason == XIAcceptTouch) {
+        int flags;
+        int nev, i;
+        ValuatorMask *mask;
+
+        InternalEvent *tel = InitEventList(GetMaximumEventsNum());
+
+        mask = valuator_mask_new(dev->valuator->numAxes);
+        valuator_mask_set_double(mask, 0,
+                                 valuator_mask_get_double(ti->valuators, 0));
+        valuator_mask_set_double(mask, 1,
+                                 valuator_mask_get_double(ti->valuators, 1));
+
+        /* FIXME: what about early acceptance? a client may accept before it
+         * owns the touch. */
+
+        /* The touch owner has accepted the touch.  Send TouchEnd events to
+         * everyone else, and truncate the list of listeners. */
+        flags = TOUCH_ACCEPT|TOUCH_CLIENT_ID;
+        if (ti->emulate_pointer)
+            flags |= TOUCH_POINTER_EMULATED;
+        nev = GetTouchEvents(tel, dev, ti->client_id, XI_TouchEnd,
+                             flags, mask);
+        for (i = 0; i < nev; i++)
+            DeliverTouchEvents(dev, ti, tel + i, 0);
+
+        FreeEventList(tel, GetMaximumEventsNum());
+        valuator_mask_free(&mask);
+
+        while (ti->num_listeners > 1)
+            TouchRemoveListener(ti, ti->listeners[1].listener);
+        /* Owner accepted after receiving end */
+        if (ti->listeners[0].state == LISTENER_HAS_END)
+            TouchEndTouch(dev, ti);
+    } else { /* this is the very first ownership event for a grab */
+        DeliverTouchEvents(dev, ti, (InternalEvent*)ev, ev->resource);
+    }
+}
+
+/**
  * Copy the event's valuator information into the touchpoint, we may need
  * this for emulated TouchEnd events.
  */
@@ -1406,7 +1559,7 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
     /* TouchOwnership events are handled separately from the rest, as they
      * have more complex semantics. */
     if (ev->any.type == ET_TouchOwnership)
-        /* FIXME: process me! */;
+        ProcessTouchOwnershipEvent(dev, ti, &ev->touch_ownership_event);
     else
     {
         TouchCopyValuatorData(&ev->device_event, ti);
commit 1894468c2b9788efa70ef4fb5fc911711402f3a7
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Dec 20 16:33:33 2011 -0800

    Xi: hook up pointer emulation for emulating touches
    
    Includes a hack for implicit grab activation, because integrating this
    requires a larger rewrite and I'm not sleeping enough as it is.
    Right now, we deliver the event and check before/after if there is an
    implicit grab on. If one activated, then store the event in the grab and
    switch the listener type to a grab listener.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index b5fc826..bbca892 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1203,6 +1203,153 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
     return TRUE;
 }
 
+static int
+DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
+                          TouchListener *listener, ClientPtr client,
+                          WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
+{
+    InternalEvent motion, button;
+    InternalEvent *ptrev = &motion;
+    int nevents;
+    DeviceIntPtr kbd;
+
+    /* We don't deliver pointer events to non-owners */
+    if (!TouchResourceIsOwner(ti, listener->listener))
+        return Success;
+
+    nevents = TouchConvertToPointerEvent(ev, &motion, &button);
+    BUG_WARN(nevents == 0);
+    if (nevents == 0)
+        return BadValue;
+
+    if (nevents > 1)
+        ptrev = &button;
+
+    kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
+    event_set_state(dev, kbd, &ptrev->device_event);
+    ptrev->device_event.corestate = event_get_corestate(dev, kbd);
+
+    if (grab)
+    {
+        /* this side-steps the usual activation mechansims, but... */
+        if (ev->any.type == ET_TouchBegin)
+            ActivatePassiveGrab(dev, grab, ptrev, ev); /* also delivers the event */
+        else {
+            int deliveries = 0;
+            /* 'grab' is the passive grab, but if the grab isn't active,
+             * don't deliver */
+            if (!dev->deviceGrab.grab)
+                return Success;
+
+            if (grab->ownerEvents)
+            {
+                WindowPtr focus = NullWindow;
+                WindowPtr win = dev->spriteInfo->sprite->win;
+                deliveries = DeliverDeviceEvents(win, ptrev, grab, focus, dev);
+            }
+
+            if (!deliveries)
+                DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype);
+
+            if (ev->any.type == ET_TouchEnd &&
+                !dev->button->buttonsDown &&
+                dev->deviceGrab.fromPassiveGrab &&
+                GrabIsPointerGrab(grab))
+                (*dev->deviceGrab.DeactivateGrab)(dev);
+        }
+    } else
+    {
+        GrabPtr devgrab = dev->deviceGrab.grab;
+
+        DeliverDeviceEvents(win, ptrev, grab, win, dev);
+        /* FIXME: bad hack
+         * Implicit passive grab activated in response to this event. Store
+         * the event.
+         */
+        if (!devgrab && dev->deviceGrab.grab && dev->deviceGrab.implicitGrab)
+        {
+            TouchListener *listener;
+
+            devgrab = dev->deviceGrab.grab;
+
+            *dev->deviceGrab.sync.event = ev->device_event;
+
+            /* The listener array has a sequence of grabs and then one event
+             * selection. Implicit grab activation occurs through delivering an
+             * event selection. Thus, we update the last listener in the array.
+             */
+            listener = &ti->listeners[ti->num_listeners - 1];
+            listener->listener = devgrab->resource;
+
+            if (devgrab->grabtype != XI2 ||
+                devgrab->type != XI_TouchBegin)
+                listener->type = LISTENER_POINTER_GRAB;
+            else
+                listener->type = LISTENER_GRAB;
+        }
+
+    }
+    if (ev->any.type == ET_TouchBegin)
+        listener->state = LISTENER_IS_OWNER;
+    else if (ev->any.type == ET_TouchEnd)
+        listener->state = LISTENER_HAS_END;
+
+    return Success;
+}
+
+
+
+
+static void
+DeliverEmulatedMotionEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                           InternalEvent *ev)
+{
+    InternalEvent motion;
+
+    if (ti->num_listeners)
+    {
+        ClientPtr client;
+        WindowPtr win;
+        GrabPtr grab;
+        XI2Mask *mask;
+
+        if (ti->listeners[0].type != LISTENER_POINTER_REGULAR ||
+            ti->listeners[0].type != LISTENER_POINTER_GRAB)
+            return;
+
+        motion = *ev;
+        motion.any.type = ET_TouchUpdate;
+        motion.device_event.detail.button = 0;
+
+        if (!RetrieveTouchDeliveryData(dev, ti, &motion,
+                                       &ti->listeners[0], &client, &win, &grab,
+                                       &mask))
+            return;
+
+        /* There may be a pointer grab on the device */
+        if (!grab)
+        {
+            grab = dev->deviceGrab.grab;
+            if (grab)
+            {
+                win = grab->window;
+                mask = grab->xi2mask;
+                client = rClient(grab);
+            }
+        }
+
+        DeliverTouchEmulatedEvent(dev, ti, &motion, &ti->listeners[0], client, win, grab, mask);
+    } else {
+        InternalEvent button;
+        int converted;
+        converted = TouchConvertToPointerEvent(ev, &motion, &button);
+
+        BUG_WARN(converted == 0);
+        if (converted)
+            ProcessOtherEvent(&motion, dev);
+    }
+}
+
 /**
  * Processes and delivers a TouchBegin, TouchUpdate, or a
  * TouchEnd event.
@@ -1241,6 +1388,12 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
         return;
     }
 
+
+    /* if emulate_pointer is set, emulate the motion event right
+     * here, so we can ignore it for button event emulation. TouchUpdate
+     * events which _only_ emulate motion just work normally */
+    if (emulate_pointer && ev->any.type != ET_TouchUpdate)
+        DeliverEmulatedMotionEvent(dev, ti, ev);
     if (emulate_pointer && IsMaster(dev))
         CheckMotion(&ev->device_event, dev);
 
@@ -1436,6 +1589,15 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev
     int rc = Success;
     Bool has_ownershipmask;
 
+    if (listener->type == LISTENER_POINTER_REGULAR ||
+        listener->type == LISTENER_POINTER_GRAB)
+    {
+        rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
+                                       grab, xi2mask);
+        goto out;
+    }
+
+
     has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
 
     if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
@@ -1454,6 +1616,7 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev
     }
     listener->state = state;
 
+out:
     return rc;
 }
 
@@ -1464,6 +1627,14 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
 {
     int rc = Success;
 
+    if (listener->type == LISTENER_POINTER_REGULAR ||
+        listener->type == LISTENER_POINTER_GRAB)
+    {
+        rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
+                                       grab, xi2mask);
+        goto out;
+    }
+
     /* Event in response to reject */
     if (ev->device_event.flags & TOUCH_REJECT)
     {
@@ -1488,6 +1659,7 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
         }
     }
 
+out:
     return rc;
 }
 
@@ -1517,7 +1689,10 @@ DeliverTouchEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
         rc = DeliverTouchBeginEvent(dev, ti, ev, listener, client, win, grab, xi2mask);
     } else if (ev->any.type == ET_TouchUpdate)
     {
-        if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
+        if (listener->type == LISTENER_POINTER_REGULAR ||
+            listener->type == LISTENER_POINTER_GRAB)
+            DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win, grab, xi2mask);
+        else if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
             rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
     } else if (ev->any.type == ET_TouchEnd)
         rc = DeliverTouchEndEvent(dev, ti, ev, listener, client, win, grab, xi2mask);
commit 753c4dca1e42035e29fb21458a746e484ed93ca3
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 17:04:38 2011 +1000

    dix: add touch to pointer event conversion helper
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/touch.c b/dix/touch.c
index 5615f2b..5731d91 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -599,6 +599,68 @@ TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
 }
 
 /**
+ * Copy the touch event into the pointer_event, switching the required
+ * fields to make it a correct pointer event.
+ *
+ * @param event The original touch event
+ * @param[in] motion_event The respective motion event
+ * @param[in] button_event The respective button event (if any)
+ *
+ * @returns The number of converted events.
+ * @retval 0 An error occured
+ * @retval 1 only the motion event is valid
+ * @retval 2 motion and button event are valid
+ */
+int
+TouchConvertToPointerEvent(const InternalEvent *event,
+                           InternalEvent *motion_event,
+                           InternalEvent *button_event)
+{
+    int ptrtype;
+    int nevents = 0;
+
+    BUG_WARN(!event);
+    BUG_WARN(!motion_event);
+
+    switch(event->any.type)
+    {
+        case ET_TouchUpdate:
+            nevents = 1;
+            break;
+        case ET_TouchBegin:
+            nevents = 2; /* motion + press */
+            ptrtype = ET_ButtonPress;
+            break;
+        case ET_TouchEnd:
+            nevents = 2; /* motion + release */
+            ptrtype = ET_ButtonRelease;
+            break;
+        default:
+            BUG_WARN_MSG(1,"Invalid event type %d\n", event->any.type);
+            return 0;
+    }
+
+    BUG_WARN_MSG(!(event->device_event.flags & TOUCH_POINTER_EMULATED),
+                 "Non-emulating touch event\n");
+
+    *motion_event = *event;
+    motion_event->any.type = ET_Motion;
+    motion_event->device_event.detail.button = 0;
+    motion_event->device_event.flags = XIPointerEmulated;
+
+    if (nevents > 1)
+    {
+        BUG_WARN(!button_event);
+        *button_event = *event;
+        button_event->any.type = ptrtype;
+        button_event->device_event.flags = XIPointerEmulated;
+        /* detail is already correct */
+    }
+
+    return nevents;
+}
+
+/**
  * Return the corresponding pointer emulation internal event type for the given
  * touch event or 0 if no such event type exists.
  */
diff --git a/include/input.h b/include/input.h
index 9fec92b..03eb053 100644
--- a/include/input.h
+++ b/include/input.h
@@ -619,6 +619,8 @@ extern void TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, Internal
 extern Bool TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
                               InternalEvent *ev);
 extern Bool TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite);
+extern int TouchConvertToPointerEvent(const InternalEvent *ev,
+                                      InternalEvent *motion, InternalEvent *button);
 extern int TouchGetPointerEventType(const InternalEvent *ev);
 
 /* misc event helpers */
commit c3843f5498a849920ab68cca3557411ad8ab3454
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 17:02:30 2011 +1000

    dix: add real_event parameter to ActivatePassiveGrab
    
    For touch events with pointer emulation, the event that triggers the grab
    (the pointer event) is not the same as the actual event (the touch event).
    For replaying, we need to store the real event then.
    
    No effective changes at this point, for the current caller event and
    real_event are identical.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/events.c b/dix/events.c
index f8ea94f..d8530ef 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -3643,11 +3643,15 @@ BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin)
  * @param device The device of the event to check.
  * @param grab The grab to check.
  * @param event The current device event.
+ * @param real_event The original event, in case of touch emulation. The
+ * real event is the one stored in the sync queue.
  *
  * @return Whether the grab has been activated.
  */
 Bool
-ActivatePassiveGrab(DeviceIntPtr device, GrabPtr grab, InternalEvent *event)
+ActivatePassiveGrab(DeviceIntPtr device, GrabPtr grab, InternalEvent *event,
+                    InternalEvent *real_event)
+
 {
     SpritePtr pSprite = device->spriteInfo->sprite;
     GrabInfoPtr grabinfo = &device->deviceGrab;
@@ -3719,7 +3723,7 @@ ActivatePassiveGrab(DeviceIntPtr device, GrabPtr grab, InternalEvent *event)
 
     if (grabinfo->sync.state == FROZEN_NO_EVENT)
         grabinfo->sync.state = FROZEN_WITH_EVENT;
-    *grabinfo->sync.event = event->device_event;
+    *grabinfo->sync.event = real_event->device_event;
 
     free(xE);
     return TRUE;
@@ -3943,7 +3947,7 @@ CheckPassiveGrabsOnWindow(
         if (!CheckPassiveGrab(device, grab, event, checkCore, tempGrab))
             continue;
 
-        if (activate && !ActivatePassiveGrab(device, grab, event))
+        if (activate && !ActivatePassiveGrab(device, grab, event, event))
             continue;
 
         break;
diff --git a/include/input.h b/include/input.h
index a6bdce0..9fec92b 100644
--- a/include/input.h
+++ b/include/input.h
@@ -634,7 +634,7 @@ void FixUpEventFromWindow(SpritePtr pSprite,
 extern WindowPtr XYToWindow(SpritePtr pSprite, int x, int y);
 extern int EventIsDeliverable(DeviceIntPtr dev, int evtype, WindowPtr win);
 extern Bool ActivatePassiveGrab(DeviceIntPtr dev, GrabPtr grab,
-                                InternalEvent *ev);
+                                InternalEvent *ev, InternalEvent *real_event);
 /**
  * Masks specifying the type of event to deliver for an InternalEvent; used
  * by EventIsDeliverable.
commit e389a19a730055d4550ff708da83c78099a516fd
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Tue Dec 20 16:32:52 2011 -0800

    Process and deliver touch events
    
    Does not include pointer emulation handling.
    Does include partial ownership handling but not the actual processing of
    ownership events.
    
    Note: this commit is a retroactive commit extracted from a series of ~50
    commits and may thus appear a bit more complicated than what you'd write out
    from scratch.
    
    Pointer processing tree is roughly:
    - ProcessOtherEvents
      - ProcessTouchEvents
        - DeliverTouchEvents
          - DeliverTouchBeginEvent|DeliverTouchEndEvent|...
            - DeliverOneTouchEvent
    
    Also hooks up the event history playing to the right function now.
    
    Co-authored-by: Daniel Stone <daniel at fooishbar.org>
    Co-authored-by: Chase Douglas <chase.douglas at canonical.com>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 5cf60f8..b5fc826 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -104,6 +104,7 @@ SOFTWARE.
 #include "eventconvert.h"
 #include "eventstr.h"
 #include "inpututils.h"
+#include "mi.h"
 
 #include <X11/extensions/XKBproto.h>
 #include "xkbsrv.h"
@@ -1013,6 +1014,258 @@ UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event)
     return DEFAULT;
 }
 
+/**
+ * A client that does not have the TouchOwnership mask set may not receive a
+ * TouchBegin event if there is at least one grab active.
+ *
+ * @return TRUE if the client selected for ownership events on the given
+ * window for this device, FALSE otherwise
+ */
+static inline Bool
+TouchClientWantsOwnershipEvents(ClientPtr client, DeviceIntPtr dev, WindowPtr win)
+{
+    InputClients *iclient;
+
+    nt_list_for_each_entry(iclient, wOtherInputMasks(win)->inputClients, next)
+    {
+        if (rClient(iclient) != client)
+            continue;
+
+        return xi2mask_isset(iclient->xi2mask, dev, XI_TouchOwnership);
+    }
+
+    return FALSE;
+}
+
+static void
+TouchSendOwnershipEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, int reason, XID resource)
+{
+    int nev, i;
+    InternalEvent *tel = InitEventList(GetMaximumEventsNum());
+
+    nev = GetTouchOwnershipEvents(tel, dev, ti, reason, resource, 0);
+    for (i = 0; i < nev; i++)
+        mieqProcessDeviceEvent(dev, tel + i, NULL);
+
+    FreeEventList(tel, GetMaximumEventsNum());
+}
+
+/**
+ * Attempts to deliver a touch event to the given client.
+ */
+static Bool
+DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
+                     GrabPtr grab, WindowPtr win, InternalEvent *ev)
+{
+    int err;
+    xEvent *xi2;
+    Mask filter;
+    Window child = DeepestSpriteWin(&ti->sprite)->drawable.id;
+
+    /* FIXME: owner event handling */
+
+    /* If the client does not have the ownership mask set and is not
+     * the current owner of the touch, only pretend we delivered */
+    if (!grab && ti->num_grabs != 0 &&
+           !TouchClientWantsOwnershipEvents(client, dev,win))
+           return TRUE;
+
+    /* If we fail here, we're going to leave a client hanging. */
+    err = EventToXI2(ev, &xi2);
+    if (err != Success)
+        FatalError("[Xi] %s: XI2 conversion failed in %s"
+                   " (%d)\n", dev->name, __func__, err);
+
+    FixUpEventFromWindow(&ti->sprite, xi2, win, child, FALSE);
+    filter = GetEventFilter(dev, xi2);
+    if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) != Success)
+        return FALSE;
+    err = TryClientEvents(client, dev, xi2, 1, filter, filter, NullGrab);
+    free(xi2);
+
+    /* Returning the value from TryClientEvents isn't useful, since all our
+     * resource-gone cleanups will update the delivery list anyway. */
+    return TRUE;
+}
+
+/**
+ * Copy the event's valuator information into the touchpoint, we may need
+ * this for emulated TouchEnd events.
+ */
+static void
+TouchCopyValuatorData(DeviceEvent *ev, TouchPointInfoPtr ti)
+{
+    int i;
+    for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
+        if (BitIsOn(ev->valuators.mask, i))
+            valuator_mask_set_double(ti->valuators, i, ev->valuators.data[i]);
+}
+
+/**
+ * Given a touch event and a potential listener, retrieve info needed for
+ * processing the event.
+ *
+ * @param dev The device generating the touch event.
+ * @param ti The touch point info record for the touch event.
+ * @param ev The touch event to process.
+ * @param listener The touch event listener that may receive the touch event.
+ * @param[out] client The client that should receive the touch event.
+ * @param[out] win The window to deliver the event on.
+ * @param[out] grab The grab to deliver the event through, if any.
+ * @param[out] mask The XI 2.x event mask of the grab or selection, if any.
+ * @return TRUE if an event should be delivered to the listener, FALSE
+ *         otherwise.
+ */
+static Bool
+RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                          InternalEvent *ev, TouchListener *listener,
+                          ClientPtr *client, WindowPtr *win, GrabPtr *grab,
+                          XI2Mask **mask)
+{
+     int rc;
+     InputClients *iclients = NULL;
+
+    if (listener->type == LISTENER_GRAB ||
+        listener->type == LISTENER_POINTER_GRAB)
+    {
+        rc = dixLookupResourceByType((pointer*)grab, listener->listener,
+                RT_PASSIVEGRAB,
+                serverClient, DixSendAccess);
+        if (rc != Success)
+        {
+            /* the grab doesn't exist but we have a grabbing listener - this
+             * is an implicit/active grab */
+            rc = dixLookupClient(client, listener->listener, serverClient, DixSendAccess);
+            if (rc != Success)
+                return FALSE;
+
+            *grab = dev->deviceGrab.grab;
+            if (!*grab)
+                return FALSE;
+        }
+
+        *client = rClient(*grab);
+        *win = (*grab)->window;
+        *mask = (*grab)->xi2mask;
+    } else {
+        if (listener->level == CORE)
+            rc = dixLookupWindow(win, listener->listener,
+                                 serverClient, DixSendAccess);
+        else
+            rc = dixLookupResourceByType((pointer*)win, listener->listener,
+                                         RT_INPUTCLIENT,
+                                         serverClient, DixSendAccess);
+        if (rc != Success)
+            return FALSE;
+
+
+        if (listener->level == XI2)
+        {
+            int evtype;
+            if (ti->emulate_pointer && listener->type == LISTENER_POINTER_REGULAR)
+                evtype = GetXI2Type(TouchGetPointerEventType(ev));
+            else
+                evtype = GetXI2Type(ev->any.type);
+
+            nt_list_for_each_entry(iclients, wOtherInputMasks(*win)->inputClients, next)
+                if (xi2mask_isset(iclients->xi2mask, dev, evtype))
+                    break;
+            BUG_WARN(!iclients);
+            if (!iclients)
+                return FALSE;
+        } else if (listener->level == XI)
+        {
+            int xi_type = GetXIType(TouchGetPointerEventType(ev));
+            Mask xi_filter = event_get_filter_from_type(dev, xi_type);
+            nt_list_for_each_entry(iclients, wOtherInputMasks(*win)->inputClients, next)
+                if (iclients->mask[dev->id] & xi_filter)
+                    break;
+            BUG_WARN(!iclients);
+            if (!iclients)
+                return FALSE;
+        } else
+        {
+            int coretype = GetCoreType(TouchGetPointerEventType(ev));
+            Mask core_filter = event_get_filter_from_type(dev, coretype);
+
+            /* 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 */
+        }
+
+        *client = iclients ? rClient(iclients) : wClient(*win);
+        *mask = iclients ? iclients->xi2mask : NULL;
+        *grab = NULL;
+    }
+
+    return TRUE;
+}
+
+/**
+ * Processes and delivers a TouchBegin, TouchUpdate, or a
+ * TouchEnd event.
+ *
+ * Due to having rather different delivery semantics (see the Xi 2.2 protocol
+ * spec for more information), this implements its own grab and event-selection
+ * delivery logic.
+ */
+static void
+ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
+{
+    TouchClassPtr t = dev->touch;
+    TouchPointInfoPtr ti;
+    uint32_t touchid;
+    int type = ev->any.type;
+    int emulate_pointer = !!(ev->device_event.flags & TOUCH_POINTER_EMULATED);
+
+    if (!t)
+        return;
+
+    if (ev->any.type == ET_TouchOwnership)
+        touchid = ev->touch_ownership_event.touchid;
+    else
+        touchid = ev->device_event.touchid;
+
+    if (type == ET_TouchBegin) {
+        ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
+                             emulate_pointer);
+    } else
+        ti = TouchFindByClientID(dev, touchid);
+
+    if (!ti)
+    {
+        DebugF("[Xi] %s: Failed to get event %d for touchpoint %d\n",
+               dev->name, type, touchid);
+        return;
+    }
+
+    if (emulate_pointer && IsMaster(dev))
+        CheckMotion(&ev->device_event, dev);
+
+    /* Make sure we have a valid window trace for event delivery; must be
+     * called after event type mutation. */
+    /* FIXME: check this */
+    if (!TouchEnsureSprite(dev, ti, ev))
+        return;
+
+    /* TouchOwnership events are handled separately from the rest, as they
+     * have more complex semantics. */
+    if (ev->any.type == ET_TouchOwnership)
+        /* FIXME: process me! */;
+    else
+    {
+        TouchCopyValuatorData(&ev->device_event, ti);
+        /* WARNING: the event type may change to TouchUpdate in
+         * DeliverTouchEvents if a TouchEnd was delivered to a grabbing
+         * owner */
+        DeliverTouchEvents(dev, ti, (InternalEvent *) ev, 0);
+        if (ev->any.type == ET_TouchEnd)
+            TouchEndTouch(dev, ti);
+    }
+}
+
 
 /**
  * Process DeviceEvents and DeviceChangedEvents.
@@ -1162,12 +1415,160 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
         case  ET_RawTouchEnd:
             DeliverRawEvent(&ev->raw_event, device);
             break;
+        case  ET_TouchBegin:
+        case  ET_TouchUpdate:
+        case  ET_TouchOwnership:
+        case  ET_TouchEnd:
+            ProcessTouchEvent(ev, device);
+            break;
         default:
             ProcessDeviceEvent(ev, device);
             break;
     }
 }
 
+static int
+DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
+                       TouchListener *listener, ClientPtr client,
+                       WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
+{
+    enum TouchListenerState state;
+    int rc = Success;
+    Bool has_ownershipmask;
+
+    has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
+
+    if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
+        rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
+    if (!TouchResourceIsOwner(ti, listener->listener))
+    {
+        if (has_ownershipmask)
+            state = LISTENER_AWAITING_OWNER;
+        else
+            state = LISTENER_AWAITING_BEGIN;
+    } else
+    {
+        if (has_ownershipmask)
+            TouchSendOwnershipEvent(dev, ti, 0, listener->listener);
+        state = LISTENER_IS_OWNER;
+    }
+    listener->state = state;
+
+    return rc;
+}
+
+static int
+DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
+                     TouchListener *listener, ClientPtr client,
+                     WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
+{
+    int rc = Success;
+
+    /* Event in response to reject */
+    if (ev->device_event.flags & TOUCH_REJECT)
+    {
+        if (listener->state != LISTENER_HAS_END)
+            rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
+        listener->state = LISTENER_HAS_END;
+    } else if (TouchResourceIsOwner(ti, listener->listener))
+    {
+        /* FIXME: what about early acceptance */
+        if (!(ev->device_event.flags & TOUCH_ACCEPT))
+        {
+            if (listener->state != LISTENER_HAS_END)
+                rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
+            listener->state = LISTENER_HAS_END;
+        }
+        if (ti->num_listeners > 1 &&
+           (ev->device_event.flags & (TOUCH_ACCEPT|TOUCH_REJECT)) == 0)
+        {
+            ev->any.type = ET_TouchUpdate;
+            ev->device_event.flags |= TOUCH_PENDING_END;
+            ti->pending_finish = TRUE;
+        }
+    }
+
+    return rc;
+}
+
+static int
+DeliverTouchEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
+                  TouchListener *listener, ClientPtr client,
+                  WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
+{
+    Bool has_ownershipmask = FALSE;
+    int rc = Success;
+
+    if (xi2mask)
+        has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
+
+    if (ev->any.type == ET_TouchOwnership)
+    {
+        ev->touch_ownership_event.deviceid = dev->id;
+        if (!TouchResourceIsOwner(ti, listener->listener))
+            goto out;
+        rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
+        listener->state = LISTENER_IS_OWNER;
+    } else
+        ev->device_event.deviceid = dev->id;
+
+    if (ev->any.type == ET_TouchBegin)
+    {
+        rc = DeliverTouchBeginEvent(dev, ti, ev, listener, client, win, grab, xi2mask);
+    } else if (ev->any.type == ET_TouchUpdate)
+    {
+        if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
+            rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
+    } else if (ev->any.type == ET_TouchEnd)
+        rc = DeliverTouchEndEvent(dev, ti, ev, listener, client, win, grab, xi2mask);
+
+out:
+    return rc;
+}
+
+/**
+ * Delivers a touch events to all interested clients.  For TouchBegin events,
+ * will update ti->listeners, ti->num_listeners, and ti->num_grabs.
+ * May also mutate ev (type and flags) upon successful delivery.  If
+ * @resource is non-zero, will only attempt delivery to the owner of that
+ * resource.
+ *
+ * @return TRUE if the event was delivered at least once, FALSE otherwise
+ */
+void
+DeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                   InternalEvent *ev, XID resource)
+{
+    int i;
+
+    if (ev->any.type == ET_TouchBegin &&
+        !(ev->device_event.flags & (TOUCH_CLIENT_ID|TOUCH_REPLAYING)))
+        TouchSetupListeners(dev, ti, ev);
+
+    TouchEventHistoryPush(ti, &ev->device_event);
+
+    for (i = 0; i < ti->num_listeners; i++)
+    {
+        GrabPtr grab = NULL;
+        ClientPtr client;
+        WindowPtr win;
+        XI2Mask *mask;
+        TouchListener *listener = &ti->listeners[i];
+
+        if (resource && listener->listener != resource)
+            continue;
+
+        if (!RetrieveTouchDeliveryData(dev, ti, ev, listener, &client, &win,
+                                       &grab, &mask))
+            continue;
+
+        DeliverTouchEvent(dev, ti, ev, listener, client, win, grab, mask);
+    }
+
+    if (ti->emulate_pointer)
+        UpdateDeviceState(dev, &ev->device_event);
+}
+
 int
 InitProximityClassDeviceStruct(DeviceIntPtr dev)
 {
diff --git a/dix/touch.c b/dix/touch.c
index 3e45e35..5615f2b 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -496,7 +496,8 @@ TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
         flags |= TOUCH_POINTER_EMULATED;
     /* send fake begin event to next owner */
     nev = GetTouchEvents(tel, dev, ti->client_id, XI_TouchBegin, flags, mask);
-    /* FIXME: deliver the event */
+    for (i = 0; i < nev; i++)
+        DeliverTouchEvents(dev, ti, tel + i, resource);
 
     valuator_mask_free(&mask);
     FreeEventList(tel, GetMaximumEventsNum());
@@ -506,7 +507,7 @@ TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
     {
         DeviceEvent *ev = &ti->history[i];
         ev->flags |= TOUCH_REPLAYING;
-        /* FIXME: deliver the event */
+        DeliverTouchEvents(dev, ti, (InternalEvent*)ev, resource);
     }
 }
 
diff --git a/include/dix.h b/include/dix.h
index 7043201..4f21b41 100644
--- a/include/dix.h
+++ b/include/dix.h
@@ -405,6 +405,12 @@ extern int DeliverOneGrabbedEvent(
     DeviceIntPtr /* dev */,
     enum InputLevel /* level */);
 
+extern void DeliverTouchEvents(
+    DeviceIntPtr /* dev */,
+    TouchPointInfoPtr /* ti */,
+    InternalEvent* /* ev */,
+    XID /* resource */);
+
 extern void InitializeSprite(
     DeviceIntPtr /* pDev */,
     WindowPtr    /* pWin */);
commit 634b0da9a83076d0e9e0fc44dc5dc77b0c368bc1
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 15 07:53:19 2011 +1000

    dix: set core and button state based on the touch state
    
    If a pointer-emulating touch caused a button to be logically down, set that
    state in the input events.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/inpututils.c b/dix/inpututils.c
index 8cd4d59..50a122f 100644
--- a/dix/inpututils.c
+++ b/dix/inpututils.c
@@ -663,6 +663,8 @@ int event_get_corestate(DeviceIntPtr mouse, DeviceIntPtr kbd)
     /* core state needs to be assembled BEFORE the device is updated. */
     corestate = (kbd && kbd->key) ? XkbStateFieldFromRec(&kbd->key->xkbInfo->state) : 0;
     corestate |= (mouse && mouse->button) ? (mouse->button->state) : 0;
+    corestate |= (mouse && mouse->touch) ? (mouse->touch->state) : 0;
+
     return corestate;
 }
 
@@ -674,6 +676,9 @@ void event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd, DeviceEvent *event)
         if (BitIsOn(mouse->button->down, i))
             SetBit(event->buttons, i);
 
+    if (mouse && mouse->touch && mouse->touch->buttonsDown > 0)
+        SetBit(event->buttons, mouse->button->map[1]);
+
     if (kbd && kbd->key)
     {
         XkbStatePtr state;
commit dbfd7b37a0ba21899d8ebb7e0b324301bd466c49
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 16:33:05 2011 +1000

    Xi: make UpdateDeviceState aware of touch events
    
    Update the logical button state for pointer-emulating events. Button state
    must be kept separate from the ButtonClassRec to avoid clearing the button
    state on a touch end if there is a physical button still down.
    
    And obviously don't change the button state if we're currently replaying the
    event history for some client.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index b18157d..5cf60f8 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -849,6 +849,7 @@ UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event)
     KeyClassPtr k       = NULL;
     ButtonClassPtr b    = NULL;
     ValuatorClassPtr v  = NULL;
+    TouchClassPtr t     = NULL;
 
     /* This event is always the first we get, before the actual events with
      * the data. However, the way how the DDX is set up, "device" will
@@ -866,6 +867,9 @@ UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event)
         case ET_KeyRelease:
         case ET_ProximityIn:
         case ET_ProximityOut:
+        case ET_TouchBegin:
+        case ET_TouchUpdate:
+        case ET_TouchEnd:
             break;
         default:
             /* other events don't update the device */
@@ -875,6 +879,7 @@ UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event)
     k = device->key;
     v = device->valuator;
     b = device->button;
+    t = device->touch;
 
     key = event->detail.key;
 
@@ -976,6 +981,34 @@ UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event)
 	device->proximity->in_proximity = TRUE;
     else if (event->type == ET_ProximityOut)
 	device->proximity->in_proximity = FALSE;
+    else if (event->type == ET_TouchBegin) {
+        BUG_WARN(!b || !v);
+        BUG_WARN(!t);
+
+        if (!b || !t || !b->map[key])
+            return DONT_PROCESS;
+
+        if (!(event->flags & TOUCH_POINTER_EMULATED) ||
+            (event->flags & TOUCH_REPLAYING))
+            return DONT_PROCESS;
+
+        IncreaseButtonCount(device, key, &t->buttonsDown, &t->motionMask, &t->state);
+        UpdateDeviceMotionMask(device, t->state, DeviceButtonMotionMask);
+    } else if (event->type == ET_TouchEnd) {
+        BUG_WARN(!b || !v);
+        BUG_WARN(!t);
+
+        if (!b || !t || t->buttonsDown <= 0 || !b->map[key])
+            return DONT_PROCESS;
+
+        if (!(event->flags & TOUCH_POINTER_EMULATED))
+            return DONT_PROCESS;
+        if (!(event->flags & TOUCH_END))
+            return DONT_PROCESS;
+
+        DecreaseButtonCount(device, key, &t->buttonsDown, &t->motionMask, &t->state);
+        UpdateDeviceMotionMask(device, t->state, DeviceButtonMotionMask);
+    }
 
     return DEFAULT;
 }
commit 593c3e2eb3da5c5fb957b68c8025dfdbe1139639
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 16:30:05 2011 +1000

    dix: add TouchResourceIsOwner helper function
    
    The first listener in the sequence is the owner of the touch sequence.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/touch.c b/dix/touch.c
index 7207fd6..3e45e35 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -619,6 +619,16 @@ TouchGetPointerEventType(const InternalEvent *event)
 
 
 /**
+ * @returns TRUE if the specified grab or selection is the current owner of
+ * the touch sequence.
+ */
+Bool
+TouchResourceIsOwner(TouchPointInfoPtr ti, XID resource)
+{
+    return (ti->listeners[0].listener == resource);
+}
+
+/**
  * Add the resource to this touch's listeners.
  */
 void
diff --git a/include/input.h b/include/input.h
index a6de824..a6bdce0 100644
--- a/include/input.h
+++ b/include/input.h
@@ -611,6 +611,7 @@ extern Bool TouchEventHistoryAllocate(TouchPointInfoPtr ti);
 extern void TouchEventHistoryFree(TouchPointInfoPtr ti);
 extern void TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev);
 extern void TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource);
+extern Bool TouchResourceIsOwner(TouchPointInfoPtr ti, XID resource);
 extern void TouchAddListener(TouchPointInfoPtr ti, XID resource, enum InputLevel level,
                                      enum TouchListenerType type, enum TouchListenerState state);
 extern Bool TouchRemoveListener(TouchPointInfoPtr ti, XID resource);
commit 5d0260cc986e8c1f0907870b851d47fd73bb1b7d
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 16:24:17 2011 +1000

    dix: add helper functions for adding/removing touch listeners
    
    The DIX will call TouchSetupListeners once for a new touch. After that
    the listener list remains static, with listeners only dropping out when they
    either reject the grab or disappear.
    
    Exception: if grabs activate they are prefixed to the listeners.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/touch.c b/dix/touch.c
index 2647ca4..7207fd6 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -34,6 +34,9 @@
 
 #include "eventstr.h"
 #include "exevents.h"
+#include "inpututils.h"
+#include "eventconvert.h"
+#include "windowstr.h"
 
 #define TOUCH_HISTORY_SIZE 100
 
@@ -614,3 +617,223 @@ TouchGetPointerEventType(const InternalEvent *event)
     return type;
 }
 
+
+/**
+ * Add the resource to this touch's listeners.
+ */
+void
+TouchAddListener(TouchPointInfoPtr ti, XID resource, enum InputLevel level,
+                 enum TouchListenerType type, enum TouchListenerState state)
+{
+    ti->listeners[ti->num_listeners].listener = resource;
+    ti->listeners[ti->num_listeners].level = level;
+    ti->listeners[ti->num_listeners].state = state;
+    ti->listeners[ti->num_listeners].type = type;
+    ti->num_listeners++;
+}
+
+/**
+ * Remove the resource from this touch's listeners.
+ *
+ * @return TRUE if the resource was removed, FALSE if the resource was not
+ * in the list
+ */
+Bool
+TouchRemoveListener(TouchPointInfoPtr ti, XID resource)
+{
+    int i;
+    for (i = 0; i < ti->num_listeners; i++)
+    {
+        if (ti->listeners[i].listener == resource)
+        {
+            int j;
+            for (j = i; j< ti->num_listeners - 1; j++)
+                ti->listeners[j] = ti->listeners[j + 1];
+            ti->num_listeners--;
+            ti->listeners[ti->num_listeners].listener = 0;
+            ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static void
+TouchAddGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                     InternalEvent *ev, GrabPtr grab)
+{
+    enum TouchListenerType type = LISTENER_GRAB;
+
+    /* FIXME: owner_events */
+
+    if (grab->grabtype == XI2)
+    {
+        if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchOwnership))
+            TouchEventHistoryAllocate(ti);
+        if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin))
+            type = LISTENER_POINTER_GRAB;
+    } else if (grab->grabtype == XI || grab->grabtype == CORE)
+    {
+        TouchEventHistoryAllocate(ti);
+        type = LISTENER_POINTER_GRAB;
+    }
+
+    TouchAddListener(ti, grab->resource, grab->grabtype,
+                     type, LISTENER_AWAITING_BEGIN);
+    ti->num_grabs++;
+}
+
+/**
+ * Add one listener if there is a grab on the given window.
+ */
+static void
+TouchAddPassiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                            WindowPtr win, InternalEvent *ev)
+{
+    GrabPtr grab;
+    Bool check_core = IsMaster(dev) && ti->emulate_pointer;
+
+    /* FIXME: make CheckPassiveGrabsOnWindow only trigger on TouchBegin */
+    grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core, FALSE);
+    if (!grab)
+        return;
+
+    TouchAddGrabListener(dev, ti, ev, grab);
+}
+
+static Bool
+TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                        WindowPtr win, InternalEvent *ev)
+{
+    InputClients *iclients = NULL;
+    OtherInputMasks *inputMasks = NULL;
+    uint16_t evtype = 0; /* may be event type or emulated event type */
+    enum TouchListenerType type = LISTENER_REGULAR;
+    int mask;
+
+    evtype = GetXI2Type(ev->any.type);
+    mask = EventIsDeliverable(dev, ev->any.type, win);
+    if (!mask && !ti->emulate_pointer)
+        return FALSE;
+    else if (!mask)/* now try for pointer event */
+    {
+        mask = EventIsDeliverable(dev, TouchGetPointerEventType(ev), win);
+        if (mask)
+        {
+            evtype = GetXI2Type(TouchGetPointerEventType(ev));
+            type = LISTENER_POINTER_REGULAR;
+        }
+    }
+    if (!mask)
+        return FALSE;
+
+    inputMasks = wOtherInputMasks(win);
+
+    if (mask & EVENT_XI2_MASK)
+    {
+        nt_list_for_each_entry(iclients, inputMasks->inputClients, next)
+        {
+            if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
+                continue;
+
+            if (!xi2mask_isset(iclients->xi2mask, dev, XI_TouchOwnership))
+                TouchEventHistoryAllocate(ti);
+
+            TouchAddListener(ti, iclients->resource, XI2,
+                             type, LISTENER_AWAITING_BEGIN);
+            return TRUE;
+        }
+    }
+
+    if (mask & EVENT_XI1_MASK)
+    {
+        int xitype = GetXIType(TouchGetPointerEventType(ev));
+        Mask xi_filter = event_get_filter_from_type(dev, xitype);
+        nt_list_for_each_entry(iclients, inputMasks->inputClients, next)
+        {
+            if (!(iclients->mask[dev->id] & xi_filter))
+                continue;
+
+            TouchEventHistoryAllocate(ti);
+            TouchAddListener(ti, iclients->resource, XI,
+                             LISTENER_POINTER_REGULAR, LISTENER_AWAITING_BEGIN);
+            return TRUE;
+        }
+    }
+
+    if (mask & EVENT_CORE_MASK)
+    {
+        int coretype = GetCoreType(TouchGetPointerEventType(ev));
+        Mask core_filter = event_get_filter_from_type(dev, coretype);
+
+        /* window owner */
+        if (IsMaster(dev) && (win->eventMask & core_filter))
+        {
+            TouchEventHistoryAllocate(ti);
+            TouchAddListener(ti, win->drawable.id, CORE,
+                             LISTENER_POINTER_REGULAR, LISTENER_AWAITING_BEGIN);
+            return TRUE;
+        }
+
+        /* all others */
+        nt_list_for_each_entry(iclients, (InputClients*)wOtherClients(win), next)
+        {
+            if (!(iclients->mask[XIAllDevices] & core_filter))
+                continue;
+
+            TouchEventHistoryAllocate(ti);
+            TouchAddListener(ti, iclients->resource, CORE,
+                             type, LISTENER_AWAITING_BEGIN);
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+static void
+TouchAddActiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
+                           InternalEvent *ev, GrabPtr grab)
+{
+    if (!ti->emulate_pointer &&
+        (grab->grabtype == CORE || grab->grabtype == XI))
+        return;
+
+    if (!ti->emulate_pointer &&
+        grab->grabtype == XI2 &&
+        (grab->type != XI_TouchBegin && grab->type != XI_TouchEnd && grab->type != XI_TouchUpdate))
+        return;
+
+    TouchAddGrabListener(dev, ti, ev, grab);
+}
+
+void
+TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
+{
+    int i;
+    SpritePtr sprite = &ti->sprite;
+    WindowPtr win;
+
+    if (dev->deviceGrab.grab)
+        TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab);
+
+    /* First, find all grabbing clients from the root window down
+     * to the deepest child window. */
+    for (i = 0; i < sprite->spriteTraceGood; i++)
+    {
+        win = sprite->spriteTrace[i];
+        TouchAddPassiveGrabListener(dev, ti, win, ev);
+    }
+
+    /* Find the first client with an applicable event selection,
+     * going from deepest child window back up to the root window. */
+    for (i = sprite->spriteTraceGood - 1; i >= 0; i--)
+    {
+        Bool delivered;
+
+        win = sprite->spriteTrace[i];
+        delivered = TouchAddRegularListener(dev, ti, win, ev);
+        if (delivered)
+            return;
+    }
+}
diff --git a/include/input.h b/include/input.h
index 84d1d43..a6de824 100644
--- a/include/input.h
+++ b/include/input.h
@@ -611,7 +611,10 @@ extern Bool TouchEventHistoryAllocate(TouchPointInfoPtr ti);
 extern void TouchEventHistoryFree(TouchPointInfoPtr ti);
 extern void TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev);
 extern void TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource);
-
+extern void TouchAddListener(TouchPointInfoPtr ti, XID resource, enum InputLevel level,
+                                     enum TouchListenerType type, enum TouchListenerState state);
+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 TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite);
commit 6a68f97ce6704dd2ff2a50f91acd2da72c9995bd
Author: Chase Douglas <chase.douglas at canonical.com>
Date:   Wed Dec 14 16:26:04 2011 +1000

    dix: add TouchGetPointerEventType helper function
    
    Returns the respective pointer event type for a given touch event type.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/touch.c b/dix/touch.c
index 0f2c0c3..2647ca4 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -593,3 +593,24 @@ TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
 
     return TRUE;
 }
+
+/**
+ * Return the corresponding pointer emulation internal event type for the given
+ * touch event or 0 if no such event type exists.
+ */
+int
+TouchGetPointerEventType(const InternalEvent *event)
+{
+    int type = 0;
+
+    switch(event->any.type)
+    {
+        case ET_TouchBegin:  type = ET_ButtonPress;   break;
+        case ET_TouchUpdate: type = ET_Motion;        break;
+        case ET_TouchEnd:    type = ET_ButtonRelease; break;
+        default:
+            break;
+    }
+    return type;
+}
+
diff --git a/include/input.h b/include/input.h
index f1615cf..84d1d43 100644
--- a/include/input.h
+++ b/include/input.h
@@ -615,6 +615,7 @@ extern void TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID
 extern Bool TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
                               InternalEvent *ev);
 extern Bool TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite);
+extern int TouchGetPointerEventType(const InternalEvent *ev);
 
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients);
commit 8e58ce73c8b79cb86e890369d0216cdd850c52a5
Author: Daniel Stone <daniel at fooishbar.org>
Date:   Wed Dec 14 16:53:04 2011 +1000

    dix: when a window disappears, remove it from the touch sprite trace
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index ffb48d1..b18157d 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1866,6 +1866,36 @@ InputClientGone(WindowPtr pWin, XID id)
     FatalError("client not on device event list");
 }
 
+/**
+ * Search for window in each touch trace for each device. Remove the window
+ * and all its subwindows from the trace when found. The initial window
+ * order is preserved.
+ */
+void WindowGone(WindowPtr win)
+{
+    DeviceIntPtr dev;
+
+    for (dev = inputInfo.devices; dev; dev = dev->next) {
+        TouchClassPtr t = dev->touch;
+        int i;
+
+        if (!t)
+            continue;
+
+        for (i = 0; i < t->num_touches; i++) {
+            SpritePtr sprite = &t->touches[i].sprite;
+            int j;
+
+            for (j = 0; j < sprite->spriteTraceGood; j++) {
+                if (sprite->spriteTrace[j] == win) {
+                    sprite->spriteTraceGood = j;
+                    break;
+                }
+            }
+        }
+    }
+}
+
 int
 SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate,
 	  xEvent * ev, Mask mask, int count)
diff --git a/dix/window.c b/dix/window.c
index 1953f02..823294b 100644
--- a/dix/window.c
+++ b/dix/window.c
@@ -131,6 +131,7 @@ Equipment Corporation.
 
 #include "privates.h"
 #include "xace.h"
+#include "exevents.h"
 
 #include <X11/Xatom.h> /* must come after server includes */
 
@@ -2971,8 +2972,10 @@ UnmapWindow(WindowPtr pWin, Bool fromConfigure)
 	if (!fromConfigure && pScreen->PostValidateTree)
 	    (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap);
     }
-    if (wasRealized && !fromConfigure)
+    if (wasRealized && !fromConfigure) {
 	WindowsRestructured ();
+	WindowGone(pWin);
+    }
     return Success;
 }
 
@@ -3055,8 +3058,10 @@ UnmapSubwindows(WindowPtr pWin)
 	if (anyMarked && pScreen->PostValidateTree)
 	    (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap);
     }
-    if (wasRealized)
+    if (wasRealized) {
 	WindowsRestructured ();
+	WindowGone(pWin);
+    }
 }
 
 
diff --git a/include/exevents.h b/include/exevents.h
index 0ab04f5..0186f53 100644
--- a/include/exevents.h
+++ b/include/exevents.h
@@ -245,6 +245,10 @@ InputClientGone(
 	WindowPtr              /* pWin */,
 	XID                    /* id */);
 
+extern void
+WindowGone(
+	WindowPtr              /* win */);
+
 extern int
 SendEvent (
 	ClientPtr              /* client */,
commit c18a173cf5f53778356c5e8f25ab132956f8c27d
Author: Daniel Stone <daniel at fooishbar.org>
Date:   Wed Dec 14 16:03:01 2011 +1000

    dix: add helper functions to build up/verify the sprite trace
    
    Touch events' sprite trace stays the same for the duration of the touch
    sequence.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/touch.c b/dix/touch.c
index 792ebcd..0f2c0c3 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -506,3 +506,90 @@ TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
         /* FIXME: deliver the event */
     }
 }
+
+Bool
+TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite)
+{
+    int i;
+    TouchClassPtr t = dev->touch;
+    WindowPtr *trace;
+    SpritePtr srcsprite;
+
+    /* All touches should have the same sprite trace, so find and reuse an
+     * existing touch's sprite if possible, else use the device's sprite. */
+    for (i = 0; i < t->num_touches; i++)
+        if (t->touches[i].sprite.spriteTraceGood > 0)
+            break;
+    if (i < t->num_touches)
+        srcsprite = &t->touches[i].sprite;
+    else if (dev->spriteInfo->sprite)
+        srcsprite = dev->spriteInfo->sprite;
+    else
+        return FALSE;
+
+    if (srcsprite->spriteTraceGood > sprite->spriteTraceSize)
+    {
+        trace = realloc(sprite->spriteTrace,
+                srcsprite->spriteTraceSize * sizeof(*trace));
+        if (!trace)
+        {
+            sprite->spriteTraceGood = 0;
+            return FALSE;
+        }
+        sprite->spriteTrace = trace;
+        sprite->spriteTraceSize = srcsprite->spriteTraceGood;
+    }
+    memcpy(sprite->spriteTrace, srcsprite->spriteTrace,
+            srcsprite->spriteTraceGood * sizeof(*trace));
+    sprite->spriteTraceGood = srcsprite->spriteTraceGood;
+
+    return TRUE;
+}
+
+/**
+ * Ensure a window trace is present in ti->sprite, constructing one for
+ * TouchBegin events.
+ */
+Bool
+TouchEnsureSprite(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? */
+        sprite->spriteTrace[0] =
+            sourcedev->spriteInfo->sprite->hotPhys.pScreen->root;
+        XYToWindow(sprite, ev->device_event.root_x, ev->device_event.root_y);
+    }
+    else if (!TouchBuildDependentSpriteTrace(sourcedev, sprite))
+        return FALSE;
+
+    if (sprite->spriteTraceGood <= 0)
+        return FALSE;
+
+    /* Mark which grabs/event selections we're delivering to: max one grab per
+     * window plus the bottom-most event selection. */
+    ti->listeners = calloc(sprite->spriteTraceGood + 1, sizeof(*ti->listeners));
+    if (!ti->listeners)
+    {
+        sprite->spriteTraceGood = 0;
+        return FALSE;
+    }
+    ti->num_listeners = 0;
+
+    return TRUE;
+}
diff --git a/include/input.h b/include/input.h
index 8ce5f2b..f1615cf 100644
--- a/include/input.h
+++ b/include/input.h
@@ -612,6 +612,10 @@ extern void TouchEventHistoryFree(TouchPointInfoPtr ti);
 extern void TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev);
 extern void TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource);
 
+extern Bool TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
+                              InternalEvent *ev);
+extern Bool TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite);
+
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients);
 extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event);
commit 40475261eacabb79a824db1138407a9d0f9fe37f
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 15:56:05 2011 +1000

    dix: add touch event history helper functions
    
    If touch client has not registered for ownership events and a grab above
    that client is rejected, the client needs to receive the complete event
    history.
    
    The history currently doesn't really do fancy overflow handling. We assume
    that the first TOUCH_HISTORY_SIZE events are the important ones and anything
    after that is dropped. If that is a problem, fix the client that takes > 100
    event to decide whether to accept or reject.
    
    Events marked with TOUCH_CLIENT_ID or TOUCH_REPLAYING must not be stored in
    the history, they are events created by the DIX to comply with the protocol.
    Any such event should already be in the history anyway.
    
    A fixme in this patch: we don't have a function to actually deliver the
    event yet.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/touch.c b/dix/touch.c
index dfb7ff0..792ebcd 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -35,6 +35,9 @@
 #include "eventstr.h"
 #include "exevents.h"
 
+#define TOUCH_HISTORY_SIZE 100
+
+
 /* If a touch queue resize is needed, the device id's bit is set. */
 static unsigned char resize_waiting[(MAXDEVICES + 7)/8];
 
@@ -394,6 +397,112 @@ TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
     ti->num_grabs = 0;
     ti->client_id = 0;
 
+    TouchEventHistoryFree(ti);
+
     valuator_mask_zero(ti->valuators);
 }
 
+/**
+ * Allocate the event history for this touch pointer. Calling this on a
+ * touchpoint that already has an event history does nothing but counts as
+ * as success.
+ *
+ * @return TRUE on success, FALSE on allocation errors
+ */
+Bool
+TouchEventHistoryAllocate(TouchPointInfoPtr ti)
+{
+    if (ti->history)
+        return TRUE;
+
+    ti->history = calloc(TOUCH_HISTORY_SIZE, sizeof(*ti->history));
+    ti->history_elements = 0;
+    if (ti->history)
+        ti->history_size = TOUCH_HISTORY_SIZE;
+    return ti->history != NULL;
+}
+
+void
+TouchEventHistoryFree(TouchPointInfoPtr ti)
+{
+    free(ti->history);
+    ti->history = NULL;
+    ti->history_size = 0;
+    ti->history_elements = 0;
+}
+
+/**
+ * Store the given event on the event history (if one exists)
+ * A touch event history consists of one TouchBegin and several TouchUpdate
+ * events (if applicable) but no TouchEnd event.
+ * If more than one TouchBegin is pushed onto the stack, the push is
+ * ignored, calling this function multiple times for the TouchBegin is
+ * valid.
+ */
+void
+TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev)
+{
+    if (!ti->history)
+        return;
+
+    switch(ev->type)
+    {
+        case ET_TouchBegin:
+            /* don't store the same touchbegin twice */
+            if (ti->history_elements > 0)
+                return;
+            break;
+        case ET_TouchUpdate:
+            break;
+        case ET_TouchEnd:
+            return; /* no TouchEnd events in the history */
+        default:
+            return;
+    }
+
+    /* We only store real events in the history */
+    if (ev->flags & (TOUCH_CLIENT_ID|TOUCH_REPLAYING))
+        return;
+
+    ti->history[ti->history_elements++] = *ev;
+    /* FIXME: proper overflow fixes */
+    if (ti->history_elements > ti->history_size - 1)
+    {
+        ti->history_elements = ti->history_size - 1;
+        DebugF("source device %d: history size %d overflowing for touch %u\n",
+                ti->sourceid, ti->history_size, ti->client_id);
+    }
+}
+
+void
+TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
+{
+    InternalEvent *tel = InitEventList(GetMaximumEventsNum());
+    ValuatorMask *mask = valuator_mask_new(0);
+    int i, nev;
+    int flags;
+
+    if (!ti->history)
+        return;
+
+    valuator_mask_set_double(mask, 0, ti->history[0].valuators.data[0]);
+    valuator_mask_set_double(mask, 1, ti->history[0].valuators.data[1]);
+
+    flags = TOUCH_CLIENT_ID|TOUCH_REPLAYING;
+    if (ti->emulate_pointer)
+        flags |= TOUCH_POINTER_EMULATED;
+    /* send fake begin event to next owner */
+    nev = GetTouchEvents(tel, dev, ti->client_id, XI_TouchBegin, flags, mask);
+    /* FIXME: deliver the event */
+
+    valuator_mask_free(&mask);
+    FreeEventList(tel, GetMaximumEventsNum());
+
+    /* First event was TouchBegin, already replayed that one */
+    for (i = 1; i < ti->history_elements; i++)
+    {
+        DeviceEvent *ev = &ti->history[i];
+        ev->flags |= TOUCH_REPLAYING;
+        /* FIXME: deliver the event */
+    }
+}
diff --git a/include/input.h b/include/input.h
index 4d60792..8ce5f2b 100644
--- a/include/input.h
+++ b/include/input.h
@@ -607,6 +607,10 @@ extern TouchPointInfoPtr TouchBeginTouch(DeviceIntPtr dev, int sourceid,
 extern TouchPointInfoPtr TouchFindByClientID(DeviceIntPtr dev,
                                              uint32_t client_id);
 extern void TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti);
+extern Bool TouchEventHistoryAllocate(TouchPointInfoPtr ti);
+extern void TouchEventHistoryFree(TouchPointInfoPtr ti);
+extern void TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev);
+extern void TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource);
 
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients);
commit b274c472a5ad700aea5fe651d677e8cb34ffc976
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Oct 26 09:08:17 2011 +1000

    Support XI 2.2 officially
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index 832bcf7..479ac2f 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -127,7 +127,7 @@
 
 /* X Input */
 #define SERVER_XI_MAJOR_VERSION			2
-#define SERVER_XI_MINOR_VERSION			1
+#define SERVER_XI_MINOR_VERSION			2
 
 /* XKB */
 #define SERVER_XKB_MAJOR_VERSION		1
commit d2af968cb65873780a6e61342d5d3c23b9654e2a
Author: Daniel Stone <daniel at fooishbar.org>
Date:   Wed Dec 14 15:45:19 2011 +1000

    Xi: allow selecting for touch events
    
    Selecting for any of XI_TouchBegin/Update/End/Ownership requires the three
    bits for begin/update/end to be set.
    
    Only one client at a time may select for XI_TouchBegin event
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/xiselectev.c b/Xi/xiselectev.c
index 815a34f..1b6c47a 100644
--- a/Xi/xiselectev.c
+++ b/Xi/xiselectev.c
@@ -155,6 +155,49 @@ ProcXISelectEvents(ClientPtr client)
             }
         }
 
+        if (evmask->mask_len >= 1)
+        {
+            unsigned char *bits = (unsigned char*)&evmask[1];
+
+            /* All three touch events must be selected at once */
+            if ((BitIsOn(bits, XI_TouchBegin) ||
+                 BitIsOn(bits, XI_TouchUpdate) ||
+                 BitIsOn(bits, XI_TouchOwnership) ||
+                 BitIsOn(bits, XI_TouchEnd)) &&
+                (!BitIsOn(bits, XI_TouchBegin) ||
+                 !BitIsOn(bits, XI_TouchUpdate) ||
+                 !BitIsOn(bits, XI_TouchEnd)))
+            {
+                client->errorValue = XI_TouchBegin;
+                return BadValue;
+            }
+
+            /* Only one client per window may select for touch events on the
+             * same devices, including master devices.
+             * XXX: This breaks if a device goes from floating to attached. */
+            if (BitIsOn(bits, XI_TouchBegin))
+            {
+                OtherInputMasks *inputMasks = wOtherInputMasks(win);
+                InputClients *iclient = NULL;
+                if (inputMasks)
+                    iclient = inputMasks->inputClients;
+                for (; iclient; iclient = iclient->next)
+                {
+                    DeviceIntPtr dummy;
+
+                    if (CLIENT_ID(iclient->resource) == client->index)
+                        continue;
+
+                    dixLookupDevice(&dummy, evmask->deviceid, serverClient, DixReadAccess);
+                    if (!dummy)
+                        return BadImplementation; /* this shouldn't happen */
+
+                    if (xi2mask_isset(iclient->xi2mask, dummy, XI_TouchBegin))
+                        return BadAccess;
+                }
+            }
+        }
+
         if (XICheckInvalidMaskBits(client, (unsigned char*)&evmask[1],
                                    evmask->mask_len * 4) != Success)
             return BadValue;
commit f3df3ad668fcd417ffb5afa3bea79a73a348bc1a
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 16:45:04 2011 +1000

    dix: handle DIX-submitted touch events
    
    The DIX needs to submit touch events for e.g. TouchEnd after an
    acceptance/rejection. These have the TOUCH_CLIENT_ID flag set.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/getevents.c b/dix/getevents.c
index 68167af..b60ddc0 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -1732,7 +1732,10 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
     int i;
     int num_events = 0;
     RawDeviceEvent *raw;
-    DDXTouchPointInfoPtr ti;
+    union touch {
+        TouchPointInfoPtr dix_ti;
+        DDXTouchPointInfoPtr ti;
+    } touchpoint;
     int need_rawevent = TRUE;
     Bool emulate_pointer = FALSE;
 
@@ -1740,15 +1743,39 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
         return 0;
 
     /* Find and/or create the DDX touch info */
-    ti = TouchFindByDDXID(dev, ddx_touchid, (type == XI_TouchBegin));
-    if (!ti)
+
+    if (flags & TOUCH_CLIENT_ID) /* A DIX-submitted TouchEnd */
     {
-        ErrorF("[dix] %s: unable to %s touch point %x\n", dev->name,
-                type == XI_TouchBegin ? "begin" : "find", ddx_touchid);
-        return 0;
+        touchpoint.dix_ti = TouchFindByClientID(dev, ddx_touchid);
+        BUG_WARN(!touchpoint.dix_ti);
+
+        if (!touchpoint.dix_ti)
+            return 0;
+
+        if (!mask_in ||
+            !valuator_mask_isset(mask_in, 0) ||
+            !valuator_mask_isset(mask_in, 1))
+        {
+            ErrorF("[dix] dix-submitted events must have x/y valuator information.\n");
+            return 0;
+        }
+
+        need_rawevent = FALSE;
+    } else /* a DDX-submitted touch */
+    {
+        touchpoint.ti = TouchFindByDDXID(dev, ddx_touchid, (type == XI_TouchBegin));
+        if (!touchpoint.ti)
+        {
+            ErrorF("[dix] %s: unable to %s touch point %x\n", dev->name,
+                    type == XI_TouchBegin ? "begin" : "find", ddx_touchid);
+            return 0;
+        }
     }
 
-    emulate_pointer =  ti->emulate_pointer;
+    if (!(flags & TOUCH_CLIENT_ID))
+        emulate_pointer =  touchpoint.ti->emulate_pointer;
+    else
+        emulate_pointer = !!(flags & TOUCH_POINTER_EMULATED);
 
     if (!IsMaster(dev))
         events = UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT, &num_events);
@@ -1760,7 +1787,7 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
         raw = &events->raw_event;
         events++;
         num_events++;
-        init_raw(dev, raw, ms, type, ti->client_id);
+        init_raw(dev, raw, ms, type, touchpoint.ti->client_id);
         set_raw_valuators(raw, &mask, raw->valuators.data_raw);
     }
 
@@ -1768,6 +1795,12 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
     num_events++;
 
     init_event(dev, event, ms);
+    /* if submitted for master device, get the sourceid from there */
+    if (flags & TOUCH_CLIENT_ID)
+    {
+        event->sourceid = touchpoint.dix_ti->sourceid;
+        /* TOUCH_CLIENT_ID implies norawevent */
+    }
 
     switch (type) {
     case XI_TouchBegin:
@@ -1794,17 +1827,19 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
         event->type = ET_TouchEnd;
         /* We can end the DDX touch here, since we don't use the active
          * field below */
-        TouchEndDDXTouch(dev, ti);
+        if (!(flags & TOUCH_CLIENT_ID))
+            TouchEndDDXTouch(dev, touchpoint.ti);
         break;
     default:
         return 0;
     }
-
-    if (!valuator_mask_isset(&mask, 0))
-        valuator_mask_set_double(&mask, 0, valuator_mask_get_double(ti->valuators, 0));
-    if (!valuator_mask_isset(&mask, 1))
-        valuator_mask_set_double(&mask, 1, valuator_mask_get_double(ti->valuators, 1));
-
+    if (!(flags & TOUCH_CLIENT_ID))
+    {
+        if (!valuator_mask_isset(&mask, 0))
+            valuator_mask_set_double(&mask, 0, valuator_mask_get_double(touchpoint.ti->valuators, 0));
+        if (!valuator_mask_isset(&mask, 1))
+            valuator_mask_set_double(&mask, 1, valuator_mask_get_double(touchpoint.ti->valuators, 1));
+    }
 
     /* Get our screen event co-ordinates (root_x/root_y/event_x/event_y):
      * these come from the touchpoint in Absolute mode, or the sprite in
@@ -1812,10 +1847,12 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
     if (t->mode == XIDirectTouch) {
         transformAbsolute(dev, &mask);
 
-        for (i = 0; i < valuator_mask_size(&mask); i++) {
-            if (valuator_mask_isset(&mask, i))
-                valuator_mask_set_double(ti->valuators, i,
-                        valuator_mask_get_double(&mask, i));
+        if (!(flags & TOUCH_CLIENT_ID)) {
+            for (i = 0; i < valuator_mask_size(&mask); i++) {
+                double val;
+                if (valuator_mask_fetch_double(&mask, i, &val))
+                    valuator_mask_set_double(touchpoint.ti->valuators, i, val);
+            }
         }
 
         clipAbsolute(dev, &mask);
@@ -1840,7 +1877,7 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
     event->root = scr->root->drawable.id;
 
     event_set_root_coordinates(event, screenx, screeny);
-    event->touchid = ti->client_id;
+    event->touchid = touchpoint.ti->client_id;
     event->flags = flags;
 
     if (emulate_pointer)
commit fcda98c48610fd507ca0b89c6006a5497d9dc1c9
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Dec 16 12:41:08 2011 +1000

    dix: button state must show the logical buttons, not physical buttons
    
    If the device is mapped 3 2 1, a click on physical button 1 sends a button 3
    press, but the state was set for button 1. Fix this, the state must be set
    for that button's logical mapping.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=655928
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/inpututils.c b/dix/inpututils.c
index 8cd4d59..e1a11a1 100644
--- a/dix/inpututils.c
+++ b/dix/inpututils.c
@@ -672,7 +672,7 @@ void event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd, DeviceEvent *event)
 
     for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++)
         if (BitIsOn(mouse->button->down, i))
-            SetBit(event->buttons, i);
+            SetBit(event->buttons, mouse->button->map[i]);
 
     if (kbd && kbd->key)
     {
commit 47da6b6b2c2e9245422655f94770146fb8cd430b
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Mon Dec 19 14:52:41 2011 +1000

    dix: don't retrieve the syncEvents tail on an empty list
    
    An empty list points to itself but syncEvents has the list head only and is
    of a different format than the elements. Thus, casting it to a QdEventPtr
    gives us garbage.
    
    Segfaults with XTS test case Xlib13/XGrabKeyboard
    
    Introduced in 7af23259d88f4c28ed21140f82cc03b3724c06bb.
    
    Reported-by: Aaron Plattner <aplattner at nvidia.com>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/events.c b/dix/events.c
index 8dff299..eb7bd92 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1115,13 +1115,14 @@ NoticeEventTime(InternalEvent *ev)
 void
 EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
 {
-    QdEventPtr	tail;
+    QdEventPtr	tail = NULL;
     QdEventPtr	qe;
     SpritePtr	pSprite = device->spriteInfo->sprite;
     int		eventlen;
     DeviceEvent *event = &ev->device_event;
 
-    tail = list_last_entry(&syncEvents.pending, QdEventRec, next);
+    if (!list_is_empty(&syncEvents.pending))
+        tail = list_last_entry(&syncEvents.pending, QdEventRec, next);
 
     NoticeTime((InternalEvent*)event);
 
commit 9ce8463a3334f76f128bb35b541aa6e67b4e4374
Author: Daniel Stone <daniel at fooishbar.org>
Date:   Wed Dec 14 15:41:07 2011 +1000

    dix: generate touchpoints from driver-submitted data
    
    The touchpoints are generated, enqueued but not processed since we don't
    handle them in the event processing yet.
    
    Co-authored-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/getevents.c b/dix/getevents.c
index b389281..68167af 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -49,6 +49,7 @@
 #include "eventconvert.h"
 #include "inpututils.h"
 #include "mi.h"
+#include "windowstr.h"
 
 #include <X11/extensions/XKBproto.h>
 #include "xkbsrv.h"
@@ -156,6 +157,17 @@ key_autorepeats(DeviceIntPtr pDev, int key_code)
 }
 
 static void
+init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms)
+{
+    memset(event, 0, sizeof(DeviceEvent));
+    event->header = ET_Internal;
+    event->length = sizeof(DeviceEvent);
+    event->time = ms;
+    event->deviceid = dev->id;
+    event->sourceid = dev->id;
+}
+
+static void
 init_touch_ownership(DeviceIntPtr dev, TouchOwnershipEvent *event, Time ms)
 {
     memset(event, 0, sizeof(TouchOwnershipEvent));
@@ -1709,9 +1721,143 @@ int
 GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
                uint16_t type, uint32_t flags, const ValuatorMask *mask_in)
 {
-    return 0;
-}
+    ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
+    TouchClassPtr t = dev->touch;
+    ValuatorClassPtr v = dev->valuator;
+    DeviceEvent *event;
+    CARD32 ms = GetTimeInMillis();
+    ValuatorMask mask;
+    double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */
+    double devx = 0.0, devy = 0.0; /* desktop-wide in device coords */
+    int i;
+    int num_events = 0;
+    RawDeviceEvent *raw;
+    DDXTouchPointInfoPtr ti;
+    int need_rawevent = TRUE;
+    Bool emulate_pointer = FALSE;
+
+    if (!dev->enabled || !t || !v)
+        return 0;
+
+    /* Find and/or create the DDX touch info */
+    ti = TouchFindByDDXID(dev, ddx_touchid, (type == XI_TouchBegin));
+    if (!ti)
+    {
+        ErrorF("[dix] %s: unable to %s touch point %x\n", dev->name,
+                type == XI_TouchBegin ? "begin" : "find", ddx_touchid);
+        return 0;
+    }
+
+    emulate_pointer =  ti->emulate_pointer;
+
+    if (!IsMaster(dev))
+        events = UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT, &num_events);
+
+    valuator_mask_copy(&mask, mask_in);
+
+    if (need_rawevent)
+    {
+        raw = &events->raw_event;
+        events++;
+        num_events++;
+        init_raw(dev, raw, ms, type, ti->client_id);
+        set_raw_valuators(raw, &mask, raw->valuators.data_raw);
+    }
+
+    event = &events->device_event;
+    num_events++;
+
+    init_event(dev, event, ms);
+
+    switch (type) {
+    case XI_TouchBegin:
+        event->type = ET_TouchBegin;
+        /* If we're starting a touch, we must have x & y co-ordinates. */
+        if (!mask_in ||
+            !valuator_mask_isset(mask_in, 0) ||
+            !valuator_mask_isset(mask_in, 1))
+        {
+            ErrorF("%s: Attempted to start touch without x/y (driver bug)\n",
+                   dev->name);
+            return 0;
+        }
+        break;
+    case XI_TouchUpdate:
+        event->type = ET_TouchUpdate;
+        if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0)
+        {
+            ErrorF("%s: TouchUpdate with no valuators? Driver bug\n",
+                    dev->name);
+        }
+        break;
+    case XI_TouchEnd:
+        event->type = ET_TouchEnd;
+        /* We can end the DDX touch here, since we don't use the active
+         * field below */
+        TouchEndDDXTouch(dev, ti);
+        break;
+    default:
+        return 0;
+    }
+
+    if (!valuator_mask_isset(&mask, 0))
+        valuator_mask_set_double(&mask, 0, valuator_mask_get_double(ti->valuators, 0));
+    if (!valuator_mask_isset(&mask, 1))
+        valuator_mask_set_double(&mask, 1, valuator_mask_get_double(ti->valuators, 1));
+
+
+    /* Get our screen event co-ordinates (root_x/root_y/event_x/event_y):
+     * these come from the touchpoint in Absolute mode, or the sprite in
+     * Relative. */
+    if (t->mode == XIDirectTouch) {
+        transformAbsolute(dev, &mask);
+
+        for (i = 0; i < valuator_mask_size(&mask); i++) {
+            if (valuator_mask_isset(&mask, i))
+                valuator_mask_set_double(ti->valuators, i,
+                        valuator_mask_get_double(&mask, i));
+        }
+
+        clipAbsolute(dev, &mask);
+    }
+    else {
+        screenx = dev->spriteInfo->sprite->hotPhys.x;
+        screeny = dev->spriteInfo->sprite->hotPhys.y;
+    }
+    if (need_rawevent)
+        set_raw_valuators(raw, &mask, raw->valuators.data);
+
+    scr = scale_to_desktop(dev, &mask, &devx, &devy, &screenx, &screeny);
+    if (emulate_pointer)
+        scr = positionSprite(dev, Absolute, &mask,
+                             &devx, &devy, &screenx, &screeny);
+
+    /* see fill_pointer_events for coordinate systems */
+    updateHistory(dev, &mask, ms);
+    clipValuators(dev, &mask);
+    storeLastValuators(dev, &mask, 0, 1, devx, devy);
+
+    event->root = scr->root->drawable.id;
+
+    event_set_root_coordinates(event, screenx, screeny);
+    event->touchid = ti->client_id;
+    event->flags = flags;
 
+    if (emulate_pointer)
+    {
+        event->flags |= TOUCH_POINTER_EMULATED;
+        event->detail.button = 1;
+    }
+
+    set_valuators(dev, event, &mask);
+    for (i = 0; i < v->numAxes; i++)
+    {
+        if (valuator_mask_isset(&mask, i))
+            v->axisVal[i] = valuator_mask_get(&mask, i);
+    }
+
+    return num_events;
+}
 
 
 /**
commit bec51f5ec6575a1971ae5371a4b6d8563933032c
Author: Daniel Stone <daniel at fooishbar.org>
Date:   Wed Dec 14 15:29:48 2011 +1000

    dix: add GetTouchOwnership event API
    
    No callers yet. This API is not to be used by drivers, it's an API for the
    DIX which will create ownership events mainly on touch acceptance/rejection.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/getevents.c b/dix/getevents.c
index 39f8ca7..b389281 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -156,6 +156,17 @@ key_autorepeats(DeviceIntPtr pDev, int key_code)
 }
 
 static void
+init_touch_ownership(DeviceIntPtr dev, TouchOwnershipEvent *event, Time ms)
+{
+    memset(event, 0, sizeof(TouchOwnershipEvent));
+    event->header = ET_Internal;
+    event->type = ET_TouchOwnership;
+    event->length = sizeof(TouchOwnershipEvent);
+    event->time = ms;
+    event->deviceid = dev->id;
+}
+
+static void
 init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail)
 {
     memset(event, 0, sizeof(RawDeviceEvent));
@@ -1631,6 +1642,30 @@ GetProximityEvents(InternalEvent *events, DeviceIntPtr pDev, int type, const Val
     return num_events;
 }
 
+int
+GetTouchOwnershipEvents(InternalEvent *events, DeviceIntPtr pDev,
+                        TouchPointInfoPtr ti, uint8_t reason, XID resource,
+                        uint32_t flags)
+{
+    TouchClassPtr t = pDev->touch;
+    TouchOwnershipEvent *event;
+    CARD32 ms = GetTimeInMillis();
+
+    if (!pDev->enabled || !t || !ti)
+        return 0;
+
+    event = &events->touch_ownership_event;
+    init_touch_ownership(pDev, event, ms);
+
+    event->touchid = ti->client_id;
+    event->sourceid = ti->sourceid;
+    event->resource = resource;
+    event->flags = flags;
+    event->reason = reason;
+
+    return 1;
+}
+
 /**
  * Generate internal events representing this touch event and enqueue them
  * on the event queue.
diff --git a/include/input.h b/include/input.h
index 834dd27..4d60792 100644
--- a/include/input.h
+++ b/include/input.h
@@ -503,6 +503,14 @@ void QueueTouchEvents(DeviceIntPtr device,
                       int flags,
                       const ValuatorMask *mask);
 
+extern int GetTouchOwnershipEvents(
+    InternalEvent *events,
+    DeviceIntPtr pDev,
+    TouchPointInfoPtr ti,
+    uint8_t mode,
+    XID resource,
+    uint32_t flags);
+
 extern _X_EXPORT int GetProximityEvents(
     InternalEvent *events,
     DeviceIntPtr pDev,
commit 5c63dc6dbcbebbb19d79575a9f1ec9878e6537f1
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 14:57:46 2011 +1000

    dix: add DIX API to create touchpoints
    
    The DIX touchpoints are the ones used for event processing.
    
    Co-authored-by: Daniel Stone <daniel at fooishbar.org>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/touch.c b/dix/touch.c
index b492e82..dfb7ff0 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -30,6 +30,7 @@
 
 #include "inputstr.h"
 #include "scrnintstr.h"
+#include "dixgrabs.h"
 
 #include "eventstr.h"
 #include "exevents.h"
@@ -262,6 +263,9 @@ TouchFreeTouchPoint(DeviceIntPtr device, int index)
         return;
     ti = &device->touch->touches[index];
 
+    if (ti->active)
+        TouchEndTouch(device, ti);
+
     valuator_mask_free(&ti->valuators);
     free(ti->sprite.spriteTrace);
     ti->sprite.spriteTrace = NULL;
@@ -273,4 +277,123 @@ TouchFreeTouchPoint(DeviceIntPtr device, int index)
     ti->history_elements = 0;
 }
 
+/**
+ * Given a client-facing ID (e.g. DeviceEvent::detail.touch), find the
+ * associated TouchPointInfoRec.
+ */
+TouchPointInfoPtr
+TouchFindByClientID(DeviceIntPtr dev, uint32_t client_id)
+{
+    TouchClassPtr t = dev->touch;
+    TouchPointInfoPtr ti;
+    int i;
+
+    if (!t)
+        return NULL;
+
+    for (i = 0; i < t->num_touches; i++)
+    {
+        ti = &t->touches[i];
+        if (ti->active && ti->client_id == client_id)
+            return ti;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Given a unique ID for a touchpoint, create a touchpoint record in the
+ * server.
+ *
+ * Returns NULL on failure (i.e. if another touch with that ID is already active,
+ * allocation failure).
+ */
+TouchPointInfoPtr
+TouchBeginTouch(DeviceIntPtr dev, int sourceid, uint32_t touchid,
+                Bool emulate_pointer)
+{
+    int i;
+    TouchClassPtr t = dev->touch;
+    TouchPointInfoPtr ti;
+    void *tmp;
+
+    if (!t)
+        return NULL;
+
+    /* Look for another active touchpoint with the same client ID.  It's
+     * technically legitimate for a touchpoint to still exist with the same
+     * ID but only once the 32 bits wrap over and you've used up 4 billion
+     * touch ids without lifting that one finger off once. In which case
+     * you deserve a medal or something, but not error handling code. */
+    if (TouchFindByClientID(dev, touchid))
+        return NULL;
+
+try_find_touch:
+    for (i = 0; i < t->num_touches; i++)
+    {
+        ti = &t->touches[i];
+        if (!ti->active) {
+            ti->active = TRUE;
+            ti->client_id = touchid;
+            ti->sourceid = sourceid;
+            ti->emulate_pointer = emulate_pointer;
+            return ti;
+        }
+    }
+
+    /* If we get here, then we've run out of touches: enlarge dev->touch and
+     * try again. */
+    tmp = realloc(t->touches, (t->num_touches + 1) * sizeof(*ti));
+    if (tmp)
+    {
+        t->touches = tmp;
+        t->num_touches++;
+        if (TouchInitTouchPoint(t, dev->valuator, t->num_touches - 1))
+            goto try_find_touch;
+    }
+
+    return NULL;
+}
+
+/**
+ * Releases a touchpoint for use: this must only be called after all events
+ * related to that touchpoint have been sent and finalised.  Called from
+ * ProcessTouchEvent and friends.  Not by you.
+ */
+void
+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 &&
+                !dev->button->buttonsDown &&
+                !dev->touch->buttonsDown &&
+                GrabIsPointerGrab(grab))
+                (*dev->deviceGrab.DeactivateGrab)(dev);
+        }
+    }
+
+    ti->active = FALSE;
+    ti->pending_finish = FALSE;
+    ti->sprite.spriteTraceGood = 0;
+    free(ti->listeners);
+    ti->listeners = NULL;
+    ti->num_listeners = 0;
+    ti->num_grabs = 0;
+    ti->client_id = 0;
+
+    valuator_mask_zero(ti->valuators);
+}
 
diff --git a/include/input.h b/include/input.h
index e79a3ee..834dd27 100644
--- a/include/input.h
+++ b/include/input.h
@@ -594,6 +594,11 @@ extern DDXTouchPointInfoPtr TouchFindByDDXID(DeviceIntPtr dev,
                                              Bool create);
 extern Bool TouchInitTouchPoint(TouchClassPtr touch, ValuatorClassPtr v, int index);
 extern void TouchFreeTouchPoint(DeviceIntPtr dev, int index);
+extern TouchPointInfoPtr TouchBeginTouch(DeviceIntPtr dev, int sourceid,
+                                         uint32_t touchid, Bool emulate_pointer);
+extern TouchPointInfoPtr TouchFindByClientID(DeviceIntPtr dev,
+                                             uint32_t client_id);
+extern void TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti);
 
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients);
diff --git a/test/touch.c b/test/touch.c
index 1ea8f0c..88955cb 100644
--- a/test/touch.c
+++ b/test/touch.c
@@ -28,6 +28,7 @@
 #include <stdint.h>
 #include "inputstr.h"
 #include "assert.h"
+#include "scrnintstr.h"
 
 static void touch_grow_queue(void)
 {
@@ -190,11 +191,80 @@ static void touch_begin_ddxtouch(void)
     last_client_id = ti->client_id;
 }
 
+static void touch_begin_touch(void)
+{
+    DeviceIntRec dev;
+    TouchClassRec touch;
+    ValuatorClassRec val;
+    TouchPointInfoPtr ti;
+    int touchid = 12434;
+    int sourceid = 23;
+    SpriteInfoRec sprite;
+    ScreenRec screen;
+
+    screenInfo.screens[0] = &screen;
+
+    memset(&dev, 0, sizeof(dev));
+    dev.id = 2;
+
+    memset(&sprite, 0, sizeof(sprite));
+    dev.spriteInfo = &sprite;
+
+    memset(&touch, 0, sizeof(touch));
+    touch.num_touches = 0;
+
+    memset(&val, 0, sizeof(val));
+    dev.valuator = &val;
+    val.numAxes = 2;
+
+    ti = TouchBeginTouch(&dev, sourceid, touchid, TRUE);
+    assert(!ti);
+
+    dev.touch = &touch;
+    ti = TouchBeginTouch(&dev, sourceid, touchid, TRUE);
+    assert(ti);
+    assert(ti->client_id == touchid);
+    assert(ti->active);
+    assert(ti->sourceid == sourceid);
+    assert(ti->emulate_pointer);
+
+    assert(touch.num_touches == 1);
+}
+
+static void touch_init(void)
+{
+    DeviceIntRec dev;
+    Atom labels[2] = {0};
+    int rc;
+    SpriteInfoRec sprite;
+    ScreenRec screen;
+
+    screenInfo.screens[0] = &screen;
+
+    memset(&dev, 0, sizeof(dev));
+
+    memset(&sprite, 0, sizeof(sprite));
+    dev.spriteInfo = &sprite;
+
+    InitAtoms();
+    rc = InitTouchClassDeviceStruct(&dev, 1, XIDirectTouch, 2);
+    assert(rc == FALSE);
+
+    InitValuatorClassDeviceStruct(&dev, 2, labels, 10, Absolute);
+    rc = InitTouchClassDeviceStruct(&dev, 1, XIDirectTouch, 2);
+    assert(rc == TRUE);
+    assert(dev.touch);
+}
+
+
+
 int main(int argc, char** argv)
 {
     touch_grow_queue();
     touch_find_ddxid();
     touch_begin_ddxtouch();
+    touch_init();
+    touch_begin_touch();
 
     return 0;
 }
commit 7f8127d203394cae45c3ded0d063030d7c5fdb70
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 14:53:52 2011 +1000

    dix: if we run out of space for new touch events, resize the queue
    
    The SIGIO handler forces us to drop the current touch and schedule the
    actual resize for later. Should not happen if the device sets up the
    TouchClassRec with the correct number of touchpoints.
    
    Co-authored-by: Daniel Stone <daniel at fooishbar.org>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/touch.c b/dix/touch.c
index f9d1617..b492e82 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -34,6 +34,9 @@
 #include "eventstr.h"
 #include "exevents.h"
 
+/* If a touch queue resize is needed, the device id's bit is set. */
+static unsigned char resize_waiting[(MAXDEVICES + 7)/8];
+
 /**
  * Some documentation about touch points:
  * The driver submits touch events with it's own (unique) touch point ID.
@@ -54,6 +57,60 @@
  */
 
 /**
+ * Check which devices need a bigger touch event queue and grow their
+ * last.touches by half it's current size.
+ *
+ * @param client Always the serverClient
+ * @param closure Always NULL
+ *
+ * @return Always True. If we fail to grow we probably will topple over soon
+ * anyway and re-executing this won't help.
+ */
+static Bool
+TouchResizeQueue(ClientPtr client, pointer closure)
+{
+    int i;
+
+    OsBlockSignals();
+
+    /* first two ids are reserved */
+    for (i = 2; i < MAXDEVICES; i++)
+    {
+        DeviceIntPtr dev;
+        DDXTouchPointInfoPtr tmp;
+        size_t size;
+
+        if (!BitIsOn(resize_waiting, i))
+            continue;
+
+        ClearBit(resize_waiting, i);
+
+        /* device may have disappeared by now */
+        dixLookupDevice(&dev, i, serverClient, DixWriteAccess);
+        if (!dev)
+            continue;
+
+        /* Need to grow the queue means dropping events. Grow sufficiently so we
+         * don't need to do it often */
+        size = dev->last.num_touches + dev->last.num_touches/2 + 1;
+
+        tmp = realloc(dev->last.touches, size *  sizeof(*dev->last.touches));
+        if (tmp)
+        {
+            int i;
+            dev->last.touches = tmp;
+            for (i = dev->last.num_touches; i < size; i++)
+                TouchInitDDXTouchPoint(dev, &dev->last.touches[i]);
+            dev->last.num_touches = size;
+        }
+
+    }
+    OsReleaseSignals();
+
+    return TRUE;
+}
+
+/**
  * Given the DDX-facing ID (which is _not_ DeviceEvent::detail.touch), find the
  * associated DDXTouchPointInfoRec.
  *
@@ -133,7 +190,16 @@ TouchBeginDDXTouch(DeviceIntPtr dev, uint32_t ddx_id)
         return ti;
     }
 
-    /* If we get here, then we've run out of touches, drop the event */
+    /* If we get here, then we've run out of touches and we need to drop the
+     * event (we're inside the SIGIO handler here) schedule a WorkProc to
+     * grow the queue for us for next time. */
+    ErrorF("%s: not enough space for touch events (max %d touchpoints). "
+           "Dropping this event.\n", dev->name, dev->last.num_touches);
+    if (!BitIsOn(resize_waiting, dev->id)) {
+        SetBit(resize_waiting, dev->id);
+        QueueWorkProc(TouchResizeQueue, serverClient, NULL);
+    }
+
     return NULL;
 }
 
diff --git a/test/touch.c b/test/touch.c
index 5b8e567..1ea8f0c 100644
--- a/test/touch.c
+++ b/test/touch.c
@@ -29,6 +29,56 @@
 #include "inputstr.h"
 #include "assert.h"
 
+static void touch_grow_queue(void)
+{
+    DeviceIntRec dev;
+    ValuatorClassRec val;
+    TouchClassRec touch;
+    size_t size, new_size;
+    int i;
+
+    memset(&dev, 0, sizeof(dev));
+    dev.id = 2;
+    dev.valuator = &val;
+    val.numAxes = 5;
+    dev.touch = &touch;
+    inputInfo.devices = &dev;
+
+    size = 5;
+
+    dev.last.num_touches = size;
+    dev.last.touches = calloc(dev.last.num_touches, sizeof(*dev.last.touches));
+    assert(dev.last.touches);
+    for (i = 0; i < size; i++) {
+        dev.last.touches[i].active = TRUE;
+        dev.last.touches[i].ddx_id = i;
+        dev.last.touches[i].client_id = i * 2;
+    }
+
+    /* no more space, should've scheduled a workproc */
+    assert(TouchBeginDDXTouch(&dev, 1234) == NULL);
+    ProcessWorkQueue();
+
+    new_size = size + size/2 + 1;
+    assert(dev.last.num_touches == new_size);
+
+    /* make sure we haven't touched those */
+    for (i = 0; i < size; i++) {
+        DDXTouchPointInfoPtr t = &dev.last.touches[i];
+        assert(t->active == TRUE);
+        assert(t->ddx_id == i);
+        assert(t->client_id == i * 2);
+    }
+
+    /* make sure those are zero-initialized */
+    for (i = size; i < new_size; i++) {
+        DDXTouchPointInfoPtr t = &dev.last.touches[i];
+        assert(t->active == FALSE);
+        assert(t->client_id == 0);
+        assert(t->ddx_id == 0);
+    }
+}
+
 static void touch_find_ddxid(void)
 {
     DeviceIntRec dev;
@@ -142,6 +192,7 @@ static void touch_begin_ddxtouch(void)
 
 int main(int argc, char** argv)
 {
+    touch_grow_queue();
     touch_find_ddxid();
     touch_begin_ddxtouch();
 
commit 758bc57ba5a89f765d83f0b169aa09e79a89bf89
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 14:48:56 2011 +1000

    dix: add helper functions to create DDX touch recs
    
    DDX touch points are the ones that keep records of the driver-submitted
    touchpoints. They're unaffected by the grab state and terminate on a
    TouchEnd submitted by the driver.
    
    The client ID assigned is server-global.
    
    Since drivers usually submit in the SIGIO handler, we cannot allocate in the
    these functions.
    
    Co-authored-by: Daniel Stone <daniel at fooishbar.org>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/touch.c b/dix/touch.c
index 9fa2f3c..f9d1617 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -31,6 +31,122 @@
 #include "inputstr.h"
 #include "scrnintstr.h"
 
+#include "eventstr.h"
+#include "exevents.h"
+
+/**
+ * Some documentation about touch points:
+ * The driver submits touch events with it's own (unique) touch point ID.
+ * The driver may re-use those IDs, the DDX doesn't care. It just passes on
+ * the data to the DIX. In the server, the driver's ID is referred to as the
+ * DDX id anyway.
+ *
+ * On a TouchBegin, we create a DDXTouchPointInfo that contains the DDX id
+ * and the client ID that this touchpoint will have. The client ID is the
+ * one visible on the protocol.
+ *
+ * TouchUpdate and TouchEnd will only be processed if there is an active
+ * touchpoint with the same DDX id.
+ *
+ * The DDXTouchPointInfo struct is stored dev->last.touches. When the event
+ * being processed, it becomes a TouchPointInfo in dev->touch-touches which
+ * contains amongst other things the sprite trace and delivery information.
+ */
+
+/**
+ * Given the DDX-facing ID (which is _not_ DeviceEvent::detail.touch), find the
+ * associated DDXTouchPointInfoRec.
+ *
+ * @param dev The device to create the touch point for
+ * @param ddx_id Touch id assigned by the driver/ddx
+ * @param create Create the touchpoint if it cannot be found
+ */
+DDXTouchPointInfoPtr
+TouchFindByDDXID(DeviceIntPtr dev, uint32_t ddx_id, Bool create)
+{
+    DDXTouchPointInfoPtr ti;
+    int i;
+
+    if (!dev->touch)
+        return NULL;
+
+    for (i = 0; i < dev->last.num_touches; i++)
+    {
+        ti = &dev->last.touches[i];
+        if (ti->active && ti->ddx_id == ddx_id)
+            return ti;
+    }
+
+    return create ? TouchBeginDDXTouch(dev, ddx_id) : NULL;
+}
+
+/**
+ * Given a unique DDX ID for a touchpoint, create a touchpoint record and
+ * return it.
+ *
+ * If no other touch points are active, mark new touchpoint for pointer
+ * emulation.
+ *
+ * Returns NULL on failure (i.e. if another touch with that ID is already active,
+ * allocation failure).
+ */
+DDXTouchPointInfoPtr
+TouchBeginDDXTouch(DeviceIntPtr dev, uint32_t ddx_id)
+{
+    static int next_client_id = 1;
+    int i;
+    TouchClassPtr t = dev->touch;
+    DDXTouchPointInfoPtr ti = NULL;
+    Bool emulate_pointer = (t->mode == XIDirectTouch);
+
+    if (!t)
+        return NULL;
+
+    /* Look for another active touchpoint with the same DDX ID. DDX
+     * touchpoints must be unique. */
+    if (TouchFindByDDXID(dev, ddx_id, FALSE))
+        return NULL;
+
+    for (i = 0; i < dev->last.num_touches; i++)
+    {
+        /* Only emulate pointer events on the first touch */
+        if (dev->last.touches[i].active)
+            emulate_pointer = FALSE;
+        else if (!ti) /* ti is now first non-active touch rec */
+            ti = &dev->last.touches[i];
+
+        if (!emulate_pointer && ti)
+            break;
+    }
+
+    if (ti)
+    {
+        int client_id;
+        ti->active = TRUE;
+        ti->ddx_id = ddx_id;
+        client_id = next_client_id;
+        next_client_id++;
+        if (next_client_id == 0)
+            next_client_id = 1;
+        ti->client_id = client_id;
+        ti->emulate_pointer = emulate_pointer;
+        return ti;
+    }
+
+    /* If we get here, then we've run out of touches, drop the event */
+    return NULL;
+}
+
+void
+TouchEndDDXTouch(DeviceIntPtr dev, DDXTouchPointInfoPtr ti)
+{
+    TouchClassPtr t = dev->touch;
+
+    if (!t)
+        return;
+
+    ti->active = FALSE;
+}
 
 void
 TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch)
diff --git a/include/input.h b/include/input.h
index 0d31edf..e79a3ee 100644
--- a/include/input.h
+++ b/include/input.h
@@ -587,6 +587,11 @@ enum TouchListenerType {
 };
 
 extern void TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch);
+extern DDXTouchPointInfoPtr TouchBeginDDXTouch(DeviceIntPtr dev, uint32_t ddx_id);
+extern void TouchEndDDXTouch(DeviceIntPtr dev, DDXTouchPointInfoPtr ti);
+extern DDXTouchPointInfoPtr TouchFindByDDXID(DeviceIntPtr dev,
+                                             uint32_t ddx_id,
+                                             Bool create);
 extern Bool TouchInitTouchPoint(TouchClassPtr touch, ValuatorClassPtr v, int index);
 extern void TouchFreeTouchPoint(DeviceIntPtr dev, int index);
 
diff --git a/test/Makefile.am b/test/Makefile.am
index 48393d3..ba8932c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,6 +1,6 @@
 if ENABLE_UNIT_TESTS
 SUBDIRS= .
-noinst_PROGRAMS = list string
+noinst_PROGRAMS = list string touch
 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
@@ -35,6 +35,7 @@ list_LDADD=$(TEST_LDADD)
 misc_LDADD=$(TEST_LDADD)
 fixes_LDADD=$(TEST_LDADD)
 xfree86_LDADD=$(TEST_LDADD)
+touch_LDADD=$(TEST_LDADD)
 
 libxservertest_la_LIBADD = $(XSERVER_LIBS)
 if XORG
diff --git a/test/touch.c b/test/touch.c
new file mode 100644
index 0000000..5b8e567
--- /dev/null
+++ b/test/touch.c
@@ -0,0 +1,149 @@
+/**
+ * Copyright © 2011 Red Hat, Inc.
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a
+ *  copy of this software and associated documentation files (the "Software"),
+ *  to deal in the Software without restriction, including without limitation
+ *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ *  and/or sell copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice (including the next
+ *  paragraph) shall be included in all copies or substantial portions of the
+ *  Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ *  DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdint.h>
+#include "inputstr.h"
+#include "assert.h"
+
+static void touch_find_ddxid(void)
+{
+    DeviceIntRec dev;
+    DDXTouchPointInfoPtr ti;
+    ValuatorClassRec val;
+    TouchClassRec touch;
+    int size = 5;
+    int i;
+
+    memset(&dev, 0, sizeof(dev));
+    dev.id = 2;
+    dev.valuator = &val;
+    val.numAxes = 5;
+    dev.touch = &touch;
+    dev.last.num_touches = size;
+    dev.last.touches = calloc(dev.last.num_touches, sizeof(*dev.last.touches));
+    inputInfo.devices = &dev;
+    assert(dev.last.touches);
+
+
+    dev.last.touches[0].active = TRUE;
+    dev.last.touches[0].ddx_id = 10;
+    dev.last.touches[0].client_id = 20;
+
+
+    /* existing */
+    ti = TouchFindByDDXID(&dev, 10, FALSE);
+    assert(ti == &dev.last.touches[0]);
+
+    /* non-existing */
+    ti = TouchFindByDDXID(&dev, 20, FALSE);
+    assert(ti == NULL);
+
+    /* Non-active */
+    dev.last.touches[0].active = FALSE;
+    ti = TouchFindByDDXID(&dev, 10, FALSE);
+    assert(ti == NULL);
+
+    /* create on number 2*/
+    dev.last.touches[0].active = TRUE;
+
+    ti = TouchFindByDDXID(&dev, 20, TRUE);
+    assert(ti == &dev.last.touches[1]);
+    assert(ti->active);
+    assert(ti->ddx_id == 20);
+
+    /* set all to active */
+    for (i = 0; i < size; i++)
+        dev.last.touches[i].active = TRUE;
+
+    /* Try to create more, fail */
+    ti = TouchFindByDDXID(&dev, 30, TRUE);
+    assert(ti == NULL);
+    ti = TouchFindByDDXID(&dev, 30, TRUE);
+    assert(ti == NULL);
+    /* make sure we haven't resized, we're in the signal handler */
+    assert(dev.last.num_touches == size);
+
+    /* stop one touchpoint, try to create, succeed */
+    dev.last.touches[2].active = FALSE;
+    ti = TouchFindByDDXID(&dev, 30, TRUE);
+    assert(ti == &dev.last.touches[2]);
+    /* but still grow anyway */
+    ProcessWorkQueue();
+    ti = TouchFindByDDXID(&dev, 40, TRUE);
+    assert(ti == &dev.last.touches[size]);
+}
+
+static void touch_begin_ddxtouch(void)
+{
+    DeviceIntRec dev;
+    DDXTouchPointInfoPtr ti;
+    ValuatorClassRec val;
+    TouchClassRec touch;
+    int ddx_id = 123;
+    unsigned int last_client_id = 0;
+    int size = 5;
+
+    memset(&dev, 0, sizeof(dev));
+    dev.id = 2;
+    dev.valuator = &val;
+    val.numAxes = 5;
+    touch.mode = XIDirectTouch;
+    dev.touch = &touch;
+    dev.last.num_touches = size;
+    dev.last.touches = calloc(dev.last.num_touches, sizeof(*dev.last.touches));
+    inputInfo.devices = &dev;
+    assert(dev.last.touches);
+
+    ti = TouchBeginDDXTouch(&dev, ddx_id);
+    assert(ti);
+    assert(ti->ddx_id == ddx_id);
+    /* client_id == ddx_id can happen in real life, but not in this test */
+    assert(ti->client_id != ddx_id);
+    assert(ti->active);
+    assert(ti->client_id > last_client_id);
+    assert(ti->emulate_pointer);
+    last_client_id = ti->client_id;
+
+    ddx_id += 10;
+    ti = TouchBeginDDXTouch(&dev, ddx_id);
+    assert(ti);
+    assert(ti->ddx_id == ddx_id);
+    /* client_id == ddx_id can happen in real life, but not in this test */
+    assert(ti->client_id != ddx_id);
+    assert(ti->active);
+    assert(ti->client_id > last_client_id);
+    assert(!ti->emulate_pointer);
+    last_client_id = ti->client_id;
+}
+
+int main(int argc, char** argv)
+{
+    touch_find_ddxid();
+    touch_begin_ddxtouch();
+
+    return 0;
+}
commit 1a133eb8b1ddbe0da7c2fbf7f6a686ec4512373e
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 15 08:30:02 2011 +1000

    xfree86: bump the input ABI for the touch changes
    
    New additions to the API:
    - InitTouchClassDeviceStruct
    - xf86PostTouchEvent
    
    Changes to the ABI:
    - DeviceIntRec now contains a TouchClassPtr
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/hw/xfree86/common/xf86Module.h b/hw/xfree86/common/xf86Module.h
index d354643..1de87db 100644
--- a/hw/xfree86/common/xf86Module.h
+++ b/hw/xfree86/common/xf86Module.h
@@ -83,7 +83,7 @@ typedef enum {
  */
 #define ABI_ANSIC_VERSION	SET_ABI_VERSION(0, 4)
 #define ABI_VIDEODRV_VERSION	SET_ABI_VERSION(12, 0)
-#define ABI_XINPUT_VERSION	SET_ABI_VERSION(15, 0)
+#define ABI_XINPUT_VERSION	SET_ABI_VERSION(16, 0)
 #define ABI_EXTENSION_VERSION	SET_ABI_VERSION(6, 0)
 #define ABI_FONT_VERSION	SET_ABI_VERSION(0, 6)
 
commit 3fb258ca28850c998097b55884774cb95f476f69
Author: Daniel Stone <daniel at fooishbar.org>
Date:   Wed Dec 14 12:46:40 2011 +1000

    input: add a TouchClassRec to the devices
    
    These structs will be used to store touch-related data, events and
    information.
    
    Drivers must call InitTouchClassDeviceStruct to set up a multi-touch capable
    device.
    
    Touchpoints for the DDX and the DIX are handled separately - touchpoints
    submitted by the driver/DDX will be stored in the DDXTouchPointInfoRec. Once
    the touchpoints are processed by the DIX, new TouchPointInfoRecs are created
    and stored. This process is already used for pointer events with the
    last.valuators field.
    
    Note that this patch does not actually add the generation of touch events,
    only the required structs.
    
    TouchListeners are (future) recipients of touch or emulated pointer events.
    Each listener is in a state, depending which event they have already
    received. The type of listener defines how the listener got to be one.
    
    Co-authored-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 2db6053..ffb48d1 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -44,6 +44,32 @@ SOFTWARE.
 
 ********************************************************/
 
+/*
+ * Copyright © 2010 Collabora Ltd.
+ * Copyright © 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Daniel Stone <daniel at fooishbar.org>
+ */
+
 /********************************************************************
  *
  *  Routines to register and initialize extension input devices.
@@ -641,6 +667,41 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
         classes->proximity = to->proximity;
         to->proximity      = NULL;
     }
+
+    if (from->touch)
+    {
+        TouchPointInfoPtr tmp;
+        if (!to->touch)
+        {
+            classes = to->unused_classes;
+            to->touch = classes->touch;
+            if (!to->touch)
+            {
+                int i;
+                to->touch = calloc(1, sizeof(TouchClassRec));
+                if (!to->touch)
+                    FatalError("[Xi] no memory for class shift.\n");
+                to->touch->num_touches = from->touch->num_touches;
+                to->touch->touches = calloc(to->touch->num_touches,
+                                            sizeof(TouchPointInfoRec));
+                for (i = 0; i < to->touch->num_touches; i++)
+                    TouchInitTouchPoint(to->touch, to->valuator, i);
+                if (!to->touch)
+                    FatalError("[Xi] no memory for class shift.\n");
+            } else
+                classes->touch = NULL;
+        }
+        tmp = to->touch->touches;
+        memcpy(to->touch, from->touch, sizeof(TouchClassRec));
+        to->touch->touches = tmp;
+        to->touch->sourceid = from->id;
+    } else if (to->touch)
+    {
+        ClassesPtr classes;
+        classes = to->unused_classes;
+        classes->touch = to->touch;
+        to->touch      = NULL;
+    }
 }
 
 /**
diff --git a/Xi/xiquerydevice.c b/Xi/xiquerydevice.c
index 5f543f6..0879080 100644
--- a/Xi/xiquerydevice.c
+++ b/Xi/xiquerydevice.c
@@ -240,6 +240,8 @@ SizeDeviceClasses(DeviceIntPtr dev)
         }
     }
 
+    if (dev->touch)
+        len += sizeof(xXITouchInfo);
 
     return len;
 }
@@ -427,6 +429,31 @@ SwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo* info)
     swapl(&info->increment.frac);
 }
 
+/**
+ * List multitouch information
+ *
+ * @return The number of bytes written into info.
+ */
+int
+ListTouchInfo(DeviceIntPtr dev, xXITouchInfo *touch)
+{
+    touch->type = XITouchClass;
+    touch->length = sizeof(xXITouchInfo) >> 2;
+    touch->sourceid = touch->sourceid;
+    touch->mode = dev->touch->mode;
+    touch->num_touches = dev->touch->num_touches;
+
+    return touch->length << 2;
+}
+
+static void
+SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo* touch)
+{
+    swaps(&touch->type);
+    swaps(&touch->length);
+    swaps(&touch->sourceid);
+}
+
 int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment)
 {
     DeviceIntPtr master = GetMaster(dev, MASTER_ATTACHED);
@@ -525,6 +552,14 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
         total_len += len;
     }
 
+    if (dev->touch)
+    {
+        (*nclasses)++;
+        len = ListTouchInfo(dev, (xXITouchInfo*)any);
+        any += len;
+        total_len += len;
+    }
+
     return total_len;
 }
 
@@ -554,6 +589,10 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info)
             case XIScrollClass:
                 SwapScrollInfo(dev, (xXIScrollInfo*)any);
                 break;
+            case XITouchClass:
+                SwapTouchInfo(dev, (xXITouchInfo*)any);
+                break;
+
         }
 
         any += len * 4;
diff --git a/Xi/xiquerydevice.h b/Xi/xiquerydevice.h
index 9db6aa2..632c42e 100644
--- a/Xi/xiquerydevice.h
+++ b/Xi/xiquerydevice.h
@@ -45,4 +45,5 @@ int ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info);
 int ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info,
 		     int axisnumber, Bool reportState);
 int ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo* info, int axisnumber);
+int ListTouchInfo(DeviceIntPtr dev, xXITouchInfo* info);
 #endif /* QUERYDEV_H */
diff --git a/dix/Makefile.am b/dix/Makefile.am
index f5af619..b7358aa 100644
--- a/dix/Makefile.am
+++ b/dix/Makefile.am
@@ -39,6 +39,7 @@ libdix_la_SOURCES = 	\
 	swaprep.c	\
 	swapreq.c	\
 	tables.c	\
+	touch.c		\
 	window.c
 
 EXTRA_DIST = buildatoms BuiltInAtoms Xserver.d Xserver-dtrace.h.in
diff --git a/dix/devices.c b/dix/devices.c
index 9ca8fe0..7478ad6 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -263,6 +263,7 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart)
 	return (DeviceIntPtr)NULL;
 
     dev->last.scroll = NULL;
+    dev->last.touches = NULL;
     dev->id = devid;
     dev->public.processInputProc = ProcessOtherEvent;
     dev->public.realInputProc = ProcessOtherEvent;
@@ -761,6 +762,21 @@ FreeDeviceClass(int type, pointer *class)
                 free((*v));
                 break;
             }
+        case XITouchClass:
+            {
+                TouchClassPtr *t = (TouchClassPtr*)class;
+                int i;
+
+                for (i = 0; i < (*t)->num_touches; i++)
+                {
+                    free((*t)->touches[i].sprite.spriteTrace);
+                    free((*t)->touches[i].listeners);
+                    free((*t)->touches[i].valuators);
+                }
+
+                free((*t));
+                break;
+            }
         case FocusClass:
             {
                 FocusClassPtr *f = (FocusClassPtr*)class;
@@ -869,6 +885,7 @@ FreeAllDeviceClasses(ClassesPtr classes)
 
     FreeDeviceClass(KeyClass, (pointer)&classes->key);
     FreeDeviceClass(ValuatorClass, (pointer)&classes->valuator);
+    FreeDeviceClass(XITouchClass, (pointer)&classes->touch);
     FreeDeviceClass(ButtonClass, (pointer)&classes->button);
     FreeDeviceClass(FocusClass, (pointer)&classes->focus);
     FreeDeviceClass(ProximityClass, (pointer)&classes->proximity);
@@ -948,6 +965,9 @@ CloseDevice(DeviceIntPtr dev)
     free(dev->deviceGrab.sync.event);
     free(dev->config_info);     /* Allocated in xf86ActivateDevice. */
     free(dev->last.scroll);
+    for (j = 0; j < dev->last.num_touches; j++)
+        free(dev->last.touches[j].valuators);
+    free(dev->last.touches);
     dev->config_info = NULL;
     dixFreeObjectWithPrivates(dev, PRIVATE_DEVICE);
 }
@@ -1419,7 +1439,6 @@ InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc)
     return TRUE;
 }
 
-
 static LedCtrl defaultLedControl = {
 	DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0};
 
@@ -1542,6 +1561,72 @@ InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, Atom* btn_
 	   InitPtrFeedbackClassDeviceStruct(dev, controlProc));
 }
 
+/**
+ * Sets up multitouch capabilities on @device.
+ *
+ * @max_touches The maximum number of simultaneous touches, or 0 for unlimited.
+ * @mode The mode of the touch device (XIDirectTouch or XIDependentTouch).
+ * @num_axes The number of touch valuator axes.
+ */
+Bool
+InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches,
+                           unsigned int mode, unsigned int num_axes)
+{
+    TouchClassPtr touch;
+    int i;
+
+    if (device->touch || !device->valuator)
+        return FALSE;
+
+    /* Check the mode is valid, and at least X and Y axes. */
+    if (mode != XIDirectTouch && mode != XIDependentTouch)
+        return FALSE;
+    if (num_axes < 2)
+        return FALSE;
+
+    if (num_axes > MAX_VALUATORS)
+    {
+        LogMessage(X_WARNING,
+                   "Device '%s' has %d touch axes, only using first %d.\n",
+                   device->name, num_axes, MAX_VALUATORS);
+        num_axes = MAX_VALUATORS;
+    }
+
+    touch = calloc(1, sizeof(*touch));
+    if (!touch)
+        return FALSE;
+
+    touch->max_touches = max_touches;
+    if (max_touches == 0)
+        max_touches = 5; /* arbitrary number plucked out of the air */
+    touch->touches = calloc(max_touches, sizeof(*touch->touches));
+    if (!touch->touches)
+        goto err;
+    touch->num_touches = max_touches;
+    for (i = 0; i < max_touches; i++)
+        TouchInitTouchPoint(touch, device->valuator, i);
+
+    touch->mode = mode;
+    touch->sourceid = device->id;
+
+    device->touch = touch;
+    device->last.touches = calloc(max_touches, sizeof(*device->last.touches));
+    device->last.num_touches = touch->num_touches;
+    for (i = 0; i < touch->num_touches; i++)
+        TouchInitDDXTouchPoint(device, &device->last.touches[i]);
+
+    return TRUE;
+
+err:
+    for (i = 0; i < touch->num_touches; i++)
+        TouchFreeTouchPoint(device, i);
+
+    free(touch->touches);
+    free(touch);
+
+    return FALSE;
+}
+
 /*
  * Check if the given buffer contains elements between low (inclusive) and
  * high (inclusive) only.
diff --git a/dix/touch.c b/dix/touch.c
new file mode 100644
index 0000000..9fa2f3c
--- /dev/null
+++ b/dix/touch.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2011 Collabra Ltd.
+ * Copyright © 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Daniel Stone <daniel at fooishbar.org>
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "inputstr.h"
+#include "scrnintstr.h"
+
+
+void
+TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch)
+{
+    memset(ddxtouch, 0, sizeof(*ddxtouch));
+    ddxtouch->valuators = valuator_mask_new(dev->valuator->numAxes);
+}
+
+
+Bool
+TouchInitTouchPoint(TouchClassPtr t, ValuatorClassPtr v, int index)
+{
+    TouchPointInfoPtr ti;
+
+    if (index >= t->num_touches)
+        return FALSE;
+    ti = &t->touches[index];
+
+    memset(ti, 0, sizeof(*ti));
+
+    ti->valuators = valuator_mask_new(v->numAxes);
+    if (!ti->valuators)
+        return FALSE;
+
+    ti->sprite.spriteTrace = calloc(32, sizeof(*ti->sprite.spriteTrace));
+    if (!ti->sprite.spriteTrace)
+    {
+        valuator_mask_free(&ti->valuators);
+        return FALSE;
+    }
+    ti->sprite.spriteTraceSize = 32;
+    ti->sprite.spriteTrace[0] = screenInfo.screens[0]->root;
+    ti->sprite.hot.pScreen = screenInfo.screens[0];
+    ti->sprite.hotPhys.pScreen = screenInfo.screens[0];
+
+    ti->client_id = -1;
+
+    return TRUE;
+}
+
+void
+TouchFreeTouchPoint(DeviceIntPtr device, int index)
+{
+    TouchPointInfoPtr ti;
+
+    if (!device->touch || index >= device->touch->num_touches)
+        return;
+    ti = &device->touch->touches[index];
+
+    valuator_mask_free(&ti->valuators);
+    free(ti->sprite.spriteTrace);
+    ti->sprite.spriteTrace = NULL;
+    free(ti->listeners);
+    ti->listeners = NULL;
+    free(ti->history);
+    ti->history = NULL;
+    ti->history_size = 0;
+    ti->history_elements = 0;
+}
+
+
diff --git a/include/input.h b/include/input.h
index a94ff94..0d31edf 100644
--- a/include/input.h
+++ b/include/input.h
@@ -124,6 +124,9 @@ typedef struct _DeviceIntRec *DeviceIntPtr;
 typedef struct _ValuatorClassRec *ValuatorClassPtr;
 typedef struct _ClassesRec *ClassesPtr;
 typedef struct _SpriteRec *SpritePtr;
+typedef struct _TouchClassRec *TouchClassPtr;
+typedef struct _TouchPointInfo *TouchPointInfoPtr;
+typedef struct _DDXTouchPointInfo *DDXTouchPointInfoPtr;
 typedef union _GrabMask GrabMask;
 
 typedef struct _ValuatorMask ValuatorMask;
@@ -324,6 +327,12 @@ extern _X_EXPORT Bool InitPointerAccelerationScheme(
 extern _X_EXPORT Bool InitFocusClassDeviceStruct(
     DeviceIntPtr /*device*/);
 
+extern _X_EXPORT Bool InitTouchClassDeviceStruct(
+    DeviceIntPtr /*device*/,
+    unsigned int /*max_touches*/,
+    unsigned int /*mode*/,
+    unsigned int /*numAxes*/);
+
 typedef void (*BellProcPtr)(
     int /*percent*/,
     DeviceIntPtr /*device*/,
@@ -563,6 +572,24 @@ extern void SendDevicePresenceEvent(int deviceid, int type);
 extern _X_EXPORT InputAttributes *DuplicateInputAttributes(InputAttributes *attrs);
 extern _X_EXPORT void FreeInputAttributes(InputAttributes *attrs);
 
+enum TouchListenerState{
+    LISTENER_AWAITING_BEGIN = 0,   /**< Waiting for a TouchBegin event */
+    LISTENER_AWAITING_OWNER,       /**< Waiting for a TouchOwnership event */
+    LISTENER_IS_OWNER,             /**< Is the current owner */
+    LISTENER_HAS_END,              /**< Has already received the end event */
+};
+
+enum TouchListenerType {
+    LISTENER_GRAB,
+    LISTENER_POINTER_GRAB,
+    LISTENER_REGULAR,
+    LISTENER_POINTER_REGULAR,
+};
+
+extern void TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch);
+extern Bool TouchInitTouchPoint(TouchClassPtr touch, ValuatorClassPtr v, int index);
+extern void TouchFreeTouchPoint(DeviceIntPtr dev, int index);
+
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients);
 extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event);
diff --git a/include/inputstr.h b/include/inputstr.h
index e684798..9881c7e 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -300,6 +300,55 @@ typedef struct _ValuatorClassRec {
     int                   v_scroll_axis; /* vert smooth-scrolling axis */
 } ValuatorClassRec;
 
+typedef struct _TouchPointInfo {
+    /* client_id must be first element, see GetTouchEvents */
+    uint32_t    client_id;          /* touch ID as seen in client events */
+    int         sourceid;           /* Source device's ID for this touchpoint */
+    Bool        active;             /* whether or not the touch is active */
+    Bool        pending_finish;     /* true if the touch is physically inactive
+                                     * but still owned by a grab */
+    SpriteRec   sprite;             /* window trace for delivery */
+    ValuatorMask *valuators;        /* last recorded axis values */
+    struct _TouchListener {
+        XID         listener;           /* grabs/event selection IDs receiving
+                                         * events for this touch */
+        enum TouchListenerType type;
+        enum TouchListenerState state;
+        enum InputLevel level;      /* matters only for emulating touches */
+    } *listeners;
+    int         num_listeners;
+    int         num_grabs;          /* number of open grabs on this touch
+                                     * which have not accepted or rejected */
+    Bool        emulate_pointer;
+    DeviceEvent *history;           /* History of events on this touchpoint */
+    size_t      history_elements;   /* Number of current elements in history */
+    size_t      history_size;       /* Size of history in elements */
+} TouchPointInfoRec;
+
+typedef struct _TouchListener TouchListener;
+
+typedef struct _DDXTouchPointInfo {
+    /* client_id must be first element, see GetTouchEvents */
+    uint32_t    client_id;          /* touch ID as seen in client events */
+    Bool        active;             /* whether or not the touch is active */
+    uint32_t    ddx_id;             /* touch ID given by the DDX */
+    Bool        emulate_pointer;
+
+    ValuatorMask* valuators;        /* last recorded axis values */
+} DDXTouchPointInfoRec;
+
+typedef struct _TouchClassRec {
+    int                sourceid;
+    TouchPointInfoPtr  touches;
+    unsigned short     num_touches;    /* number of allocated touches */
+    unsigned short     max_touches;    /* maximum number of touches, may be 0 */
+    CARD8              mode;           /* ::XIDirectTouch, XIDependentTouch */
+    /* for pointer-emulation */
+    CARD8              buttonsDown;    /* number of buttons down */
+    unsigned short     state;          /* logical button state */
+    Mask               motionMask;
+} TouchClassRec;
+
 typedef struct _ButtonClassRec {
     int			sourceid;
     CARD8		numButtons;
@@ -383,6 +432,7 @@ typedef struct _LedFeedbackClassRec {
 typedef struct _ClassesRec {
     KeyClassPtr		key;
     ValuatorClassPtr	valuator;
+    TouchClassPtr	touch;
     ButtonClassPtr	button;
     FocusClassPtr	focus;
     ProximityClassPtr	proximity;
@@ -510,6 +560,7 @@ typedef struct _DeviceIntRec {
     int			id;
     KeyClassPtr		key;
     ValuatorClassPtr	valuator;
+    TouchClassPtr	touch;
     ButtonClassPtr	button;
     FocusClassPtr	focus;
     ProximityClassPtr	proximity;
@@ -541,6 +592,8 @@ typedef struct _DeviceIntRec {
         int             numValuators;
         DeviceIntPtr    slave;
         ValuatorMask    *scroll;
+        int             num_touches; /* size of the touches array */
+        DDXTouchPointInfoPtr touches;
     } last;
 
     /* Input device property handling. */
commit 098b837440e40bbc485368ec9658e12efd6ef581
Author: Daniel Stone <daniel at fooishbar.org>
Date:   Wed Dec 14 14:41:48 2011 +1000

    Add the touch input API stubs
    
    xf86PostTouchEvent is the driver API to submit touch events to the server.
    This API doesn't do anything yet though but now we can at least bump the
    API.
    
    For valuators, drivers should use the existing xf86InitValuatorAxisStruct
    function.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/getevents.c b/dix/getevents.c
index d7d6c09..39f8ca7 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -1632,6 +1632,54 @@ GetProximityEvents(InternalEvent *events, DeviceIntPtr pDev, int type, const Val
 }
 
 /**
+ * Generate internal events representing this touch event and enqueue them
+ * on the event queue.
+ *
+ * This function is not reentrant. Disable signals before calling.
+ *
+ * @param device The device to generate the event for
+ * @param type Event type, one of XI_TouchBegin, XI_TouchUpdate, XI_TouchEnd
+ * @param touchid Touch point ID
+ * @param flags Event modification flags
+ * @param mask Valuator mask for valuators present for this event.
+ */
+void
+QueueTouchEvents(DeviceIntPtr device, int type,
+                 uint32_t ddx_touchid, int flags, const ValuatorMask *mask)
+{
+    int nevents;
+
+    nevents = GetTouchEvents(InputEventList, device, ddx_touchid, type, flags, mask);
+    queueEventList(device, InputEventList, nevents);
+}
+
+/**
+ * Get events for a touch. Generates a TouchBegin event if end is not set and
+ * the touch id is not active. Generates a TouchUpdate event if end is not set
+ * and the touch id is active. Generates a TouchEnd event if end is set and the
+ * touch id is active.
+ *
+ * events is not NULL-terminated; the return value is the number of events.
+ * The DDX is responsible for allocating the event structure in the first
+ * place via GetMaximumEventsNum(), and for freeing it.
+ *
+ * @param[out] events The list of events generated
+ * @param dev The device to generate the events for
+ * @param ddx_touchid The touch ID as assigned by the DDX
+ * @param type XI_TouchBegin, XI_TouchUpdate or XI_TouchEnd
+ * @param flags Event flags
+ * @param mask_in Valuator information for this event
+ */
+int
+GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
+               uint16_t type, uint32_t flags, const ValuatorMask *mask_in)
+{
+    return 0;
+}
+
+
+
+/**
  * Synthesize a single motion event for the core pointer.
  *
  * Used in cursor functions, e.g. when cursor confinement changes, and we need
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index b9753f0..280a6ec 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -1410,4 +1410,28 @@ xf86EnableDevice(DeviceIntPtr dev)
     EnableDevice(dev, TRUE);
 }
 
+/**
+ * Post a touch event with optional valuators.  If this is the first touch in
+ * the sequence, at least x & y valuators must be provided. The driver is
+ * responsible for maintaining the correct event sequence (TouchBegin, TouchUpdate,
+ * TouchEnd). Submitting an update or end event for a unregistered touchid will
+ * result in errors.
+ * Touch IDs may be reused by the driver but only after a TouchEnd has been
+ * submitted for that touch ID.
+ *
+ * @param dev The device to post the event for
+ * @param touchid The touchid of the current touch event. Must be an
+ * existing ID for TouchUpdate or TouchEnd events
+ * @param type One of XI_TouchBegin, XI_TouchUpdate, XI_TouchEnd
+ * @param flags Flags for this event
+ * @param The valuator mask with all valuators set for this event.
+ */
+void
+xf86PostTouchEvent(DeviceIntPtr dev, uint32_t touchid, uint16_t type,
+                   uint32_t flags, const ValuatorMask *mask)
+{
+
+    QueueTouchEvents(dev, type, touchid, flags, mask);
+}
+
 /* end of xf86Xinput.c */
diff --git a/hw/xfree86/common/xf86Xinput.h b/hw/xfree86/common/xf86Xinput.h
index 909fb57..851aeae 100644
--- a/hw/xfree86/common/xf86Xinput.h
+++ b/hw/xfree86/common/xf86Xinput.h
@@ -141,6 +141,9 @@ extern _X_EXPORT void xf86PostKeyEventP(DeviceIntPtr device, unsigned int key_co
 		       const int *valuators);
 extern _X_EXPORT void xf86PostKeyboardEvent(DeviceIntPtr device, unsigned int key_code,
                            int is_down);
+extern _X_EXPORT void xf86PostTouchEvent(DeviceIntPtr dev, uint32_t touchid,
+                                         uint16_t type, uint32_t flags,
+                                         const ValuatorMask *mask);
 extern _X_EXPORT InputInfoPtr xf86FirstLocalDevice(void);
 extern _X_EXPORT int xf86ScaleAxis(int Cx, int to_max, int to_min, int from_max, int from_min);
 extern _X_EXPORT void xf86ProcessCommonOptions(InputInfoPtr pInfo, XF86OptionPtr options);
diff --git a/include/input.h b/include/input.h
index 7a7e16b..a94ff94 100644
--- a/include/input.h
+++ b/include/input.h
@@ -480,6 +480,20 @@ extern _X_EXPORT void QueueKeyboardEvents(
     int key_code,
     const ValuatorMask *mask);
 
+extern int GetTouchEvents(
+    InternalEvent *events,
+    DeviceIntPtr pDev,
+    uint32_t ddx_touchid,
+    uint16_t type,
+    uint32_t flags,
+    const ValuatorMask *mask);
+
+void QueueTouchEvents(DeviceIntPtr device,
+                      int type,
+                      uint32_t ddx_touchid,
+                      int flags,
+                      const ValuatorMask *mask);
+
 extern _X_EXPORT int GetProximityEvents(
     InternalEvent *events,
     DeviceIntPtr pDev,
commit 93c2a1628a9f6e7480d834bf55c080997fd18911
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 13:51:12 2011 +1000

    Hook up the ownership events
    
    This patch applies most of the protocol conversions and the internal event
    type for ownership events.
    
    Note that ownership events are generated by the DIX only, they do not pass
    through the event queue.
    
    Co-authored-by: Daniel Stone <daniel at fooishbar.org>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/extinit.c b/Xi/extinit.c
index 0b7bc34..a81c8f1 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -829,6 +829,22 @@ static void SRawEvent(xXIRawEvent *from, xXIRawEvent *to)
     swaps(&to->valuators_len);
 }
 
+static void STouchOwnershipEvent(xXITouchOwnershipEvent *from,
+                                 xXITouchOwnershipEvent *to)
+{
+    *to = *from;
+    swaps(&to->sequenceNumber);
+    swapl(&to->length);
+    swaps(&to->evtype);
+    swaps(&to->deviceid);
+    swapl(&to->time);
+    swaps(&to->sourceid);
+    swapl(&to->touchid);
+    swapl(&to->flags);
+    swapl(&to->root);
+    swapl(&to->event);
+    swapl(&to->child);
+}
 
 /** Event swapping function for XI2 events. */
 void
@@ -863,6 +879,10 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
         case XI_TouchEnd:
             SDeviceEvent((xXIDeviceEvent*)from, (xXIDeviceEvent*)to);
             break;
+        case XI_TouchOwnership:
+            STouchOwnershipEvent((xXITouchOwnershipEvent*)from,
+                                 (xXITouchOwnershipEvent*)to);
+            break;
         case XI_RawMotion:
         case XI_RawKeyPress:
         case XI_RawKeyRelease:
diff --git a/dix/eventconvert.c b/dix/eventconvert.c
index 582769a..017c871 100644
--- a/dix/eventconvert.c
+++ b/dix/eventconvert.c
@@ -58,6 +58,7 @@ static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count);
 static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce);
 static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
 static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
+static int eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi);
 
 /* Do not use, read comments below */
 BOOL EventIsKeyRepeat(xEvent *event);
@@ -164,6 +165,7 @@ EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
         case ET_TouchBegin:
         case ET_TouchUpdate:
         case ET_TouchEnd:
+        case ET_TouchOwnership:
             ret = BadMatch;
             break;
         default:
@@ -220,6 +222,7 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count)
         case ET_TouchBegin:
         case ET_TouchUpdate:
         case ET_TouchEnd:
+        case ET_TouchOwnership:
             *count = 0;
             *xi = NULL;
             return BadMatch;
@@ -265,6 +268,8 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
         case ET_TouchUpdate:
         case ET_TouchEnd:
             return eventToDeviceEvent(&ev->device_event, xi);
+        case ET_TouchOwnership:
+            return eventToTouchOwnershipEvent(&ev->touch_ownership_event, xi);
         case ET_ProximityIn:
         case ET_ProximityOut:
             *xi = NULL;
@@ -722,6 +727,27 @@ eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
 }
 
 static int
+eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi)
+{
+    int len = sizeof(xXITouchOwnershipEvent);
+    xXITouchOwnershipEvent *xtoe;
+
+    *xi = calloc(1, len);
+    xtoe = (xXITouchOwnershipEvent*)*xi;
+    xtoe->type          = GenericEvent;
+    xtoe->extension     = IReqCode;
+    xtoe->length        = bytes_to_int32(len - sizeof(xEvent));
+    xtoe->evtype        = GetXI2Type(ev->type);
+    xtoe->deviceid      = ev->deviceid;
+    xtoe->time          = ev->time;
+    xtoe->sourceid      = ev->sourceid;
+    xtoe->touchid       = ev->touchid;
+    xtoe->flags         = 0; /* we don't have wire flags for ownership yet */
+
+    return Success;
+}
+
+static int
 eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
 {
     xXIRawEvent* raw;
@@ -844,6 +870,7 @@ GetXI2Type(enum EventType type)
         case ET_TouchBegin:     xi2type = XI_TouchBegin;       break;
         case ET_TouchEnd:       xi2type = XI_TouchEnd;         break;
         case ET_TouchUpdate:    xi2type = XI_TouchUpdate;      break;
+        case ET_TouchOwnership: xi2type = XI_TouchOwnership;   break;
         default:
             break;
     }
diff --git a/dix/events.c b/dix/events.c
index f80b8fd..f8ea94f 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -2476,6 +2476,13 @@ FixUpEventFromWindow(
 
         event->root = RootWindow(pSprite)->drawable.id;
         event->event = pWin->drawable.id;
+
+        if (evtype == XI_TouchOwnership)
+        {
+            event->child = child;
+            return;
+        }
+
         if (pSprite->hot.pScreen == pWin->drawable.pScreen)
         {
             event->event_x = event->root_x - FP1616(pWin->drawable.x, 0);
diff --git a/include/events.h b/include/events.h
index 375173a..222cc3d 100644
--- a/include/events.h
+++ b/include/events.h
@@ -26,6 +26,7 @@
 #define EVENTS_H
 typedef struct _DeviceEvent DeviceEvent;
 typedef struct _DeviceChangedEvent DeviceChangedEvent;
+typedef struct _TouchOwnershipEvent TouchOwnershipEvent;
 #if XFreeXDGA
 typedef struct _DGAEvent DGAEvent;
 #endif
diff --git a/include/eventstr.h b/include/eventstr.h
index 3323073..e4410a7 100644
--- a/include/eventstr.h
+++ b/include/eventstr.h
@@ -53,6 +53,7 @@ enum EventType {
     ET_TouchBegin,
     ET_TouchUpdate,
     ET_TouchEnd,
+    ET_TouchOwnership,
     ET_Enter,
     ET_Leave,
     ET_FocusIn,
@@ -123,6 +124,24 @@ struct _DeviceEvent
     uint32_t flags;   /**< Flags to be copied into the generated event */
 };
 
+/**
+ * Generated internally whenever a touch ownership chain changes - an owner
+ * has accepted or rejected a touch, or a grab/event selection in the delivery
+ * chain has been removed.
+ */
+struct _TouchOwnershipEvent
+{
+    unsigned char header; /**< Always ET_Internal */
+    enum EventType type;  /**< One of EventType */
+    int length;           /**< Length in bytes */
+    Time time;            /**< Time in ms */
+    int deviceid;         /**< Device to post this event for */
+    int sourceid;         /**< The physical source device */
+    uint32_t touchid;     /**< Touch ID (client_id) */
+    uint8_t reason;       /**< ::XIAcceptTouch, ::XIRejectTouch */
+    uint32_t resource;    /**< Provoking grab or event selection */
+    uint32_t flags;       /**< Flags to be copied into the generated event */
+};
 
 /* Flags used in DeviceChangedEvent to signal if the slave has changed */
 #define DEVCHANGE_SLAVE_SWITCH 0x2
@@ -238,6 +257,7 @@ union _InternalEvent {
         } any;
         DeviceEvent device_event;
         DeviceChangedEvent changed_event;
+        TouchOwnershipEvent touch_ownership_event;
 #if XFreeXDGA
         DGAEvent dga_event;
 #endif
diff --git a/mi/mieq.c b/mi/mieq.c
index 8335289..ea8bcf0 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -375,6 +375,9 @@ ChangeDeviceID(DeviceIntPtr dev, InternalEvent* event)
         case ET_TouchEnd:
             event->device_event.deviceid = dev->id;
             break;
+        case ET_TouchOwnership:
+            event->touch_ownership_event.deviceid = dev->id;
+            break;
 #if XFreeXDGA
         case ET_DGAEvent:
             break;
commit 3390d3fc0347947796aa245d70fefecf59b7bfe4
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 13:21:59 2011 +1000

    Xi: process raw touch events
    
    No-one can generated them yet, but if they could, we'd be processing them
    like there was no tomorrow.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index b05cf2c..2db6053 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1063,6 +1063,9 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
         case  ET_RawButtonPress:
         case  ET_RawButtonRelease:
         case  ET_RawMotion:
+        case  ET_RawTouchBegin:
+        case  ET_RawTouchUpdate:
+        case  ET_RawTouchEnd:
             DeliverRawEvent(&ev->raw_event, device);
             break;
         default:
diff --git a/Xi/extinit.c b/Xi/extinit.c
index 87f7933..0b7bc34 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -868,6 +868,9 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
         case XI_RawKeyRelease:
         case XI_RawButtonPress:
         case XI_RawButtonRelease:
+        case XI_RawTouchBegin:
+        case XI_RawTouchUpdate:
+        case XI_RawTouchEnd:
             SRawEvent((xXIRawEvent*)from, (xXIRawEvent*)to);
             break;
         default:
diff --git a/Xi/xiselectev.c b/Xi/xiselectev.c
index ee14edb..815a34f 100644
--- a/Xi/xiselectev.c
+++ b/Xi/xiselectev.c
@@ -145,7 +145,10 @@ ProcXISelectEvents(ClientPtr client)
                 BitIsOn(bits, XI_RawKeyRelease) ||
                 BitIsOn(bits, XI_RawButtonPress) ||
                 BitIsOn(bits, XI_RawButtonRelease) ||
-                BitIsOn(bits, XI_RawMotion))
+                BitIsOn(bits, XI_RawMotion) ||
+                BitIsOn(bits, XI_RawTouchBegin) ||
+                BitIsOn(bits, XI_RawTouchUpdate) ||
+                BitIsOn(bits, XI_RawTouchEnd))
             {
                 client->errorValue = XI_RawKeyPress;
                 return BadValue;
diff --git a/dix/eventconvert.c b/dix/eventconvert.c
index 3802ea1..582769a 100644
--- a/dix/eventconvert.c
+++ b/dix/eventconvert.c
@@ -158,6 +158,9 @@ EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
         case ET_RawButtonPress:
         case ET_RawButtonRelease:
         case ET_RawMotion:
+        case ET_RawTouchBegin:
+        case ET_RawTouchUpdate:
+        case ET_RawTouchEnd:
         case ET_TouchBegin:
         case ET_TouchUpdate:
         case ET_TouchEnd:
@@ -211,6 +214,9 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count)
         case ET_RawButtonPress:
         case ET_RawButtonRelease:
         case ET_RawMotion:
+        case ET_RawTouchBegin:
+        case ET_RawTouchUpdate:
+        case ET_RawTouchEnd:
         case ET_TouchBegin:
         case ET_TouchUpdate:
         case ET_TouchEnd:
@@ -270,6 +276,9 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
         case ET_RawButtonPress:
         case ET_RawButtonRelease:
         case ET_RawMotion:
+        case ET_RawTouchBegin:
+        case ET_RawTouchUpdate:
+        case ET_RawTouchEnd:
             return eventToRawEvent(&ev->raw_event, xi);
         default:
             break;
@@ -827,6 +836,9 @@ GetXI2Type(enum EventType type)
         case ET_RawButtonPress: xi2type = XI_RawButtonPress;   break;
         case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break;
         case ET_RawMotion:      xi2type = XI_RawMotion;        break;
+        case ET_RawTouchBegin:  xi2type = XI_RawTouchBegin;    break;
+        case ET_RawTouchUpdate: xi2type = XI_RawTouchUpdate;  break;
+        case ET_RawTouchEnd:    xi2type = XI_RawTouchEnd;      break;
         case ET_FocusIn:        xi2type = XI_FocusIn;          break;
         case ET_FocusOut:       xi2type = XI_FocusOut;         break;
         case ET_TouchBegin:     xi2type = XI_TouchBegin;       break;
diff --git a/dix/events.c b/dix/events.c
index 2b54969..f80b8fd 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -2463,6 +2463,9 @@ FixUpEventFromWindow(
             case XI_RawButtonPress:
             case XI_RawButtonRelease:
             case XI_RawMotion:
+            case XI_RawTouchBegin:
+            case XI_RawTouchUpdate:
+            case XI_RawTouchEnd:
             case XI_DeviceChanged:
             case XI_HierarchyChanged:
             case XI_PropertyEvent:
diff --git a/dix/getevents.c b/dix/getevents.c
index ea62ca8..d7d6c09 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -161,7 +161,16 @@ init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail)
     memset(event, 0, sizeof(RawDeviceEvent));
     event->header = ET_Internal;
     event->length = sizeof(RawDeviceEvent);
-    event->type = ET_RawKeyPress - ET_KeyPress + type;
+    switch(type) {
+        case MotionNotify:      event->type = ET_RawMotion; break;
+        case ButtonPress:       event->type = ET_RawButtonPress; break;
+        case ButtonRelease:     event->type = ET_RawButtonRelease; break;
+        case KeyPress:          event->type = ET_RawKeyPress; break;
+        case KeyRelease:        event->type = ET_RawKeyRelease; break;
+        case XI_TouchBegin:     event->type = ET_RawTouchBegin; break;
+        case XI_TouchUpdate:    event->type = ET_RawTouchUpdate; break;
+        case XI_TouchEnd:       event->type = ET_RawTouchEnd; break;
+    }
     event->time = ms;
     event->deviceid = dev->id;
     event->sourceid = dev->id;
diff --git a/include/eventstr.h b/include/eventstr.h
index 9626076..3323073 100644
--- a/include/eventstr.h
+++ b/include/eventstr.h
@@ -67,6 +67,9 @@ enum EventType {
     ET_RawButtonPress,
     ET_RawButtonRelease,
     ET_RawMotion,
+    ET_RawTouchBegin,
+    ET_RawTouchUpdate,
+    ET_RawTouchEnd,
     ET_XQuartz,
     ET_Internal = 0xFF /* First byte */
 };
diff --git a/mi/mieq.c b/mi/mieq.c
index 06c3d8e..8335289 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -384,6 +384,9 @@ ChangeDeviceID(DeviceIntPtr dev, InternalEvent* event)
         case ET_RawButtonPress:
         case ET_RawButtonRelease:
         case ET_RawMotion:
+        case ET_RawTouchBegin:
+        case ET_RawTouchEnd:
+        case ET_RawTouchUpdate:
             event->raw_event.deviceid = dev->id;
             break;
         default:
commit 84db813b9db34975b5fe288a8a551bb98f0cc1c1
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 12:45:28 2011 +1000

    Hook up TouchBegin/Update/End events
    
    The are the same as device events internally but require the touch ID
    separately from the detail.button field (the protocol uses the detail field
    for the touch id).
    For simpler integration of pointer emulation we need to set the
    detail.button field while keeping the touchid around.
    
    Add the three new touch event types to the various places in the server
    where they need to be handled. The actual handling of the events is somewhat
    more complicated in most places.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 1e16b74..b05cf2c 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -128,6 +128,21 @@ IsPointerEvent(InternalEvent* event)
     return FALSE;
 }
 
+Bool
+IsTouchEvent(InternalEvent* event)
+{
+    switch(event->any.type)
+    {
+        case ET_TouchBegin:
+        case ET_TouchUpdate:
+        case ET_TouchEnd:
+            return TRUE;
+        default:
+            break;
+    }
+    return FALSE;
+}
+
 /**
  * @return the device matching the deviceid of the device set in the event, or
  * NULL if the event is not an XInput event.
diff --git a/Xi/extinit.c b/Xi/extinit.c
index b43f9bb..87f7933 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -858,6 +858,9 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
         case XI_KeyRelease:
         case XI_ButtonPress:
         case XI_ButtonRelease:
+        case XI_TouchBegin:
+        case XI_TouchUpdate:
+        case XI_TouchEnd:
             SDeviceEvent((xXIDeviceEvent*)from, (xXIDeviceEvent*)to);
             break;
         case XI_RawMotion:
diff --git a/dix/eventconvert.c b/dix/eventconvert.c
index 67b420a..3802ea1 100644
--- a/dix/eventconvert.c
+++ b/dix/eventconvert.c
@@ -158,6 +158,9 @@ EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
         case ET_RawButtonPress:
         case ET_RawButtonRelease:
         case ET_RawMotion:
+        case ET_TouchBegin:
+        case ET_TouchUpdate:
+        case ET_TouchEnd:
             ret = BadMatch;
             break;
         default:
@@ -208,6 +211,9 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count)
         case ET_RawButtonPress:
         case ET_RawButtonRelease:
         case ET_RawMotion:
+        case ET_TouchBegin:
+        case ET_TouchUpdate:
+        case ET_TouchEnd:
             *count = 0;
             *xi = NULL;
             return BadMatch;
@@ -249,6 +255,9 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
         case ET_ButtonRelease:
         case ET_KeyPress:
         case ET_KeyRelease:
+        case ET_TouchBegin:
+        case ET_TouchUpdate:
+        case ET_TouchEnd:
             return eventToDeviceEvent(&ev->device_event, xi);
         case ET_ProximityIn:
         case ET_ProximityOut:
@@ -650,7 +659,11 @@ eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
     xde->evtype         = GetXI2Type(ev->type);
     xde->time           = ev->time;
     xde->length         = bytes_to_int32(len - sizeof(xEvent));
-    xde->detail         = ev->detail.button;
+    if (IsTouchEvent((InternalEvent*)ev))
+        xde->detail     = ev->touchid;
+    else
+        xde->detail     = ev->detail.button;
+
     xde->root           = ev->root;
     xde->buttons_len    = btlen;
     xde->valuators_len  = vallen;
@@ -659,7 +672,11 @@ eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
     xde->root_x         = FP1616(ev->root_x, ev->root_x_frac);
     xde->root_y         = FP1616(ev->root_y, ev->root_y_frac);
 
-    xde->flags          = ev->flags;
+    if (ev->type == ET_TouchUpdate)
+        xde->flags |= (ev->flags & TOUCH_PENDING_END) ? XITouchPendingEnd : 0;
+    else
+        xde->flags = ev->flags;
+
     if (ev->key_repeat)
         xde->flags      |= XIKeyRepeat;
 
@@ -812,6 +829,9 @@ GetXI2Type(enum EventType type)
         case ET_RawMotion:      xi2type = XI_RawMotion;        break;
         case ET_FocusIn:        xi2type = XI_FocusIn;          break;
         case ET_FocusOut:       xi2type = XI_FocusOut;         break;
+        case ET_TouchBegin:     xi2type = XI_TouchBegin;       break;
+        case ET_TouchEnd:       xi2type = XI_TouchEnd;         break;
+        case ET_TouchUpdate:    xi2type = XI_TouchUpdate;      break;
         default:
             break;
     }
diff --git a/dix/events.c b/dix/events.c
index 8dff299..2b54969 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -2978,6 +2978,9 @@ CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev)
             case ET_ButtonPress:
             case ET_ButtonRelease:
             case ET_Motion:
+            case ET_TouchBegin:
+            case ET_TouchUpdate:
+            case ET_TouchEnd:
                 break;
             default:
                 /* all other events return FALSE */
diff --git a/include/dix.h b/include/dix.h
index 9b9dc4b..7043201 100644
--- a/include/dix.h
+++ b/include/dix.h
@@ -582,6 +582,7 @@ extern Bool DevHasCursor(DeviceIntPtr pDev);
 extern _X_EXPORT Bool IsPointerDevice(DeviceIntPtr dev);
 extern _X_EXPORT Bool IsKeyboardDevice(DeviceIntPtr dev);
 extern Bool IsPointerEvent(InternalEvent *event);
+extern Bool IsTouchEvent(InternalEvent *event);
 extern _X_EXPORT Bool IsMaster(DeviceIntPtr dev);
 extern _X_EXPORT Bool IsFloating(DeviceIntPtr dev);
 
diff --git a/include/eventstr.h b/include/eventstr.h
index 4d836fb..9626076 100644
--- a/include/eventstr.h
+++ b/include/eventstr.h
@@ -50,6 +50,9 @@ enum EventType {
     ET_ButtonPress,
     ET_ButtonRelease,
     ET_Motion,
+    ET_TouchBegin,
+    ET_TouchUpdate,
+    ET_TouchEnd,
     ET_Enter,
     ET_Leave,
     ET_FocusIn,
@@ -84,9 +87,11 @@ struct _DeviceEvent
     int deviceid;         /**< Device to post this event for */
     int sourceid;         /**< The physical source device */
     union {
-        uint32_t button;  /**< Button number */
+        uint32_t button;  /**< Button number (also used in pointer emulating
+                               touch events) */
         uint32_t key;     /**< Key code */
     } detail;
+    uint32_t touchid;     /**< Touch ID (client_id) */
     int16_t root_x;       /**< Pos relative to root window in integral data */
     float root_x_frac;    /**< Pos relative to root window in frac part */
     int16_t root_y;       /**< Pos relative to root window in integral part */
diff --git a/mi/mieq.c b/mi/mieq.c
index 093dba2..06c3d8e 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -370,6 +370,9 @@ ChangeDeviceID(DeviceIntPtr dev, InternalEvent* event)
         case ET_ProximityOut:
         case ET_Hierarchy:
         case ET_DeviceChanged:
+        case ET_TouchBegin:
+        case ET_TouchUpdate:
+        case ET_TouchEnd:
             event->device_event.deviceid = dev->id;
             break;
 #if XFreeXDGA
commit 92a5862d0c120b009a688237ec7142b7c21ae272
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 15:00:33 2011 +1000

    include: add a bunch of flags for GetTouchEvent processing
    
    TOUCH_CLIENT_ID is set if the touch was generated from a client ID instead
    of a DDX/driver touch ID. i.e. submitted by the dix.
    
    TOUCH_END is a special flag that's required to force the touch to end.
    Since the protocol with grab replaying and pointer emulation is rather
    complex, it's quite hard to know otherwise when a touch sequence should
    really die.
    
    The others do what it says on the imaginary box.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/include/input.h b/include/input.h
index bd12f68..7a7e16b 100644
--- a/include/input.h
+++ b/include/input.h
@@ -71,6 +71,15 @@ SOFTWARE.
 #define POINTER_NORAW		(1 << 5)	/* Don't generate RawEvents */
 #define POINTER_EMULATED	(1 << 6)	/* Event was emulated from another event */
 
+/* GetTouchEvent flags */
+#define TOUCH_ACCEPT            (1 << 0)
+#define TOUCH_REJECT            (1 << 1)
+#define TOUCH_PENDING_END       (1 << 2)
+#define TOUCH_CLIENT_ID         (1 << 3)        /* touch ID is the client-visible id */
+#define TOUCH_REPLAYING         (1 << 4)        /* event is being replayed */
+#define TOUCH_POINTER_EMULATED  (1 << 5)        /* touch event may be pointer emulated */
+#define TOUCH_END               (1 << 6)        /* really end this touch now */
+
 /*int constants for pointer acceleration schemes*/
 #define PtrAccelNoOp            0
 #define PtrAccelPredictable     1
commit 956a97487beada8cf5f354550ff779635cc64361
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 12:19:27 2011 +1000

    include: RawTouchEnd is the last event now
    
    Plus, use the actual definition from the protocol instead of the numeric
    values. Turns out not everyone knows the protocol event IDs by heart.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/include/inputstr.h b/include/inputstr.h
index 5aae1b5..e684798 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -49,6 +49,8 @@ SOFTWARE.
 #ifndef INPUTSTRUCT_H
 #define INPUTSTRUCT_H
 
+#include <X11/extensions/XI2proto.h>
+
 #include <pixman.h>
 #include "input.h"
 #include "window.h"
@@ -71,7 +73,7 @@ extern _X_EXPORT int CountBits(const uint8_t *mask, int len);
  * events to the protocol, the server will not support these events until
  * this number here is bumped.
  */
-#define XI2LASTEVENT    17 /* XI_RawMotion */
+#define XI2LASTEVENT    XI_RawTouchEnd
 #define XI2MASKSIZE     ((XI2LASTEVENT >> 3) + 1) /* no of bytes for masks */
 
 /**
commit 92c6c0c1d2d6a8882ed97b0e7f2952978ee5ce82
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 12:15:29 2011 +1000

    tests: update for touch support
    
    Touch event mask must be set for all three event types.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/test/xi2/protocol-xipassivegrabdevice.c b/test/xi2/protocol-xipassivegrabdevice.c
index 89ffc3d..b405556 100644
--- a/test/xi2/protocol-xipassivegrabdevice.c
+++ b/test/xi2/protocol-xipassivegrabdevice.c
@@ -180,7 +180,7 @@ static void test_XIPassiveGrabDevice(void)
     request->deviceid = XIAllMasterDevices;
 
     printf("Testing invalid grab types\n");
-    for (i = XIGrabtypeFocusIn + 1; i < 0xFF; i++)
+    for (i = XIGrabtypeTouchBegin + 1; i < 0xFF; i++)
     {
         request->grab_type = i;
         request_XIPassiveGrabDevice(&client_request, request, BadValue, request->grab_type);
diff --git a/test/xi2/protocol-xiselectevents.c b/test/xi2/protocol-xiselectevents.c
index 4eaf839..0390858 100644
--- a/test/xi2/protocol-xiselectevents.c
+++ b/test/xi2/protocol-xiselectevents.c
@@ -125,6 +125,28 @@ static void request_XISelectEvent(xXISelectEventsReq *req, int error)
     assert(rc == error);
 }
 
+static void _set_bit(unsigned char *bits, int bit)
+{
+    SetBit(bits, bit);
+    if (bit >= XI_TouchBegin && bit <= XI_TouchOwnership)
+    {
+        SetBit(bits, XI_TouchBegin);
+        SetBit(bits, XI_TouchUpdate);
+        SetBit(bits, XI_TouchEnd);
+    }
+}
+
+static void _clear_bit(unsigned char *bits, int bit)
+{
+    ClearBit(bits, bit);
+    if (bit >= XI_TouchBegin && bit <= XI_TouchOwnership)
+    {
+        ClearBit(bits, XI_TouchBegin);
+        ClearBit(bits, XI_TouchUpdate);
+        ClearBit(bits, XI_TouchEnd);
+    }
+}
+
 static void request_XISelectEvents_masks(xXISelectEventsReq *req)
 {
     int i, j;
@@ -157,9 +179,9 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req)
         memset(bits, 0, mask->mask_len * 4);
         for (j = 0; j <= XI2LASTEVENT; j++)
         {
-            SetBit(bits, j);
+            _set_bit(bits, j);
             request_XISelectEvent(req, Success);
-            ClearBit(bits, j);
+            _clear_bit(bits, j);
         }
 
         /* Test 2:
@@ -173,7 +195,7 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req)
 
         for (j = 0; j <= XI2LASTEVENT; j++)
         {
-            SetBit(bits, j);
+            _set_bit(bits, j);
             request_XISelectEvent(req, Success);
         }
 
@@ -187,9 +209,9 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req)
 
         for (j = XI2LASTEVENT + 1; j < mask->mask_len * 4; j++)
         {
-            SetBit(bits, j);
+            _set_bit(bits, j);
             request_XISelectEvent(req, BadValue);
-            ClearBit(bits, j);
+            _clear_bit(bits, j);
         }
 
         /* Test 4:
@@ -200,7 +222,7 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req)
         memset(bits, 0, mask->mask_len * 4);
         for (j = 0; j <= XI2LASTEVENT; j++)
         {
-            SetBit(bits, j);
+            _set_bit(bits, j);
             request_XISelectEvent(req, Success);
         }
 
@@ -227,8 +249,8 @@ static void request_XISelectEvents_masks(xXISelectEventsReq *req)
         mask->mask_len = (nmasks + 3)/4;
         memset(bits, 0, mask->mask_len * 4);
         for (j = 0; j <= XI2LASTEVENT; j++)
-            SetBit(bits, j);
-        ClearBit(bits, XI_HierarchyChanged);
+            _set_bit(bits, j);
+        _clear_bit(bits, XI_HierarchyChanged);
         for (j = 1; j < 6; j++)
         {
             mask->deviceid = j;
commit 731b1db2fcc82c0a8afd28d7f28363c1db0a20ce
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 10:41:17 2011 +1000

    Require inputproto 2.1.99.3
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/configure.ac b/configure.ac
index 27bf6ab..e2d91f2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -776,7 +776,7 @@ XPROTO="xproto >= 7.0.22"
 RANDRPROTO="randrproto >= 1.2.99.3"
 RENDERPROTO="renderproto >= 0.11"
 XEXTPROTO="xextproto >= 7.1.99"
-INPUTPROTO="inputproto >= 2.0.99.1"
+INPUTPROTO="inputproto >= 2.1.99.3"
 KBPROTO="kbproto >= 1.0.3"
 FONTSPROTO="fontsproto"
 FIXESPROTO="fixesproto >= 5.0"
commit 4c825eae89063fdc2241f92ab4101ba682b5b4b7
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Nov 2 10:38:26 2011 +1000

    Xi: add a FIXME
    
    All the DeepCopy stuff really needs to be shared between the init calls the
    drivers use and this code here. Too many bugs by not keeping the two in
    sync.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index ad9c3d6..1e16b74 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -492,6 +492,8 @@ DeepCopyKeyboardClasses(DeviceIntPtr from, DeviceIntPtr to)
 
 }
 
+/* FIXME: this should really be shared with the InitValuatorAxisClassRec and
+ * similar */
 static void
 DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
 {
commit 0b9d2e426defabbf6df7e872e158b080a6a5e0be
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 13:21:03 2011 +1000

    Xi: split ProcessOtherEvent into ProcessDeviceEvent
    
    No functional changes.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Alan Coopersmith <alan.coopersmith at oracle.com>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 45a289a..ad9c3d6 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -902,13 +902,12 @@ UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event)
     return DEFAULT;
 }
 
+
 /**
- * Main device event processing function.
- * Called from when processing the events from the event queue.
- *
+ * Process DeviceEvents and DeviceChangedEvents.
  */
-void
-ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
+static void
+ProcessDeviceEvent(InternalEvent *ev, DeviceIntPtr device)
 {
     GrabPtr grab;
     Bool deactivateDeviceGrab = FALSE;
@@ -919,18 +918,6 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
     DeviceIntPtr mouse = NULL, kbd = NULL;
     DeviceEvent *event = &ev->device_event;
 
-    verify_internal_event(ev);
-
-    if (ev->any.type == ET_RawKeyPress ||
-        ev->any.type == ET_RawKeyRelease ||
-        ev->any.type == ET_RawButtonPress ||
-        ev->any.type == ET_RawButtonRelease ||
-        ev->any.type == ET_RawMotion)
-    {
-        DeliverRawEvent(&ev->raw_event, device);
-        return;
-    }
-
     if (IsPointerDevice(device))
     {
         kbd = GetMaster(device, KEYBOARD_OR_FLOAT);
@@ -1042,6 +1029,31 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
     event->detail.key = key;
 }
 
+/**
+ * Main device event processing function.
+ * Called from when processing the events from the event queue.
+ *
+ */
+void
+ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
+{
+    verify_internal_event(ev);
+
+    switch(ev->any.type)
+    {
+        case  ET_RawKeyPress:
+        case  ET_RawKeyRelease:
+        case  ET_RawButtonPress:
+        case  ET_RawButtonRelease:
+        case  ET_RawMotion:
+            DeliverRawEvent(&ev->raw_event, device);
+            break;
+        default:
+            ProcessDeviceEvent(ev, device);
+            break;
+    }
+}
+
 int
 InitProximityClassDeviceStruct(DeviceIntPtr dev)
 {
commit 190a6f45ee7412870b3d95c5db6c1079a285bc59
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Fri Dec 16 09:52:43 2011 +1000

    dix: split positionSprite into scale_to_desktop and positionSprite
    
    For future touch points, we need positionSprite to calculate the coordinates
    but we don't want to actually change the cursor position for non-emulating
    touches.
    
    No functional changes at this point.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Jamey Sharp <jamey at minilop.net>
    Reviewed-by: Chase Douglas <chase.douglas at canonical.com>

diff --git a/dix/getevents.c b/dix/getevents.c
index 57d8c17..ea62ca8 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -786,36 +786,28 @@ scale_from_screen(DeviceIntPtr dev, ValuatorMask *mask)
 
 
 /**
- * If we have HW cursors, this actually moves the visible sprite. If not, we
- * just do all the screen crossing, etc.
- *
- * We scale from device to screen coordinates here, call
- * miPointerSetPosition() and then scale back into device coordinates (if
- * needed). miPSP will change x/y if the screen was crossed.
+ * Scale from (absolute) device to screen coordinates here,
  *
- * The coordinates provided are always absolute. The parameter mode
- * specifies whether it was relative or absolute movement that landed us at
- * those coordinates. see fill_pointer_events for information on coordinate
- * systems.
+ * The coordinates provided are always absolute. see fill_pointer_events for
+ * information on coordinate systems.
  *
  * @param dev The device to be moved.
- * @param mode Movement mode (Absolute or Relative)
- * @param[in,out] mask Mask of axis values for this event, returns the
- * per-screen device coordinates after confinement
+ * @param mask Mask of axis values for this event
  * @param[out] devx x desktop-wide coordinate in device coordinate system
  * @param[out] devy y desktop-wide coordinate in device coordinate system
  * @param[out] screenx x coordinate in desktop coordinate system
  * @param[out] screeny y coordinate in desktop coordinate system
  */
 static ScreenPtr
-positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
-               double *devx, double *devy,
-               double *screenx, double *screeny)
+scale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask,
+                 double *devx, double *devy,
+                 double *screenx, double *screeny)
 {
-    double x, y;
-    double tmpx, tmpy;
     ScreenPtr scr = miPointerGetScreen(dev);
+    double x, y;
 
+    BUG_WARN(!dev->valuator);
+    BUG_WARN(dev->valuator->numAxes < 2);
     if (!dev->valuator || dev->valuator->numAxes < 2)
         return scr;
 
@@ -834,11 +826,48 @@ positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
     *screeny = rescaleValuatorAxis(y, dev->valuator->axes + 1, NULL,
                                    screenInfo.y, screenInfo.height);
 
-    tmpx = *screenx;
-    tmpy = *screeny;
     *devx = x;
     *devy = y;
 
+    return scr;
+}
+
+/**
+ * If we have HW cursors, this actually moves the visible sprite. If not, we
+ * just do all the screen crossing, etc.
+ *
+ * We use the screen coordinates here, call miPointerSetPosition() and then
+ * scale back into device coordinates (if needed). miPSP will change x/y if
+ * the screen was crossed.
+ *
+ * The coordinates provided are always absolute. The parameter mode
+ * specifies whether it was relative or absolute movement that landed us at
+ * those coordinates. see fill_pointer_events for information on coordinate
+ * systems.
+ *
+ * @param dev The device to be moved.
+ * @param mode Movement mode (Absolute or Relative)
+ * @param[out] mask Mask of axis values for this event, returns the
+ * per-screen device coordinates after confinement
+ * @param[in,out] devx x desktop-wide coordinate in device coordinate system
+ * @param[in,out] devy y desktop-wide coordinate in device coordinate system
+ * @param[in,out] screenx x coordinate in desktop coordinate system
+ * @param[in,out] screeny y coordinate in desktop coordinate system
+ */
+static ScreenPtr
+positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
+               double *devx, double *devy,
+               double *screenx, double *screeny)
+{
+    ScreenPtr scr = miPointerGetScreen(dev);
+    double tmpx, tmpy;
+
+    if (!dev->valuator || dev->valuator->numAxes < 2)
+        return scr;
+
+    tmpx = *screenx;
+    tmpy = *screeny;
+
     /* miPointerSetPosition takes care of crossing screens for us, as well as
      * clipping to the current screen. Coordinates returned are in desktop
      * coord system */
@@ -858,11 +887,13 @@ positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
 
     /* Recalculate the per-screen device coordinates */
     if (valuator_mask_isset(mask, 0)) {
+        double x;
         x = rescaleValuatorAxis(*screenx - scr->x, NULL, dev->valuator->axes + 0,
                                 0, scr->width);
         valuator_mask_set_double(mask, 0, x);
     }
     if (valuator_mask_isset(mask, 1)) {
+        double y;
         y = rescaleValuatorAxis(*screeny - scr->y, NULL, dev->valuator->axes + 1,
                                 0, scr->height);
         valuator_mask_set_double(mask, 1, y);
@@ -1251,6 +1282,7 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
     if ((flags & POINTER_NORAW) == 0)
         set_raw_valuators(raw, &mask, raw->valuators.data);
 
+    scale_to_desktop(pDev, &mask, &devx, &devy, &screenx, &screeny);
     scr = positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative,
                          &mask, &devx, &devy, &screenx, &screeny);
 
commit ff6d9c79c1aa502f1aef81d8063425e5fc002534
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Dec 15 10:19:26 2011 +1000

    include: fix BUG_WARN_MSG for constant messages only
    
    Previous declaration required the use of a message + printf varargs. We
    obviously want to allow the use of just a message.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Alan Coopersmith <alan.coopersmith at oracle.com>

diff --git a/include/misc.h b/include/misc.h
index 09f928a..3d08511 100644
--- a/include/misc.h
+++ b/include/misc.h
@@ -370,8 +370,8 @@ extern _X_EXPORT unsigned long serverGeneration;
               xorg_backtrace();                                           \
           } } while(0)
 
-#define BUG_WARN_MSG(cond, msg, ...)                                      \
-          __BUG_WARN_MSG(cond, 1, msg, __VA_ARGS__)
+#define BUG_WARN_MSG(cond, ...)                                           \
+          __BUG_WARN_MSG(cond, 1, __VA_ARGS__)
 
 #define BUG_WARN(cond)  __BUG_WARN_MSG(cond, 0, NULL)
 
commit 4c80dc1394344dc10cffe4f757c980944312dc3d
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Wed Dec 14 10:31:23 2011 +1000

    configure: split the required modules up
    
    We do the same thing for libraries and optional modules already, and it's
    much easier to read when one of them changes
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/configure.ac b/configure.ac
index 27bf7db..27bf6ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -771,6 +771,20 @@ VIDMODEPROTO="xf86vidmodeproto >= 2.2.99.1"
 WINDOWSWMPROTO="windowswmproto"
 APPLEWMPROTO="applewmproto >= 1.4"
 
+dnl Required modules
+XPROTO="xproto >= 7.0.22"
+RANDRPROTO="randrproto >= 1.2.99.3"
+RENDERPROTO="renderproto >= 0.11"
+XEXTPROTO="xextproto >= 7.1.99"
+INPUTPROTO="inputproto >= 2.0.99.1"
+KBPROTO="kbproto >= 1.0.3"
+FONTSPROTO="fontsproto"
+FIXESPROTO="fixesproto >= 5.0"
+DAMAGEPROTO="damageproto >= 1.1"
+XCMISCPROTO="xcmiscproto >= 1.2.0"
+BIGREQSPROTO="bigreqsproto >= 1.1.0"
+XTRANS="xtrans >= 1.2.2"
+
 dnl List of libraries that require a specific version
 LIBAPPLEWM="applewm >= 1.4"
 LIBDMX="dmx >= 1.0.99.1"
@@ -793,11 +807,11 @@ PKG_CHECK_MODULES(PIXMAN, $LIBPIXMAN)
 REQUIRED_LIBS="$REQUIRED_LIBS $LIBPIXMAN $LIBXFONT xau"
 
 dnl Core modules for most extensions, et al.
-SDK_REQUIRED_MODULES="[xproto >= 7.0.22] [randrproto >= 1.2.99.3] [renderproto >= 0.11] [xextproto >= 7.1.99] [inputproto >= 2.0.99.1] [kbproto >= 1.0.3] fontsproto $LIBPIXMAN"
+SDK_REQUIRED_MODULES="$XPROTO $RANDRPROTO $RENDERPROTO $XEXTPROTO $INPUTPROTO $KBPROTO $FONTSPROTO $LIBPIXMAN"
 # Make SDK_REQUIRED_MODULES available for inclusion in xorg-server.pc
 AC_SUBST(SDK_REQUIRED_MODULES)
 
-REQUIRED_MODULES="[fixesproto >= 5.0] [damageproto >= 1.1] [xcmiscproto >= 1.2.0] [xtrans >= 1.2.2] [bigreqsproto >= 1.1.0] $SDK_REQUIRED_MODULES"
+REQUIRED_MODULES="$FIXESPROTO $DAMAGEPROTO $XCMISCPROTO $XTRANS $BIGREQSPROTO $SDK_REQUIRED_MODULES"
 
 if test "x$CONFIG_UDEV" = xyes &&
  { test "x$CONFIG_DBUS_API" = xyes || test "x$CONFIG_HAL" = xyes; }; then


More information about the Xquartz-changes mailing list