diff options
Diffstat (limited to 'x11-base/xorg-server/files')
10 files changed, 6466 insertions, 0 deletions
diff --git a/x11-base/xorg-server/files/xorg-cve-2011-4028+4029.patch b/x11-base/xorg-server/files/xorg-cve-2011-4028+4029.patch new file mode 100644 index 0000000..66e77f6 --- /dev/null +++ b/x11-base/xorg-server/files/xorg-cve-2011-4028+4029.patch @@ -0,0 +1,22 @@ +diff --git a/os/utils.c b/os/utils.c +index e8ecb71..18ff1ca 100644 +--- a/os/utils.c ++++ b/os/utils.c +@@ -297,7 +297,7 @@ LockServer(void) + FatalError("Could not create lock file in %s\n", tmp); + (void) sprintf(pid_str, "%10ld\n", (long)getpid()); + (void) write(lfd, pid_str, 11); +- (void) chmod(tmp, 0444); ++ (void) fchmod(lfd, 0444); + (void) close(lfd); + + /* +@@ -318,7 +318,7 @@ LockServer(void) + /* + * Read the pid from the existing file + */ +- lfd = open(LockFile, O_RDONLY); ++ lfd = open(LockFile, O_RDONLY|O_NOFOLLOW); + if (lfd < 0) { + unlink(tmp); + FatalError("Can't read lock file %s\n", LockFile); diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-Xi_ensure_replayed_touch_events_have_devices.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-Xi_ensure_replayed_touch_events_have_devices.patch new file mode 100644 index 0000000..7e641bf --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-Xi_ensure_replayed_touch_events_have_devices.patch @@ -0,0 +1,35 @@ +From a1535e63935e6453301e54efbc4c13dc11995b40 Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho <carlosg@gnome.org> +Date: Mon, 5 Sep 2011 17:25:54 +0200 +Subject: [PATCH 1/6] Xi: ensure replayed touch events have the right devices + set + +So update the event device/source to the TouchClientPtr ones +--- + Xi/exevents.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/Xi/exevents.c b/Xi/exevents.c +index 2f1a066..b8b9129 100644 +--- a/Xi/exevents.c ++++ b/Xi/exevents.c +@@ -1625,12 +1625,16 @@ ProcessTouchOwnership(DeviceIntPtr dev, TouchPointInfoPtr ti, uint8_t reason, + Bool ret; + + /* Deliver the saved touch begin event. */ ++ ti->begin_event->device_event.deviceid = tc->device->id; ++ ti->begin_event->device_event.sourceid = tc->source->id; + ret = DeliverOneTouchEvent(tc, ti, ti->begin_event); + + /* Deliver all the touch motion events in the ring buffer. */ + ev = ti->first_history; + while (ret && ev != ti->next_history) + { ++ ev->device_event.deviceid = tc->device->id; ++ ev->device_event.sourceid = tc->source->id; + ret = DeliverOneTouchEvent(tc, ti, ev); + + if (ev->any.type == ET_TouchEnd) +-- +1.7.5.4 + diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-Xi_ensure_touch_events_update_currentTime.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-Xi_ensure_touch_events_update_currentTime.patch new file mode 100644 index 0000000..36022b4 --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-Xi_ensure_touch_events_update_currentTime.patch @@ -0,0 +1,27 @@ +From 071c0d19396be0a12d9e2300d6fa2667ad6f032e Mon Sep 17 00:00:00 2001 +From: Carlos Garnacho <carlosg@gnome.org> +Date: Mon, 5 Sep 2011 17:36:06 +0200 +Subject: [PATCH 2/6] Xi: Ensure touch events update currentTime + +This is so grabs initiated by touch events don't check +against a possibly outdated currentTime, and appear to +be in the future while they actually aren't. +--- + Xi/exevents.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/Xi/exevents.c b/Xi/exevents.c +index b8b9129..d445c9a 100644 +--- a/Xi/exevents.c ++++ b/Xi/exevents.c +@@ -1924,6 +1924,7 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device) + DeviceEvent *event = &ev->device_event; + + CHECKEVENT(ev); ++ UpdateCurrentTimeIf(); + + if (ev->any.type == ET_RawKeyPress || + ev->any.type == ET_RawKeyRelease || +-- +1.7.5.4 + diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_masked_transformed_valuators.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_masked_transformed_valuators.patch new file mode 100644 index 0000000..31813aa --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_masked_transformed_valuators.patch @@ -0,0 +1,106 @@ +We must store two sets of the X and Y valuator values in the server: both the +last untransformed and the last transformed values. We need the last +untransformed values so we can correctly transform new values, and we need the +last transformed values to know when to set the valuator in the event mask. This +patch ensures the correct handling of valuator values when an input coordinate +transformation matrix with rotation is applied. + +Index: xorg-server/dix/getevents.c +=================================================================== +--- xorg-server.orig/dix/getevents.c 2011-08-24 12:56:49.855650623 +0300 ++++ xorg-server/dix/getevents.c 2011-08-24 12:57:09.015650896 +0300 +@@ -1185,15 +1185,29 @@ + } + } + +- x = (valuator_mask_isset(&mask, 0) ? valuator_mask_get(&mask, 0) : +- pDev->last.valuators[0]); +- y = (valuator_mask_isset(&mask, 1) ? valuator_mask_get(&mask, 1) : +- pDev->last.valuators[1]); +- transformAbsolute(pDev, &mask, &x, &y); + if (valuator_mask_isset(&mask, 0)) +- valuator_mask_set(&mask, 0, x); ++ { ++ x = valuator_mask_get(&mask, 0); ++ pDev->last.untransformed_x = x; ++ } else ++ x = pDev->last.untransformed_x; + if (valuator_mask_isset(&mask, 1)) ++ { ++ y = valuator_mask_get(&mask, 1); ++ pDev->last.untransformed_y = y; ++ } else ++ y = pDev->last.untransformed_y; ++ ++ transformAbsolute(pDev, &mask, &x, &y); ++ ++ if (x != pDev->last.valuators[0]) ++ valuator_mask_set(&mask, 0, x); ++ else ++ valuator_mask_unset(&mask, 0); ++ if (y != pDev->last.valuators[1]) + valuator_mask_set(&mask, 1, y); ++ else ++ valuator_mask_unset(&mask, 1); + + moveAbsolute(pDev, &x, &y, &mask); + } else { +@@ -1402,22 +1416,27 @@ + * Relative. */ + if (t->mode == XIDirectTouch) { + if (valuator_mask_isset(&mask, t->x_axis)) ++ { + x = valuator_mask_get(&mask, t->x_axis); +- else +- x = ti->valuators[t->x_axis]; +- x = rescaleValuatorAxis(x, 0.0, &x_frac, +- (AxisInfoPtr)(t->axes + t->x_axis), +- NULL, scr->width); ++ ti->untransformed_x = x; ++ } else ++ x = ti->untransformed_x; + + if (valuator_mask_isset(&mask, t->y_axis)) ++ { + y = valuator_mask_get(&mask, t->y_axis); +- else +- y = ti->valuators[t->y_axis]; ++ ti->untransformed_y = y; ++ } else ++ y = ti->untransformed_y; ++ ++ transformAbsolute(pDev, &mask, &x, &y); ++ ++ x = rescaleValuatorAxis(x, 0.0, &x_frac, ++ (AxisInfoPtr)(t->axes + t->x_axis), ++ NULL, scr->width); + y = rescaleValuatorAxis(y, 0.0, &y_frac, + (AxisInfoPtr)(t->axes + t->y_axis), + NULL, scr->height); +- +- transformAbsolute(pDev, &mask, &x, &y); + } + else { + x = pDev->spriteInfo->sprite->hotPhys.x; +Index: xorg-server/include/inputstr.h +=================================================================== +--- xorg-server.orig/include/inputstr.h 2011-08-24 12:56:49.865650624 +0300 ++++ xorg-server/include/inputstr.h 2011-08-24 12:56:49.905650624 +0300 +@@ -335,6 +335,8 @@ + unsigned int history_size; /* Size of history ring buffer */ + InternalEvent *first_history; /* Pointer to first event in history */ + InternalEvent *next_history; /* Pointer to next available event */ ++ int untransformed_x; ++ int untransformed_y; + } TouchPointInfoRec; + + typedef struct _TouchAxisInfo { +@@ -623,6 +625,8 @@ + float remainder[MAX_VALUATORS]; + int numValuators; + DeviceIntPtr slave; ++ int untransformed_x; ++ int untransformed_y; + } last; + + /* Input device property handling. */ diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_no_coords.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_no_coords.patch new file mode 100644 index 0000000..c733ad2 --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_no_coords.patch @@ -0,0 +1,66 @@ +Fix handling of events when the X and Y valuators are not set. This fixes cursor +warping to (0,0) on Wacom button press events. + +Index: xorg-server/dix/getevents.c +=================================================================== +--- xorg-server.orig/dix/getevents.c 2011-08-24 12:56:49.905650624 +0300 ++++ xorg-server/dix/getevents.c 2011-08-24 12:56:49.925650626 +0300 +@@ -1185,31 +1185,37 @@ + } + } + +- if (valuator_mask_isset(&mask, 0)) ++ if (valuator_mask_isset(&mask, 0) || valuator_mask_isset(&mask, 1)) + { +- x = valuator_mask_get(&mask, 0); +- pDev->last.untransformed_x = x; +- } else +- x = pDev->last.untransformed_x; +- if (valuator_mask_isset(&mask, 1)) +- { +- y = valuator_mask_get(&mask, 1); +- pDev->last.untransformed_y = y; +- } else +- y = pDev->last.untransformed_y; ++ if (valuator_mask_isset(&mask, 0)) ++ { ++ x = valuator_mask_get(&mask, 0); ++ pDev->last.untransformed_x = x; ++ } else ++ x = pDev->last.untransformed_x; ++ if (valuator_mask_isset(&mask, 1)) ++ { ++ y = valuator_mask_get(&mask, 1); ++ pDev->last.untransformed_y = y; ++ } else ++ y = pDev->last.untransformed_y; + +- transformAbsolute(pDev, &mask, &x, &y); ++ transformAbsolute(pDev, &mask, &x, &y); + +- if (x != pDev->last.valuators[0]) +- valuator_mask_set(&mask, 0, x); +- else +- valuator_mask_unset(&mask, 0); +- if (y != pDev->last.valuators[1]) +- valuator_mask_set(&mask, 1, y); +- else +- valuator_mask_unset(&mask, 1); ++ if (x != pDev->last.valuators[0]) ++ valuator_mask_set(&mask, 0, x); ++ else ++ valuator_mask_unset(&mask, 0); ++ if (y != pDev->last.valuators[1]) ++ valuator_mask_set(&mask, 1, y); ++ else ++ valuator_mask_unset(&mask, 1); + +- moveAbsolute(pDev, &x, &y, &mask); ++ moveAbsolute(pDev, &x, &y, &mask); ++ } else { ++ x = pDev->last.valuators[0]; ++ y = pDev->last.valuators[1]; ++ } + } else { + if (flags & POINTER_ACCELERATE) { + /* FIXME: Pointer acceleration only requires X and Y values. This diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_touchpad_touch_event_removal.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_touchpad_touch_event_removal.patch new file mode 100644 index 0000000..6b16b65 --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_touchpad_touch_event_removal.patch @@ -0,0 +1,16 @@ +--- a/dix/events.c ++++ b/dix/events.c +@@ -1327,11 +1327,11 @@ RemoveTouchEventsFromQueue(DeviceIntPtr + dev->deviceGrab.sync.event = malloc(sizeof(DeviceEvent)); + memcpy(dev->deviceGrab.sync.event, first->event, + sizeof(DeviceEvent)); ++ syncEvents.pending = first->next; ++ free(first); + } + else + dev->deviceGrab.sync.event = NULL; +- syncEvents.pending = first->next; +- free(first); + if (!syncEvents.pending) + syncEvents.pendtail = NULL; + } diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-gestures-extension.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-gestures-extension.patch new file mode 100644 index 0000000..c9a0026 --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-gestures-extension.patch @@ -0,0 +1,1482 @@ +Index: xorg-server/Makefile.am +=================================================================== +--- xorg-server.orig/Makefile.am 2011-08-24 12:52:43.205647111 +0300 ++++ xorg-server/Makefile.am 2011-08-24 12:56:49.885650627 +0300 +@@ -17,6 +17,10 @@ + RECORD_DIR=record + endif + ++if GESTURES ++GESTURE_DIR=gesture ++endif ++ + SUBDIRS = \ + doc \ + include \ +@@ -37,6 +41,7 @@ + $(COMPOSITE_DIR) \ + $(GLX_DIR) \ + exa \ ++ $(GESTURE_DIR) \ + config \ + hw \ + test +Index: xorg-server/configure.ac +=================================================================== +--- xorg-server.orig/configure.ac 2011-08-24 12:56:49.855650623 +0300 ++++ xorg-server/configure.ac 2011-08-24 12:56:49.885650627 +0300 +@@ -596,6 +596,8 @@ + AC_ARG_ENABLE(pc98, AC_HELP_STRING([--enable-pc98], [Enable PC98 support in Xorg (default: auto)]), + [SUPPORT_PC98=$enableval], + [SUPPORT_PC98=auto]) ++AC_ARG_ENABLE(gestures, AC_HELP_STRING([--enable-gestures], [Enable gesture support (default: disabled)]), ++ [GESTURES=$enableval]) + + dnl GLX build options + AC_ARG_ENABLE(aiglx, AS_HELP_STRING([--enable-aiglx], [Build accelerated indirect GLX (default: enabled)]), +@@ -1366,6 +1368,13 @@ + MIEXT_SYNC_LIB='$(top_builddir)/miext/sync/libsync.la' + CORE_INCS='-I$(top_srcdir)/include -I$(top_builddir)/include' + ++AM_CONDITIONAL(GESTURES, [test "x$GESTURES" = "xyes"]) ++if test "x$GESTURES" = xyes; then ++ AC_DEFINE(GESTURES, 1, [Enable gesture support]) ++ GESTURE_LIB='$(top_builddir)/gesture/libgesture.la' ++ GESTURE_INC='-I$(top_srcdir)/gesture' ++fi ++ + # SHA1 hashing + AC_ARG_WITH([sha1], + [AS_HELP_STRING([--with-sha1=libc|libmd|libgcrypt|libcrypto|libsha1|CommonCrypto|nettle], +@@ -1513,7 +1522,7 @@ + AC_DEFINE([SVR4],1,[Define to 1 on systems derived from System V Release 4]) + AC_MSG_RESULT([yes])], AC_MSG_RESULT([no])) + +-XSERVER_CFLAGS="$XSERVER_CFLAGS $CORE_INCS $XEXT_INC $COMPOSITE_INC $DAMAGE_INC $FIXES_INC $XI_INC $MI_INC $MIEXT_SYNC_INC $MIEXT_SHADOW_INC $MIEXT_LAYER_INC $MIEXT_DAMAGE_INC $RENDER_INC $RANDR_INC $FB_INC" ++XSERVER_CFLAGS="$XSERVER_CFLAGS $CORE_INCS $XEXT_INC $COMPOSITE_INC $DAMAGE_INC $FIXES_INC $XI_INC $MI_INC $MIEXT_SYNC_INC $MIEXT_SHADOW_INC $MIEXT_LAYER_INC $MIEXT_DAMAGE_INC $RENDER_INC $RANDR_INC $FB_INC $GESTURE_INC" + + dnl --------------------------------------------------------------------------- + dnl DDX section. +@@ -1526,7 +1535,7 @@ + AM_CONDITIONAL(XVFB, [test "x$XVFB" = xyes]) + + if test "x$XVFB" = xyes; then +- XVFB_LIBS="$FB_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB" ++ XVFB_LIBS="$FB_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $GESTURE_LIB" + XVFB_SYS_LIBS="$XVFBMODULES_LIBS $GLX_SYS_LIBS" + AC_SUBST([XVFB_LIBS]) + AC_SUBST([XVFB_SYS_LIBS]) +@@ -1547,7 +1556,7 @@ + if test "x$have_xnest" = xno; then + AC_MSG_ERROR([Xnest build explicitly requested, but required modules not found.]) + fi +- XNEST_LIBS="$FB_LIB $FIXES_LIB $MI_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $DIX_LIB $MAIN_LIB $OS_LIB" ++ XNEST_LIBS="$FB_LIB $FIXES_LIB $MI_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $DIX_LIB $MAIN_LIB $OS_LIB $GESTURE_LIB" + XNEST_SYS_LIBS="$XNESTMODULES_LIBS $GLX_SYS_LIBS" + AC_SUBST([XNEST_LIBS]) + AC_SUBST([XNEST_SYS_LIBS]) +@@ -1575,7 +1584,7 @@ + XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' + XORG_INCS="$XORG_DDXINCS $XORG_OSINCS" + XORG_CFLAGS="$XORGSERVER_CFLAGS -DHAVE_XORG_CONFIG_H" +- XORG_LIBS="$COMPOSITE_LIB $FIXES_LIB $XEXTXORG_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB" ++ XORG_LIBS="$COMPOSITE_LIB $FIXES_LIB $XEXTXORG_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $GESTURE_LIB" + + dnl ================================================================== + dnl symbol visibility +@@ -1911,7 +1920,7 @@ + XWIN_SYS_LIBS=-lwinsock2 + ;; + esac +- XWIN_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $RANDR_LIB $RENDER_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $OS_LIB" ++ XWIN_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $RANDR_LIB $RENDER_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $OS_LIB $GESTURE_LIB" + XWIN_SYS_LIBS="$XWIN_SYS_LIBS $XWINMODULES_LIBS" + AC_SUBST(XWIN_LIBS) + AC_SUBST(XWIN_SERVER_NAME) +@@ -1941,7 +1950,7 @@ + AC_DEFINE(XQUARTZ,1,[Have Quartz]) + AC_DEFINE(ROOTLESS,1,[Build Rootless code]) + +- DARWIN_LIBS="$MI_LIB $OS_LIB $DIX_LIB $MAIN_LIB $FB_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $XPSTUBS_LIB" ++ DARWIN_LIBS="$MI_LIB $OS_LIB $DIX_LIB $MAIN_LIB $FB_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $XPSTUBS_LIB $GESTURE_LIB" + AC_SUBST([DARWIN_LIBS]) + + AC_CHECK_LIB([Xplugin],[xp_init],[:]) +@@ -2002,7 +2011,7 @@ + fi + DMX_INCLUDES="$XEXT_INC $RENDER_INC $RECORD_INC" + XDMX_CFLAGS="$DMXMODULES_CFLAGS" +- XDMX_LIBS="$FB_LIB $MI_LIB $XEXT_LIB $RENDER_LIB $RECORD_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $MIEXT_SYNC_LIB $MIEXT_SHADOW_LIB $MIEXT_DAMAGE_LIB $COMPOSITE_LIB $DAMAGE_LIB $MAIN_LIB $DIX_LIB $CONFIG_LIB $OS_LIB $FIXES_LIB" ++ XDMX_LIBS="$FB_LIB $MI_LIB $XEXT_LIB $RENDER_LIB $RECORD_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $MIEXT_SYNC_LIB $MIEXT_SHADOW_LIB $MIEXT_DAMAGE_LIB $COMPOSITE_LIB $DAMAGE_LIB $MAIN_LIB $DIX_LIB $CONFIG_LIB $OS_LIB $FIXES_LIB $GESTURE_LIB" + XDMX_SYS_LIBS="$DMXMODULES_LIBS" + AC_SUBST([XDMX_CFLAGS]) + AC_SUBST([XDMX_LIBS]) +@@ -2113,7 +2122,7 @@ + + KDRIVE_CFLAGS="$XSERVER_CFLAGS -DHAVE_KDRIVE_CONFIG_H $TSLIB_CFLAGS" + +- KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB" ++ KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB $GESTURE_LIB" + KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la' + case $host_os in + *linux*) +@@ -2229,6 +2238,7 @@ + Xi/Makefile + xfixes/Makefile + exa/Makefile ++gesture/Makefile + hw/Makefile + hw/xfree86/Makefile + hw/xfree86/common/Makefile +Index: xorg-server/dix/events.c +=================================================================== +--- xorg-server.orig/dix/events.c 2011-08-24 12:56:49.875650625 +0300 ++++ xorg-server/dix/events.c 2011-08-24 12:56:49.895650626 +0300 +@@ -6016,6 +6016,9 @@ + FreeResource(oc->resource, RT_NONE); + while ( (passive = wPassiveGrabs(pWin)) ) + FreeResource(passive->resource, RT_NONE); ++#ifdef GESTURES ++ DeleteWindowFromGestureEvents(pWin); ++#endif + } + + DeleteWindowFromAnyExtEvents(pWin, freeResources); +Index: xorg-server/dix/window.c +=================================================================== +--- xorg-server.orig/dix/window.c 2011-08-24 12:56:49.855650623 +0300 ++++ xorg-server/dix/window.c 2011-08-24 12:56:49.895650626 +0300 +@@ -404,6 +404,9 @@ + pWin->optional->deviceCursors = NULL; + pWin->optional->colormap = pScreen->defColormap; + pWin->optional->visual = pScreen->rootVisual; ++#ifdef GESTURES ++ pWin->optional->gestureMasks = NULL; ++#endif + + pWin->nextSib = NullWindow; + +@@ -3415,6 +3418,10 @@ + pNode = pNode->next; + } + } ++#ifdef GESTURES ++ if (optional->gestureMasks != NULL) ++ return; ++#endif + + parentOptional = FindWindowWithOptional(w)->optional; + if (optional->visual != parentOptional->visual) +@@ -3458,6 +3465,9 @@ + optional->inputShape = NULL; + optional->inputMasks = NULL; + optional->deviceCursors = NULL; ++#ifdef GESTURES ++ optional->gestureMasks = NULL; ++#endif + + parentOptional = FindWindowWithOptional(pWin)->optional; + optional->visual = parentOptional->visual; +Index: xorg-server/gesture/Makefile.am +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ xorg-server/gesture/Makefile.am 2011-08-24 12:56:49.895650626 +0300 +@@ -0,0 +1,10 @@ ++noinst_LTLIBRARIES = libgesture.la ++ ++AM_CFLAGS = $(DIX_CFLAGS) ++ ++libgesture_la_SOURCES = \ ++ init.c \ ++ gesture.c \ ++ gesture.h ++ ++sdk_HEADERS = gesture.h +Index: xorg-server/gesture/gesture.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ xorg-server/gesture/gesture.c 2011-08-24 12:56:49.895650626 +0300 +@@ -0,0 +1,430 @@ ++/* ++ * Copyright © 2010 Canonical, Ltd. ++ * ++ * 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. ++ * ++ * Authors: Chase Douglas <chase.douglas@canonical.com> ++ * ++ */ ++ ++#include "windowstr.h" ++#include "gestureint.h" ++ ++int ++SProcGestureQueryVersion(ClientPtr client) ++{ ++ char n; ++ ++ REQUEST(GestureQueryVersionReq); ++ swaps(&stuff->length, n); ++ REQUEST_AT_LEAST_SIZE(GestureQueryVersionReq); ++ swaps(&stuff->major_version, n); ++ swaps(&stuff->minor_version, n); ++ return (ProcGestureQueryVersion(client)); ++} ++ ++GestureExtensionVersion GestureVersion; ++/** ++ * Return the supported Gesture version. ++ * ++ * Saves the version the client claims to support as well, for future ++ * reference. ++ */ ++int ++ProcGestureQueryVersion(ClientPtr client) ++{ ++ GestureQueryVersionReply rep; ++ GestureClientPtr gestureClient; ++ int major, minor; ++ unsigned int sversion, cversion; ++ ++ REQUEST(GestureQueryVersionReq); ++ REQUEST_SIZE_MATCH(GestureQueryVersionReq); ++ ++ gestureClient = dixLookupPrivate(&client->devPrivates, ++ &GestureClientPrivateKeyRec); ++ ++ sversion = GestureVersion.major_version * 1000 + GestureVersion.minor_version; ++ cversion = stuff->major_version * 1000 + stuff->minor_version; ++ ++ if (sversion > cversion) ++ { ++ major = stuff->major_version; ++ minor = stuff->minor_version; ++ } else ++ { ++ major = GestureVersion.major_version; ++ minor = GestureVersion.minor_version; ++ } ++ ++ gestureClient->major_version = major; ++ gestureClient->minor_version = minor; ++ ++ memset(&rep, 0, sizeof(GestureQueryVersionReply)); ++ rep.repType = X_Reply; ++ rep.RepType = X_GestureQueryVersion; ++ rep.length = 0; ++ rep.sequenceNumber = client->sequence; ++ rep.major_version = major; ++ rep.minor_version = minor; ++ ++ WriteReplyToClient(client, sizeof(GestureQueryVersionReply), &rep); ++ ++ return Success; ++} ++ ++void ++SRepGestureQueryVersion(ClientPtr client, int size, GestureQueryVersionReply *rep) ++{ ++ char n; ++ swaps(&rep->sequenceNumber, n); ++ swapl(&rep->length, n); ++ swaps(&rep->major_version, n); ++ swaps(&rep->minor_version, n); ++ WriteToClient(client, size, (char *)rep); ++} ++ ++static Bool ++MakeGestureMasks(WindowPtr pWin) ++{ ++ struct _GestureMasks *masks; ++ ++ masks = calloc(1, sizeof(struct _GestureMasks)); ++ if (!masks) ++ return FALSE; ++ pWin->optional->gestureMasks = masks; ++ return TRUE; ++} ++ ++static int ++AddGestureClient(WindowPtr pWin, ClientPtr client) ++{ ++ GestureClientsPtr others; ++ ++ if (!pWin->optional && !MakeWindowOptional(pWin)) ++ return BadAlloc; ++ others = calloc(1, sizeof(GestureClients)); ++ if (!others) ++ return BadAlloc; ++ if (!pWin->optional->gestureMasks && !MakeGestureMasks(pWin)) ++ return BadAlloc; ++ others->resource = FakeClientID(client->index); ++ others->next = pWin->optional->gestureMasks->clients; ++ pWin->optional->gestureMasks->clients = others; ++ if (!AddResource(others->resource, RT_GESTURECLIENT, (pointer) pWin)) ++ return BadAlloc; ++ return Success; ++} ++ ++/** ++ * Check the given mask (in len bytes) for invalid mask bits. ++ * Invalid mask bits are any bits above GestureLastEvent. ++ * ++ * @return BadValue if at least one invalid bit is set or Success otherwise. ++ */ ++static int ++GestureCheckInvalidMaskBits(unsigned char *mask, int len) ++{ ++ if (len >= GESTUREMASKSIZE) ++ { ++ int i; ++ for (i = GESTURELASTEVENT + 1; i < len * 8; i++) ++ if (BitIsOn(mask, i)) ++ return BadValue; ++ } ++ ++ return Success; ++} ++ ++int ++SProcGestureSelectEvents(ClientPtr client) ++{ ++ char n; ++ int i; ++ ++ REQUEST(GestureSelectEventsReq); ++ swaps(&stuff->length, n); ++ REQUEST_AT_LEAST_SIZE(GestureSelectEventsReq); ++ swapl(&stuff->window, n); ++ swaps(&stuff->mask.device_id, n); ++ swaps(&stuff->mask.mask_len, n); ++ ++ for (i = 0; i < stuff->mask.mask_len; i++) ++ swapl(((uint32_t *)(stuff + 1)) + i, n); ++ ++ return (ProcGestureSelectEvents(client)); ++} ++ ++static void ++RecalculateGestureDeliverableEvents(WindowPtr win) ++{ ++ GestureClientsPtr others; ++ int i; ++ ++ if (!win->optional || !wGestureMasks(win)) ++ return; ++ ++ memset(&wGestureMasks(win)->mask, 0, sizeof(wGestureMasks(win)->mask)); ++ ++ for (others = wGestureMasks(win)->clients; others; others = others->next) ++ for (i = 0; i < sizeof(others->gestureMask) * 8; i++) ++ if (BitIsOn(&others->gestureMask, i)) ++ SetBit(wGestureMasks(win)->mask, i % (GESTURELASTEVENT + 1)); ++} ++ ++static int ++GestureSetEventMask(DeviceIntPtr dev, WindowPtr win, ClientPtr client, ++ unsigned int len, unsigned char* mask) ++{ ++ GestureMasks *masks; ++ GestureClientsPtr others = NULL; ++ ++ masks = wGestureMasks(win); ++ if (masks) ++ { ++ for (others = masks->clients; others; ++ others = others->next) { ++ if (SameClient(others, client)) { ++ memset(others->gestureMask[dev->id], 0, ++ sizeof(others->gestureMask[dev->id])); ++ break; ++ } ++ } ++ } ++ ++ len = min(len, sizeof(others->gestureMask[dev->id])); ++ ++ if (len && !others) ++ { ++ if (AddGestureClient(win, client) != Success) ++ return BadAlloc; ++ masks = wGestureMasks(win); ++ others = masks->clients; ++ } ++ ++ if (others) ++ memset(others->gestureMask[dev->id], 0, ++ sizeof(others->gestureMask[dev->id])); ++ ++ if (len) ++ memcpy(others->gestureMask[dev->id], mask, len); ++ ++ RecalculateGestureDeliverableEvents(win); ++ ++ return Success; ++} ++ ++int ++ProcGestureSelectEvents(ClientPtr client) ++{ ++ int rc; ++ WindowPtr win; ++ DeviceIntPtr dev; ++ DeviceIntRec dummy; ++ ++ REQUEST(GestureSelectEventsReq); ++ REQUEST_AT_LEAST_SIZE(GestureSelectEventsReq); ++ ++ if (sizeof(GestureSelectEventsReq) + stuff->mask.mask_len * 4 > ++ stuff->length * 4) ++ return BadLength; ++ ++ rc = dixLookupWindow(&win, stuff->window, client, DixReceiveAccess); ++ if (rc != Success) ++ return rc; ++ ++ if (GestureCheckInvalidMaskBits((unsigned char*)(stuff + 1), ++ stuff->mask.mask_len * 4) != Success) ++ return BadValue; ++ ++ if (stuff->mask.device_id == GestureAllDevices) ++ { ++ dummy.id = stuff->mask.device_id; ++ dev = &dummy; ++ } else { ++ rc = dixLookupDevice(&dev, stuff->mask.device_id, client, DixUseAccess); ++ if (rc != Success) ++ return rc; ++ } ++ ++ if (GestureSetEventMask(dev, win, client, stuff->mask.mask_len * 4, ++ (unsigned char*)(stuff + 1)) != Success) ++ return BadAlloc; ++ ++ return Success; ++} ++ ++int ++SProcGestureGetSelectedEvents(ClientPtr client) ++{ ++ char n; ++ ++ REQUEST(GestureGetSelectedEventsReq); ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(GestureGetSelectedEventsReq); ++ swapl(&stuff->window, n); ++ ++ return (ProcGestureGetSelectedEvents(client)); ++} ++ ++int ++ProcGestureGetSelectedEvents(ClientPtr client) ++{ ++ int rc, i; ++ WindowPtr win; ++ char n; ++ char *buffer = NULL; ++ GestureGetSelectedEventsReply reply; ++ GestureMasks *masks; ++ GestureClientsPtr others = NULL; ++ GestureEventMask *evmask = NULL; ++ DeviceIntPtr dev; ++ ++ REQUEST(GestureGetSelectedEventsReq); ++ REQUEST_SIZE_MATCH(GestureGetSelectedEventsReq); ++ ++ rc = dixLookupWindow(&win, stuff->window, client, DixGetAttrAccess); ++ if (rc != Success) ++ return rc; ++ ++ reply.repType = X_Reply; ++ reply.RepType = X_GestureGetSelectedEvents; ++ reply.length = 0; ++ reply.sequenceNumber = client->sequence; ++ reply.num_masks = 0; ++ ++ masks = wGestureMasks(win); ++ if (masks) ++ { ++ for (others = masks->clients; others; others = others->next) { ++ if (SameClient(others, client)) { ++ break; ++ } ++ } ++ } ++ ++ if (!others) ++ { ++ WriteReplyToClient(client, sizeof(GestureGetSelectedEventsReply), &reply); ++ return Success; ++ } ++ ++ buffer = calloc(MAXDEVICES, sizeof(GestureEventMask) + pad_to_int32(GESTUREMASKSIZE)); ++ if (!buffer) ++ return BadAlloc; ++ ++ evmask = (GestureEventMask*)buffer; ++ for (i = 0; i < MAXDEVICES; i++) ++ { ++ int j; ++ unsigned char *devmask = others->gestureMask[i]; ++ ++ if (i > 2) ++ { ++ rc = dixLookupDevice(&dev, i, client, DixGetAttrAccess); ++ if (rc != Success) ++ continue; ++ } ++ ++ ++ for (j = GESTUREMASKSIZE - 1; j >= 0; j--) ++ { ++ if (devmask[j] != 0) ++ { ++ int mask_len = (j + 4)/4; /* j is an index, hence + 4, not + 3 */ ++ evmask->device_id = i; ++ evmask->mask_len = mask_len; ++ reply.num_masks++; ++ reply.length += sizeof(GestureEventMask)/4 + evmask->mask_len; ++ ++ if (client->swapped) ++ { ++ swaps(&evmask->device_id, n); ++ swaps(&evmask->mask_len, n); ++ } ++ ++ memcpy(&evmask[1], devmask, j + 1); ++ evmask = (GestureEventMask*)((char*)evmask + ++ sizeof(GestureEventMask) + mask_len * 4); ++ break; ++ } ++ } ++ } ++ ++ WriteReplyToClient(client, sizeof(GestureGetSelectedEventsReply), &reply); ++ ++ if (reply.num_masks) ++ WriteToClient(client, reply.length * 4, buffer); ++ ++ free(buffer); ++ return Success; ++} ++ ++void ++SRepGestureGetSelectedEvents(ClientPtr client, ++ int len, GestureGetSelectedEventsReply *rep) ++{ ++ char n; ++ ++ swaps(&rep->sequenceNumber, n); ++ swapl(&rep->length, n); ++ swaps(&rep->num_masks, n); ++ WriteToClient(client, len, (char *)rep); ++} ++ ++int ++GestureClientGone(WindowPtr pWin, XID id) ++{ ++ GestureClientsPtr other, prev; ++ ++ if (!wGestureMasks(pWin)) ++ return (Success); ++ prev = 0; ++ for (other = wGestureMasks(pWin)->clients; other; ++ other = other->next) { ++ if (other->resource == id) { ++ if (prev) { ++ prev->next = other->next; ++ free(other); ++ } else if (!(other->next)) { ++ free(wGestureMasks(pWin)); ++ pWin->optional->gestureMasks = (GestureMasks *) NULL; ++ CheckWindowOptionalNeed(pWin); ++ free(other); ++ } else { ++ wGestureMasks(pWin)->clients = other->next; ++ free(other); ++ } ++ RecalculateGestureDeliverableEvents(pWin); ++ return (Success); ++ } ++ prev = other; ++ } ++ FatalError("client not on device event list"); ++} ++ ++void ++DeleteWindowFromGestureEvents(WindowPtr pWin) ++{ ++ struct _GestureMasks *gestureMasks; ++ ++ while ((gestureMasks = wGestureMasks(pWin)) != 0) ++ FreeResource(gestureMasks->clients->resource, RT_NONE); ++} +Index: xorg-server/gesture/gesture.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ xorg-server/gesture/gesture.h 2011-08-24 12:56:49.895650626 +0300 +@@ -0,0 +1,78 @@ ++/* ++ * Copyright © 2010 Canonical, Ltd. ++ * ++ * 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. ++ * ++ * Authors: Chase Douglas <chase.douglas@canonical.com> ++ * ++ */ ++ ++#ifndef _GESTURE_H_ ++#define _GESTURE_H_ ++ ++#ifdef HAVE_DIX_CONFIG_H ++#include <dix-config.h> ++#endif ++ ++#include "inputstr.h" ++ ++/* This is the last Gesture event supported by the server. If you add ++ * events to the protocol, the server will not support these events until ++ * this number here is bumped. ++ */ ++#define GESTURELASTEVENT 63 ++#define GESTUREMASKSIZE (GESTURELASTEVENT/8 + 1) /* no of bits for masks */ ++ ++extern _X_EXPORT int GestureReqCode; ++ ++/** ++ * Attached to the devPrivates of each client. Specifies the version number as ++ * supported by the client. ++ */ ++typedef struct _GestureClientRec { ++ int major_version; ++ int minor_version; ++} GestureClientRec, *GestureClientPtr; ++ ++typedef struct _GestureClients *GestureClientsPtr; ++ ++/** ++ * This struct stores the Gesture event mask for each client. ++ * ++ * Each window that has events selected has at least one of these masks. If ++ * multiple client selected for events on the same window, these masks are in ++ * a linked list. ++ */ ++typedef struct _GestureClients { ++ GestureClientsPtr next; /**< Pointer to the next mask */ ++ XID resource; /**< id for putting into resource manager */ ++ /** Gesture event masks. One per device, each bit is a mask of (1 << type) */ ++ unsigned char gestureMask[EMASKSIZE][GESTUREMASKSIZE]; ++} GestureClients; ++ ++typedef struct _GestureMasks { ++ GestureClientsPtr clients; ++ unsigned char mask[GESTUREMASKSIZE]; ++} GestureMasks; ++ ++extern int GestureClientGone(WindowPtr pWin, XID id); ++extern void DeleteWindowFromGestureEvents(WindowPtr pWin); ++ ++#endif /* _GESTURE_H_ */ +Index: xorg-server/gesture/gestureint.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ xorg-server/gesture/gestureint.h 2011-08-24 12:56:49.895650626 +0300 +@@ -0,0 +1,49 @@ ++/* ++ * Copyright © 2010 Canonical, Ltd. ++ * ++ * 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. ++ * ++ * Authors: Chase Douglas <chase.douglas@canonical.com> ++ * ++ */ ++ ++#ifndef _GESTUREINT_H_ ++#define _GESTUREINT_H_ ++ ++#include "gestureproto.h" ++ ++typedef struct { ++ short major_version; ++ short minor_version; ++} GestureExtensionVersion; ++ ++extern DevPrivateKeyRec GestureClientPrivateKeyRec; ++extern int RT_GESTURECLIENT; ++ ++extern int ProcGestureQueryVersion(ClientPtr client); ++extern int ProcGestureSelectEvents(ClientPtr client); ++extern int ProcGestureGetSelectedEvents(ClientPtr client); ++extern int SProcGestureQueryVersion(ClientPtr client); ++extern int SProcGestureSelectEvents(ClientPtr client); ++extern int SProcGestureGetSelectedEvents(ClientPtr client); ++extern void SRepGestureQueryVersion(ClientPtr client, int size, GestureQueryVersionReply *rep); ++extern void SRepGestureGetSelectedEvents(ClientPtr client, int len, GestureGetSelectedEventsReply *rep); ++ ++#endif /* _GESTUREINT_H_ */ +Index: xorg-server/gesture/gestureproto.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ xorg-server/gesture/gestureproto.h 2011-08-24 12:56:49.895650626 +0300 +@@ -0,0 +1,132 @@ ++/* ++ * Copyright © 2010 Canonical, Ltd. ++ * ++ * 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. ++ * ++ * Authors: Chase Douglas <chase.douglas@canonical.com> ++ * ++ */ ++ ++#ifndef _GESTUREPROTO_H_ ++#define _GESTUREPROTO_H_ ++ ++#include <stdint.h> ++#include <X11/X.h> ++ ++#define Window uint32_t ++#define Time uint32_t ++ ++#define X_GestureQueryVersion 1 ++#define X_GestureSelectEvents 2 ++#define X_GestureGetSelectedEvents 3 ++ ++#define GESTUREREQUESTS (X_GestureGetSelectedEvents - X_GestureQueryVersion + 1) ++ ++#define GestureAllDevices 0 ++ ++/** ++ * Used to select for events on a given window. ++ * Struct is followed by (mask_len * CARD8), with each bit set representing ++ * the event mask for the given type. A mask bit represents an event type if ++ * (mask == (1 << type)). ++ */ ++typedef struct { ++ uint16_t device_id; /**< Device id to select for */ ++ uint16_t mask_len; /**< Length of mask in 4 byte units */ ++} GestureEventMask; ++ ++typedef struct { ++ uint8_t reqType; /**< Gesture extension major code */ ++ uint8_t ReqType; /**< Always ::X_GestureQueryVersion */ ++ uint16_t length; /**< Length in 4 byte units */ ++ uint16_t major_version; ++ uint16_t minor_version; ++} GestureQueryVersionReq; ++ ++typedef struct { ++ uint8_t repType; /**< ::X_Reply */ ++ uint8_t RepType; /**< Always ::X_GestureQueryVersion */ ++ uint16_t sequenceNumber; ++ uint32_t length; ++ uint16_t major_version; ++ uint16_t minor_version; ++ uint32_t pad1; ++ uint32_t pad2; ++ uint32_t pad3; ++ uint32_t pad4; ++ uint32_t pad5; ++} GestureQueryVersionReply; ++ ++typedef struct { ++ uint8_t reqType; /**< Gesture extension major code */ ++ uint8_t ReqType; /**< Always ::X_GestureSelectEvents */ ++ uint16_t length; /**< Length in 4 byte units */ ++ Window window; ++ GestureEventMask mask; ++} GestureSelectEventsReq; ++ ++typedef struct { ++ uint8_t reqType; /**< Gesture extension major code */ ++ uint8_t ReqType; /**< Always ::X_GestureGetSelectedEvents */ ++ uint16_t length; /**< Length in 4 byte units */ ++ Window window; ++} GestureGetSelectedEventsReq; ++ ++typedef struct { ++ uint8_t repType; /**< Gesture extension major opcode */ ++ uint8_t RepType; /**< Always ::X_GestureGetSelectedEvents */ ++ uint16_t sequenceNumber; ++ uint32_t length; ++ uint16_t num_masks; /**< Number of GestureEventMask structs ++ trailing the reply */ ++ uint16_t pad0; ++ uint32_t pad1; ++ uint32_t pad2; ++ uint32_t pad3; ++ uint32_t pad4; ++ uint32_t pad5; ++} GestureGetSelectedEventsReply; ++ ++typedef struct ++{ ++ uint8_t type; /**< Always GenericEvent */ ++ uint8_t extension; /**< Gesture extension offset */ ++ uint16_t sequenceNumber; /**< Xevent sequence number */ ++ uint32_t length; /**< Length in 4 byte uints */ ++ uint16_t evtype; /**< X generic event type */ ++ uint16_t gesture_id; /**< Unique ID for gesture */ ++ uint16_t gesture_type; /**< Gesture type (zoom, rotate, etc.) */ ++ uint16_t device_id; /**< Device that generated this gesture */ ++ Time time; /**< Time of gesture event */ ++ Window root; /**< Root window event occurred on */ ++ Window event; /**< Window selecting this event for a client */ ++ Window child; /**< Top-most window of gesture event */ ++/* └──────── 32 byte boundary ────────┘ */ ++ float focus_x; /**< Always window coords, 16.16 fixed point */ ++ float focus_y; /**< Relative to event window */ ++ uint16_t status; /**< Gesture event status */ ++ uint16_t num_props; /**< Number of properties for gesture event */ ++/* └──── Gesture properties below ────┘ */ ++} GestureEvent; ++ ++#undef Window ++#undef Time ++ ++#endif /* _GESTUREPROTO_H_ */ +Index: xorg-server/gesture/init.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ xorg-server/gesture/init.c 2011-08-24 12:56:49.895650626 +0300 +@@ -0,0 +1,280 @@ ++/************************************************************ ++ ++Copyright 2010 Canonical, Ltd. ++Copyright 1989, 1998 The Open Group ++ ++Permission to use, copy, modify, distribute, and sell this software and its ++documentation for any purpose is hereby granted without fee, provided that ++the above copyright notice appear in all copies and that both that ++copyright notice and this permission notice appear in supporting ++documentation. ++ ++The above copyright notice and this permission notice 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 ++OPEN GROUP 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. ++ ++Except as contained in this notice, the name of The Open Group shall not be ++used in advertising or otherwise to promote the sale, use or other dealings ++in this Software without prior written authorization from The Open Group. ++ ++Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. ++ ++ All Rights Reserved ++ ++Permission to use, copy, modify, and distribute this software and its ++documentation for any purpose and without fee is hereby granted, ++provided that the above copyright notice appear in all copies and that ++both that copyright notice and this permission notice appear in ++supporting documentation, and that the name of Hewlett-Packard not be ++used in advertising or publicity pertaining to distribution of the ++software without specific, written prior permission. ++ ++HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ++ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ++HEWLETT-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ++ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ++WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ++ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ++SOFTWARE. ++ ++********************************************************/ ++ ++/******************************************************************** ++ * ++ * Dispatch routines and initialization routines for the X gesture extension. ++ * ++ */ ++ ++#define NUMTYPES 15 ++ ++#ifdef HAVE_DIX_CONFIG_H ++#include <dix-config.h> ++#endif ++ ++#include "gcstruct.h" /* pointer for extnsionst.h */ ++#include "extnsionst.h" /* extension entry */ ++#include "gesture.h" ++#include "gestureint.h" ++#include <X11/extensions/geproto.h> ++#include "geext.h" /* extension interfaces for ge */ ++ ++#include "swaprep.h" ++#include "privates.h" ++#include "protocol-versions.h" ++#include "dixstruct.h" ++ ++#define GESTURE_NAME "GestureExtension" ++#define GESTURE_EVENTS 0 ++#define GESTURE_ERRORS 0 ++ ++void GestureExtensionInit(void); ++ ++/** ++ * Dispatch vector. Functions defined in here will be called when the matching ++ * request arrives. ++ */ ++static int (*ProcGestureVector[])(ClientPtr) = { ++ NULL, /* 0 */ ++ ProcGestureQueryVersion, /* 1 */ ++ ProcGestureSelectEvents, /* 2 */ ++ ProcGestureGetSelectedEvents, /* 3 */ ++}; ++ ++/* For swapped clients */ ++static int (*SProcGestureVector[])(ClientPtr) = { ++ NULL, /* 0 */ ++ SProcGestureQueryVersion, /* 1 */ ++ SProcGestureSelectEvents, /* 2 */ ++ SProcGestureGetSelectedEvents, /* 3 */ ++}; ++ ++/***************************************************************** ++ * ++ * Globals referenced elsewhere in the server. ++ * ++ */ ++ ++int GestureReqCode = 0; ++int GestureNotify = 0; ++ ++int RT_GESTURECLIENT; ++ ++/***************************************************************** ++ * ++ * Externs defined elsewhere in the X server. ++ * ++ */ ++ ++extern GestureExtensionVersion GestureVersion; ++ ++ ++/***************************************************************** ++ * ++ * Versioning support ++ * ++ */ ++ ++DevPrivateKeyRec GestureClientPrivateKeyRec; ++ ++ ++/***************************************************************** ++ * ++ * Declarations of local routines. ++ * ++ */ ++ ++static void ++GestureClientCallback(CallbackListPtr *list, ++ pointer closure, ++ pointer data) ++{ ++ NewClientInfoRec *clientinfo = (NewClientInfoRec*)data; ++ ClientPtr client = clientinfo->client; ++ GestureClientPtr gestureClient; ++ ++ gestureClient = dixLookupPrivate(&client->devPrivates, ++ &GestureClientPrivateKeyRec); ++ gestureClient->major_version = 0; ++ gestureClient->minor_version = 0; ++} ++ ++/************************************************************************* ++ * ++ * ProcGestureDispatch - main dispatch routine for requests to this extension. ++ * This routine is used if server and client have the same byte ordering. ++ * ++ */ ++ ++static int ++ProcGestureDispatch(ClientPtr client) ++{ ++ REQUEST(xReq); ++ if (stuff->data > GESTUREREQUESTS || !ProcGestureVector[stuff->data]) ++ return BadRequest; ++ ++ return (*ProcGestureVector[stuff->data])(client); ++} ++ ++/******************************************************************************* ++ * ++ * SProcXDispatch ++ * ++ * Main swapped dispatch routine for requests to this extension. ++ * This routine is used if server and client do not have the same byte ordering. ++ * ++ */ ++ ++static int ++SProcGestureDispatch(ClientPtr client) ++{ ++ REQUEST(xReq); ++ if (stuff->data > GESTUREREQUESTS || !SProcGestureVector[stuff->data]) ++ return BadRequest; ++ ++ return (*SProcGestureVector[stuff->data])(client); ++} ++ ++/********************************************************************** ++ * ++ * SReplyGestureDispatch ++ * Swap any replies defined in this extension. ++ * ++ */ ++ ++static void ++SReplyGestureDispatch(ClientPtr client, int len, GestureQueryVersionReply *rep) ++{ ++ if (rep->RepType == X_GestureQueryVersion) ++ SRepGestureQueryVersion(client, len, (GestureQueryVersionReply*)rep); ++ else if (rep->RepType == X_GestureGetSelectedEvents) ++ SRepGestureGetSelectedEvents(client, len, (GestureGetSelectedEventsReply *) rep); ++ else { ++ FatalError("Gesture confused sending swapped reply"); ++ } ++} ++ ++static void SGestureEvent(GestureEvent *from, GestureEvent *to) ++{ ++ char n; ++ ++ memcpy(to, from, sizeof(xEvent) + from->length * 4); ++ ++ swaps(&to->sequenceNumber, n); ++ swapl(&to->length, n); ++ swaps(&to->evtype, n); ++ swaps(&to->gesture_id, n); ++ swaps(&to->gesture_type, n); ++ swaps(&to->device_id, n); ++ swapl(&to->time, n); ++ swapl(&to->root, n); ++ swapl(&to->event, n); ++ swapl(&to->child, n); ++ swapl(&to->focus_x, n); ++ swapl(&to->focus_y, n); ++ swaps(&to->status, n); ++ swaps(&to->num_props, n); ++} ++ ++static void ++GestureEventSwap(xGenericEvent *from, xGenericEvent *to) ++{ ++ SGestureEvent((GestureEvent *)from, (GestureEvent *)to); ++} ++ ++static void ++CloseGestureExt(ExtensionEntry *unused) ++{ ++ ReplySwapVector[GestureReqCode] = ReplyNotSwappd; ++ GestureReqCode = 0; ++ GestureNotify = 0; ++} ++ ++/********************************************************************** ++ * ++ * GestureExtensionInit - initialize the gesture extension. ++ * ++ * Called from InitExtensions in main() or from QueryExtension() if the ++ * extension is dynamically loaded. ++ * ++ * This extension has several events and errors. ++ */ ++ ++void ++GestureExtensionInit(void) ++{ ++ ExtensionEntry *extEntry; ++ GestureExtensionVersion thisversion = { ++ SERVER_GESTURE_MAJOR_VERSION, ++ SERVER_GESTURE_MINOR_VERSION, ++ }; ++ ++ if (!dixRegisterPrivateKey(&GestureClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(GestureClientRec))) ++ FatalError("Cannot request private for Gesture.\n"); ++ ++ if (!AddCallback(&ClientStateCallback, GestureClientCallback, 0)) ++ FatalError("Failed to add callback to Gesture.\n"); ++ ++ extEntry = AddExtension(GESTURE_NAME, GESTURE_EVENTS, GESTURE_ERRORS, ++ ProcGestureDispatch, SProcGestureDispatch, CloseGestureExt, ++ StandardMinorOpcode); ++ if (extEntry) { ++ GestureReqCode = extEntry->base; ++ GestureVersion = thisversion; ++ RT_GESTURECLIENT = CreateNewResourceType((DeleteType) GestureClientGone, ++ "GESTURECLIENT"); ++ if (!RT_GESTURECLIENT) ++ FatalError("Failed to add resource type for Gesture.\n"); ++ ReplySwapVector[GestureReqCode] = (ReplySwapPtr) SReplyGestureDispatch; ++ ++ GERegisterExtension(GestureReqCode, GestureEventSwap); ++ } else { ++ FatalError("GestureExtensionInit: AddExtensions failed\n"); ++ } ++} ++ +Index: xorg-server/hw/xfree86/common/xf86Xinput.c +=================================================================== +--- xorg-server.orig/hw/xfree86/common/xf86Xinput.c 2011-08-24 12:56:49.875650625 +0300 ++++ xorg-server/hw/xfree86/common/xf86Xinput.c 2011-08-24 12:56:49.895650626 +0300 +@@ -99,6 +99,15 @@ + return; \ + } + ++#include "gestureproto.h" ++ ++_X_EXPORT void ++xf86PostGestureEvent(DeviceIntPtr dev, unsigned short x, unsigned short y, ++ unsigned short client_id, unsigned short gesture_id, ++ unsigned short gesture_type, Window root, Window event, ++ Window child, unsigned short status, ++ unsigned short num_props, float *props); ++ + EventListPtr xf86Events = NULL; + + static int +@@ -972,6 +981,40 @@ + */ + + void ++xf86PostGestureEvent(DeviceIntPtr dev, unsigned short x, unsigned short y, ++ unsigned short client_id, unsigned short gesture_id, ++ unsigned short gesture_type, Window root, Window event, ++ Window child, unsigned short status, ++ unsigned short num_props, float *props) ++{ ++ DeviceEvent *ev = (DeviceEvent *)xf86Events->event; ++ ++ if (num_props > MAX_GESTURE_PROPS) ++ num_props = MAX_GESTURE_PROPS; ++ ++ memset(ev, 0, sizeof(DeviceEvent)); ++ ev->header = ET_Internal; ++ ev->length = sizeof(DeviceEvent); ++ ev->time = GetTimeInMillis(); ++ ev->deviceid = dev->id; ++ ev->sourceid = dev->id; ++ ev->type = ET_Gesture; ++ ev->root_x = x; ++ ev->root_y = y; ++ ev->gesture.client_id = client_id; ++ ev->gesture.id = gesture_id; ++ ev->gesture.type = gesture_type; ++ ev->root = root; ++ ev->gesture.event = event; ++ ev->gesture.child = child; ++ ev->gesture.status = status; ++ ev->gesture.num_props = num_props; ++ memcpy(ev->gesture.props, props, num_props * sizeof(float)); ++ ++ mieqEnqueue(dev, (InternalEvent*)ev); ++} ++ ++void + xf86PostMotionEvent(DeviceIntPtr device, + int is_absolute, + int first_valuator, +Index: xorg-server/include/dix-config.h.in +=================================================================== +--- xorg-server.orig/include/dix-config.h.in 2011-08-24 12:56:49.505650620 +0300 ++++ xorg-server/include/dix-config.h.in 2011-08-24 12:56:49.895650626 +0300 +@@ -30,6 +30,9 @@ + /* Support Damage extension */ + #undef DAMAGE + ++/* Support Gesture extension */ ++#undef GESTURES ++ + /* Build for darwin with Quartz support */ + #undef DARWIN_WITH_QUARTZ + +Index: xorg-server/include/eventstr.h +=================================================================== +--- xorg-server.orig/include/eventstr.h 2011-08-24 12:56:49.865650624 +0300 ++++ xorg-server/include/eventstr.h 2011-08-24 12:56:49.895650626 +0300 +@@ -70,6 +70,7 @@ + ET_TouchMotion, + ET_TouchMotionUnowned, + ET_TouchOwnership, ++ ET_Gesture, + ET_Internal = 0xFF /* First byte */ + }; + +@@ -77,6 +78,9 @@ + FatalError("Wrong event type %d.\n", \ + ((InternalEvent*)(ev))->any.header); + ++/* Should match DIM_GRAIL_PROP in grail.h */ ++#define MAX_GESTURE_PROPS 32 ++ + /** + * Used for ALL input device events internal in the server until + * copied into the matching protocol event. +@@ -120,6 +124,16 @@ + uint8_t locked; /**< XKB locked group */ + uint8_t effective;/**< XKB effective group */ + } group; ++ struct { ++ uint16_t client_id; ++ uint16_t id; ++ uint16_t type; ++ Window event; ++ Window child; ++ uint16_t status; ++ uint16_t num_props; ++ float props[MAX_GESTURE_PROPS]; ++ } gesture; + Window root; /**< Root window of the event */ + int corestate; /**< Core key/button state BEFORE the event */ + int key_repeat; /**< Internally-generated key repeat event */ +Index: xorg-server/include/protocol-versions.h +=================================================================== +--- xorg-server.orig/include/protocol-versions.h 2011-08-24 12:56:49.865650624 +0300 ++++ xorg-server/include/protocol-versions.h 2011-08-24 12:56:49.895650626 +0300 +@@ -145,4 +145,8 @@ + #define SERVER_XVMC_MAJOR_VERSION 1 + #define SERVER_XVMC_MINOR_VERSION 1 + ++/* Gesture */ ++#define SERVER_GESTURE_MAJOR_VERSION 0 ++#define SERVER_GESTURE_MINOR_VERSION 5 ++ + #endif +Index: xorg-server/include/windowstr.h +=================================================================== +--- xorg-server.orig/include/windowstr.h 2011-08-24 12:52:43.235647111 +0300 ++++ xorg-server/include/windowstr.h 2011-08-24 12:56:49.895650626 +0300 +@@ -48,6 +48,10 @@ + #ifndef WINDOWSTRUCT_H + #define WINDOWSTRUCT_H + ++#ifdef HAVE_DIX_CONFIG_H ++#include <dix-config.h> ++#endif ++ + #include "window.h" + #include "pixmapstr.h" + #include "regionstr.h" +@@ -60,6 +64,10 @@ + #include <X11/Xprotostr.h> + #include "opaque.h" + ++#ifdef GESTURES ++#include "gesture.h" ++#endif ++ + #define GuaranteeNothing 0 + #define GuaranteeVisBack 1 + +@@ -94,6 +102,9 @@ + RegionPtr inputShape; /* default: NULL */ + struct _OtherInputMasks *inputMasks; /* default: NULL */ + DevCursorList deviceCursors; /* default: NULL */ ++#ifdef GESTURES ++ struct _GestureMasks *gestureMasks; /* default: NULL */ ++#endif + } WindowOptRec, *WindowOptPtr; + + #define BackgroundPixel 2L +@@ -202,6 +213,9 @@ + #define wInputShape(w) wUseDefault(w, inputShape, NULL) + #define wClient(w) (clients[CLIENT_ID((w)->drawable.id)]) + #define wBorderWidth(w) ((int) (w)->borderWidth) ++#ifdef GESTURES ++#define wGestureMasks(w) wUseDefault(w, gestureMasks, NULL) ++#endif + + /* true when w needs a border drawn. */ + +Index: xorg-server/mi/mieq.c +=================================================================== +--- xorg-server.orig/mi/mieq.c 2011-08-24 12:56:49.865650624 +0300 ++++ xorg-server/mi/mieq.c 2011-08-24 12:56:49.895650626 +0300 +@@ -58,6 +58,8 @@ + # include <X11/extensions/dpmsconst.h> + #endif + ++#include "gestureproto.h" ++ + #define QUEUE_SIZE 512 + + #define EnqueueScreen(dev) dev->spriteInfo->sprite->pEnqueueScreen +@@ -383,6 +385,39 @@ + + CHECKEVENT(event); + ++ if (event->any.header == ET_Internal && event->any.type == ET_Gesture){ ++ GestureEvent gev; ++ DeviceEvent *ev = (DeviceEvent *)event; ++ ClientPtr client = clients[ev->gesture.client_id]; ++ ++ /* Check if client still exists */ ++ if (!client) ++ return; ++ ++ gev.type = GenericEvent; ++ gev.extension = GestureReqCode; ++ gev.sequenceNumber = client->sequence; ++ gev.evtype = 0; ++ gev.time = ev->time; ++ gev.length = (sizeof(GestureEvent) + ++ ev->gesture.num_props * sizeof(float) - ++ sizeof(xEvent)) / 4; ++ gev.gesture_id = ev->gesture.id; ++ gev.gesture_type = ev->gesture.type; ++ gev.device_id = ev->deviceid; ++ gev.root = ev->root; ++ gev.event = ev->gesture.event; ++ gev.child = ev->gesture.child; ++ gev.focus_x = ev->root_x; ++ gev.focus_y = ev->root_y; ++ gev.status = ev->gesture.status; ++ gev.num_props = ev->gesture.num_props; ++ ++ WriteToClient(client, sizeof(GestureEvent), &gev); ++ WriteToClient(client, sizeof(float) * gev.num_props, ev->gesture.props); ++ return; ++ } ++ + /* Custom event handler */ + handler = miEventQueue.handlers[event->any.type]; + +Index: xorg-server/mi/miinitext.c +=================================================================== +--- xorg-server.orig/mi/miinitext.c 2011-08-24 12:52:43.285647113 +0300 ++++ xorg-server/mi/miinitext.c 2011-08-24 12:56:49.895650626 +0300 +@@ -152,6 +152,9 @@ + #ifdef XV + extern Bool noXvExtension; + #endif ++#ifdef GESTURES ++extern Bool noGestureExtension; ++#endif + extern Bool noGEExtension; + + #ifndef XFree86LOADER +@@ -263,6 +266,9 @@ + extern void CompositeExtensionInit(INITARGS); + #endif + extern void GEExtensionInit(INITARGS); ++#ifdef GESTURES ++extern void GestureExtensionInit(INITARGS); ++#endif + + /* The following is only a small first step towards run-time + * configurable extensions. +@@ -334,6 +340,9 @@ + #ifdef XV + { "XVideo", &noXvExtension }, + #endif ++#ifdef GESTURES ++ { "Gesture", &noGestureExtension }, ++#endif + { NULL, NULL } + }; + +@@ -470,6 +479,9 @@ + GlxPushProvider(&__glXDRISWRastProvider); + if (!noGlxExtension) GlxExtensionInit(); + #endif ++#ifdef GESTURES ++ if (!noGestureExtension) GestureExtensionInit(); ++#endif + } + + #else /* XFree86LOADER */ +@@ -511,6 +523,9 @@ + #ifdef DAMAGE + { DamageExtensionInit, "DAMAGE", &noDamageExtension, NULL }, + #endif ++#ifdef GESTURES ++ { GestureExtensionInit, "GESTURE", &noGestureExtension, NULL }, ++#endif + { NULL, NULL, NULL, NULL, NULL } + }; + +Index: xorg-server/os/utils.c +=================================================================== +--- xorg-server.orig/os/utils.c 2011-08-24 12:56:49.765650622 +0300 ++++ xorg-server/os/utils.c 2011-08-24 12:56:49.895650626 +0300 +@@ -185,6 +185,9 @@ + #ifdef DRI2 + Bool noDRI2Extension = FALSE; + #endif ++#ifdef GESTURES ++Bool noGestureExtension = FALSE; ++#endif + + Bool noGEExtension = FALSE; + diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-touch_grab_reject_send_ownership.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-touch_grab_reject_send_ownership.patch new file mode 100644 index 0000000..368643b --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-touch_grab_reject_send_ownership.patch @@ -0,0 +1,12 @@ +--- a/Xi/exevents.c ++++ b/Xi/exevents.c +@@ -1647,7 +1647,8 @@ ProcessTouchOwnership(DeviceIntPtr dev, + if (ev == ti->history + ti->history_size) + ev = ti->history; + } +- } else if (tc->type == TOUCH_SELECT_UNOWNED && ++ } else if ((tc->type == TOUCH_SELECT_UNOWNED || ++ tc->type == TOUCH_GRAB) && + !ti->emulate_pointer) { + DeliverTouchOwnershipEvent(tc, ti); + } diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-xf86CoordinatesToWindow.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-xf86CoordinatesToWindow.patch new file mode 100644 index 0000000..51355ef --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-xf86CoordinatesToWindow.patch @@ -0,0 +1,97 @@ +Index: xorg-server/dix/events.c +=================================================================== +--- xorg-server.orig/dix/events.c 2011-08-24 12:56:49.855650623 +0300 ++++ xorg-server/dix/events.c 2011-08-24 12:57:14.725650980 +0300 +@@ -6385,3 +6385,47 @@ + return FALSE; + } + ++WindowPtr ++CoordinatesToWindow(int x, int y, int screen) ++{ ++ WindowPtr pWin; ++ WindowPtr ret = NullWindow; ++ BoxRec box; ++ ++ pWin = screenInfo.screens[screen]->root; ++ while (pWin) ++ { ++ if ((pWin->mapped) && ++ (x >= pWin->drawable.x - wBorderWidth (pWin)) && ++ (x < pWin->drawable.x + (int)pWin->drawable.width + ++ wBorderWidth(pWin)) && ++ (y >= pWin->drawable.y - wBorderWidth (pWin)) && ++ (y < pWin->drawable.y + (int)pWin->drawable.height + ++ wBorderWidth (pWin)) ++ /* When a window is shaped, a further check ++ * is made to see if the point is inside ++ * borderSize ++ */ ++ && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y)) ++ && (!wInputShape(pWin) || ++ RegionContainsPoint(wInputShape(pWin), ++ x - pWin->drawable.x, ++ y - pWin->drawable.y, &box)) ++#ifdef ROOTLESS ++ /* In rootless mode windows may be offscreen, even when ++ * they're in X's stack. (E.g. if the native window system ++ * implements some form of virtual desktop system). ++ */ ++ && !pWin->rootlessUnhittable ++#endif ++ ) ++ { ++ ret = pWin; ++ pWin = pWin->firstChild; ++ } ++ else ++ pWin = pWin->nextSib; ++ } ++ return ret; ++} ++ +Index: xorg-server/hw/xfree86/common/xf86Xinput.c +=================================================================== +--- xorg-server.orig/hw/xfree86/common/xf86Xinput.c 2011-08-24 12:56:49.855650623 +0300 ++++ xorg-server/hw/xfree86/common/xf86Xinput.c 2011-08-24 12:57:14.715650981 +0300 +@@ -1465,4 +1465,10 @@ + mieqEnqueue(dev, (InternalEvent *)((xf86Events + i)->event)); + } + ++WindowPtr ++xf86CoordinatesToWindow(int x, int y, int screen) ++{ ++ return CoordinatesToWindow(x, y, screen); ++} ++ + /* end of xf86Xinput.c */ +Index: xorg-server/hw/xfree86/common/xf86Xinput.h +=================================================================== +--- xorg-server.orig/hw/xfree86/common/xf86Xinput.h 2011-08-24 12:56:49.865650624 +0300 ++++ xorg-server/hw/xfree86/common/xf86Xinput.h 2011-08-24 12:56:49.875650625 +0300 +@@ -184,4 +184,6 @@ + /* xf86Option.c */ + extern _X_EXPORT void xf86CollectInputOptions(InputInfoPtr pInfo, const char **defaultOpts); + ++extern _X_EXPORT WindowPtr xf86CoordinatesToWindow(int x, int y, int screen); ++ + #endif /* _xf86Xinput_h */ +Index: xorg-server/include/events.h +=================================================================== +--- xorg-server.orig/include/events.h 2011-08-24 12:56:49.865650624 +0300 ++++ xorg-server/include/events.h 2011-08-24 12:56:49.875650625 +0300 +@@ -24,6 +24,7 @@ + + #ifndef EVENTS_H + #define EVENTS_H ++ + typedef struct _DeviceEvent DeviceEvent; + typedef struct _DeviceChangedEvent DeviceChangedEvent; + typedef struct _TouchOwnershipEvent TouchOwnershipEvent; +@@ -36,4 +37,6 @@ + #endif + typedef union _InternalEvent InternalEvent; + ++extern WindowPtr CoordinatesToWindow(int x, int y, int screen); ++ + #endif diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch new file mode 100644 index 0000000..26be6ef --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch @@ -0,0 +1,4603 @@ +Index: xorg-server/Xi/allowev.c +=================================================================== +--- xorg-server.orig/Xi/allowev.c 2011-08-24 12:52:43.965647120 +0300 ++++ xorg-server/Xi/allowev.c 2011-08-24 12:56:49.845650625 +0300 +@@ -125,5 +125,24 @@ + client->errorValue = stuff->mode; + return BadValue; + } ++ ++ /* If this is a master pointer with an active touch emulation and the touch ++ * has physically ceased, end the touchpoint state. */ ++ if (thisdev->emulate_dev) ++ { ++ DeviceIntPtr sourcedev = thisdev->emulate_dev; ++ TouchPointInfoPtr ti = sourcedev->touch->emulate; ++ ++ if (ti->pending_finish && ti->owner < 0) ++ EndTouchPoint(sourcedev, ti); ++ else if (ti->pending_finish) ++ { ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ if (tc->type == TOUCH_SELECT || tc->type == TOUCH_SELECT_UNOWNED) ++ EndTouchPoint(sourcedev, ti); ++ } ++ } ++ + return Success; + } +Index: xorg-server/Xi/exevents.c +=================================================================== +--- xorg-server.orig/Xi/exevents.c 2011-08-24 12:56:49.835650626 +0300 ++++ xorg-server/Xi/exevents.c 2011-08-24 12:56:49.855650623 +0300 +@@ -44,6 +44,31 @@ + + ********************************************************/ + ++/* ++ * Copyright © 2010 Collabora Ltd. ++ * ++ * 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@fooishbar.org> ++ */ ++ + /******************************************************************** + * + * Routines to register and initialize extension input devices. +@@ -77,6 +102,9 @@ + #include "xiquerydevice.h" /* For List*Info */ + #include "eventconvert.h" + #include "eventstr.h" ++#include "xserver-properties.h" ++#include "inpututils.h" ++#include "mi.h" + + #include <X11/extensions/XKBproto.h> + #include "xkbsrv.h" +@@ -127,6 +155,20 @@ + return FALSE; + } + ++Bool ++IsTouchEvent(InternalEvent* event) ++{ ++ switch(event->any.type) ++ { ++ case ET_TouchBegin: ++ case ET_TouchEnd: ++ case ET_TouchMotion: ++ return TRUE; ++ default: ++ 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. +@@ -722,6 +764,46 @@ + XISendDeviceChangedEvent(slave, device, dce); + } + ++#define DEFAULT 0 ++#define DONT_PROCESS 1 ++int ++ReleaseButton(DeviceIntPtr device, int button) ++{ ++ ButtonClassPtr b = device->button; ++ int i; ++ ++ if (IsMaster(device)) { ++ DeviceIntPtr sd; ++ ++ /* ++ * Leave the button down if any slave has the ++ * button still down. Note that this depends on the ++ * event being delivered through the slave first ++ */ ++ for (sd = inputInfo.devices; sd; sd = sd->next) { ++ if (IsMaster(sd) || sd->u.master != device) ++ continue; ++ if (!sd->button) ++ continue; ++ for (i = 1; i <= sd->button->numButtons; i++) ++ if (sd->button->map[i] == button && ++ button_is_down(sd, i, BUTTON_PROCESSED)) ++ return DONT_PROCESS; ++ } ++ } ++ set_button_up(device, button, BUTTON_PROCESSED); ++ if (device->valuator) ++ device->valuator->motionHintWindow = NullWindow; ++ if (!b->map[button]) ++ return DONT_PROCESS; ++ if (b->buttonsDown >= 1 && !--b->buttonsDown) ++ b->motionMask = 0; ++ if (b->map[button] <= 5) ++ b->state &= ~((Button1Mask >> 1) << b->map[button]); ++ ++ return DEFAULT; ++} ++ + /** + * Update the device state according to the data in the event. + * +@@ -729,8 +811,6 @@ + * DEFAULT ... process as normal + * DONT_PROCESS ... return immediately from caller + */ +-#define DEFAULT 0 +-#define DONT_PROCESS 1 + int + UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event) + { +@@ -854,34 +934,9 @@ + + if (!button_is_down(device, key, BUTTON_PROCESSED)) + return DONT_PROCESS; +- if (IsMaster(device)) { +- DeviceIntPtr sd; + +- /* +- * Leave the button down if any slave has the +- * button still down. Note that this depends on the +- * event being delivered through the slave first +- */ +- for (sd = inputInfo.devices; sd; sd = sd->next) { +- if (IsMaster(sd) || sd->u.master != device) +- continue; +- if (!sd->button) +- continue; +- for (i = 1; i <= sd->button->numButtons; i++) +- if (sd->button->map[i] == key && +- button_is_down(sd, i, BUTTON_PROCESSED)) +- return DONT_PROCESS; +- } +- } +- set_button_up(device, key, BUTTON_PROCESSED); +- if (device->valuator) +- device->valuator->motionHintWindow = NullWindow; +- if (!b->map[key]) ++ if (ReleaseButton(device, key) == DONT_PROCESS) + return DONT_PROCESS; +- if (b->buttonsDown >= 1 && !--b->buttonsDown) +- b->motionMask = 0; +- if (b->map[key] <= 5) +- b->state &= ~((Button1Mask >> 1) << b->map[key]); + + /* Add state and motionMask to the filter for this event */ + mask = DevicePointerMotionMask | b->state | b->motionMask; +@@ -897,6 +952,955 @@ + } + + /** ++ * Add a touch client to the list of clients for the touch point. Return TRUE ++ * if the caller should stop processing touch clients. ++ */ ++static Bool ++AddTouchClient(TouchPointInfoPtr ti, int client_id, WindowPtr window, ++ TouchClientType type, DeviceIntPtr dev, DeviceIntPtr sourcedev, ++ GrabPtr grab) ++{ ++ TouchClientPtr client; ++ ++ ti->active_clients++; ++ if (ti->active_clients > ti->num_clients) ++ { ++ int num_clients = ti->num_clients ? ti->num_clients * 2 : 2; ++ ++ TouchClientPtr tmp; ++ tmp = realloc(ti->clients, num_clients * sizeof(TouchClientRec)); ++ ++ if (tmp) ++ { ++ ti->clients = tmp; ++ ti->num_clients = num_clients; ++ } else { ++ LogMessage(X_ERROR, "failed to reallocate touch clients\n"); ++ return TRUE; ++ } ++ } ++ ++ client = &ti->clients[ti->active_clients - 1]; ++ client->client = clients[client_id]; ++ client->window = window; ++ client->type = type; ++ client->device = dev; ++ client->source = sourcedev; ++ client->grab = grab; ++ ++ return FALSE; ++} ++ ++/** ++ * Ensure a list of clients for a touchpoint, constructing one for TouchBegin ++ * events. Returns TRUE if a touch client exists, FALSE if none. ++ */ ++static Bool ++EnsureTouchClients(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, ++ InternalEvent *ev) ++{ ++ TouchClassPtr t = sourcedev->touch; ++ SpritePtr sprite = &ti->sprite; ++ DeviceIntPtr masterdev = sourcedev->u.master; ++ int i; ++ ++ if (ev->any.type != ET_TouchBegin) ++ return (ti->active_clients > 0); ++ ++ if (ti->active_clients > 0) ++ LogMessage(X_ERROR, "Getting touch clients for active touch\n"); ++ ++ /* Create sprite trace for the touchpoint */ ++ 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 ++ { ++ WindowPtr *trace; ++ SpritePtr srcsprite; ++ ++ /* Find and reuse an existing, physically active touch's sprite and ++ * touch client list if possible, else use the device's pointer sprite ++ * and generate a new list of touch clients. */ ++ for (i = 0; i < t->num_touches; i++) ++ if (!t->touches[i].ddx_pending_finish && ++ t->touches[i].active_clients > 0) ++ break; ++ if (i < t->num_touches) { ++ srcsprite = &t->touches[i].sprite; ++ ti->active_clients = t->touches[i].active_clients; ++ ++ if (ti->active_clients > ti->num_clients) ++ { ++ TouchClientPtr tmp; ++ ++ tmp = realloc(ti->clients, ++ ti->active_clients * sizeof(TouchClientRec)); ++ if (!tmp) ++ { ++ ti->active_clients = 0; ++ ti->owner = -1; ++ return FALSE; ++ } ++ ti->clients = tmp; ++ ti->num_clients = ti->active_clients; ++ } ++ memcpy(ti->clients, t->touches[i].clients, ++ ti->active_clients * sizeof(TouchClientRec)); ++ } ++ else if (sourcedev->spriteInfo->sprite) ++ srcsprite = sourcedev->spriteInfo->sprite; ++ else ++ return FALSE; ++ ++ if (srcsprite->spriteTraceGood > sprite->spriteTraceSize) ++ { ++ trace = realloc(sprite->spriteTrace, ++ srcsprite->spriteTraceSize * sizeof(*trace)); ++ if (!trace) ++ { ++ sprite->spriteTraceGood = 0; ++ ti->active_clients = 0; ++ ti->owner = -1; ++ return FALSE; ++ } ++ sprite->spriteTrace = trace; ++ sprite->spriteTraceSize = srcsprite->spriteTraceGood; ++ } ++ memcpy(sprite->spriteTrace, srcsprite->spriteTrace, ++ srcsprite->spriteTraceGood * sizeof(*trace)); ++ sprite->spriteTraceGood = srcsprite->spriteTraceGood; ++ ++ if (ti->active_clients) ++ return TRUE; ++ } ++ ++ if (sprite->spriteTraceGood <= 0) ++ return FALSE; ++ ++ /* Search for touch grab clients from root to child windows. */ ++ for (i = 0; i < sprite->spriteTraceGood; i++) ++ { ++ WindowPtr win = sprite->spriteTrace[i]; ++ GrabPtr grab; ++ InternalEvent ev; ++ ++ ev.any.type = ET_TouchBegin; ++ if ((grab = CheckPassiveGrabsOnWindow(win, sourcedev, &ev, FALSE, ++ FALSE))) ++ { ++ if (AddTouchClient(ti, CLIENT_ID(grab->resource), win, TOUCH_GRAB, ++ sourcedev, sourcedev, grab)) ++ goto done; ++ continue; ++ } ++ if (masterdev && ++ (grab = CheckPassiveGrabsOnWindow(win, masterdev, &ev, FALSE, ++ FALSE))) ++ { ++ if (AddTouchClient(ti, CLIENT_ID(grab->resource), win, TOUCH_GRAB, ++ masterdev, sourcedev, grab)) ++ goto done; ++ continue; ++ } ++ } ++ ++ /* Search for one touch select client from child to root windows. */ ++ for (i = sprite->spriteTraceGood - 1; i >= 0; i--) ++ { ++ WindowPtr win = sprite->spriteTrace[i]; ++ OtherInputMasks *inputMasks = wOtherInputMasks(win); ++ ++ /* Is anyone listening for unowned events on this window? */ ++ if (inputMasks && ++ (BitIsOn(inputMasks->xi2mask[XIAllDevices], ++ XI_TouchUpdateUnowned) || ++ BitIsOn(inputMasks->xi2mask[sourcedev->id], ++ XI_TouchUpdateUnowned) || ++ (masterdev && ++ (BitIsOn(inputMasks->xi2mask[XIAllMasterDevices], ++ XI_TouchUpdateUnowned) || ++ BitIsOn(inputMasks->xi2mask[masterdev->id], ++ XI_TouchUpdateUnowned))))) ++ { ++ InputClientsPtr inputClients = inputMasks->inputClients; ++ ++ /* Find the one client listening for unowned events. */ ++ for (inputClients = inputMasks->inputClients; ++ inputClients; ++ inputClients = inputClients->next) ++ { ++ if (BitIsOn(inputClients->xi2mask[XIAllDevices], ++ XI_TouchUpdateUnowned) || ++ BitIsOn(inputClients->xi2mask[sourcedev->id], ++ XI_TouchUpdateUnowned)) ++ { ++ AddTouchClient(ti, CLIENT_ID(inputClients->resource), ++ win, TOUCH_SELECT_UNOWNED, sourcedev, ++ sourcedev, NULL); ++ goto done; ++ } ++ else if (masterdev && ++ (BitIsOn(inputClients->xi2mask[XIAllMasterDevices], ++ XI_TouchUpdateUnowned) || ++ BitIsOn(inputClients->xi2mask[masterdev->id], ++ XI_TouchUpdateUnowned))) ++ { ++ AddTouchClient(ti, CLIENT_ID(inputClients->resource), ++ win, TOUCH_SELECT_UNOWNED, masterdev, ++ sourcedev, NULL); ++ goto done; ++ } ++ } ++ } ++ ++ /* Is anyone listening for only owned events on this window? */ ++ if (inputMasks && ++ (BitIsOn(inputMasks->xi2mask[XIAllDevices], XI_TouchUpdate) || ++ BitIsOn(inputMasks->xi2mask[sourcedev->id], XI_TouchUpdate) || ++ (masterdev && ++ (BitIsOn(inputMasks->xi2mask[XIAllMasterDevices], ++ XI_TouchUpdate) || ++ BitIsOn(inputMasks->xi2mask[masterdev->id], ++ XI_TouchUpdate))))) ++ { ++ InputClientsPtr inputClients = inputMasks->inputClients; ++ ++ /* Find the one client listening for owned events. */ ++ for (inputClients = inputMasks->inputClients; ++ inputClients; ++ inputClients = inputClients->next) ++ { ++ if (BitIsOn(inputClients->xi2mask[XIAllDevices], ++ XI_TouchUpdate) || ++ BitIsOn(inputClients->xi2mask[sourcedev->id], ++ XI_TouchUpdate)) ++ { ++ AddTouchClient(ti, CLIENT_ID(inputClients->resource), win, ++ TOUCH_SELECT, sourcedev, sourcedev, NULL); ++ goto done; ++ } ++ else if (masterdev && ++ (BitIsOn(inputClients->xi2mask[XIAllMasterDevices], ++ XI_TouchUpdate) || ++ BitIsOn(inputClients->xi2mask[masterdev->id], ++ XI_TouchUpdate))) ++ { ++ AddTouchClient(ti, CLIENT_ID(inputClients->resource), win, ++ TOUCH_SELECT, masterdev, sourcedev, NULL); ++ goto done; ++ } ++ } ++ } ++ } ++ ++done: ++ return (ti->active_clients > 0); ++} ++ ++/** ++ * Attempts to deliver a touch event to the given client. ++ */ ++static Bool ++DeliverOneTouchEvent(TouchClientPtr client, TouchPointInfoPtr ti, ++ InternalEvent *ev) ++{ ++ int err; ++ xEvent *xi2; ++ Mask filter; ++ Window child = DeepestSpriteWin(&ti->sprite)->drawable.id; ++ ++ /* 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 DeliverOneTouchEvent" ++ " (%d)\n", client->device->name, err); ++ ++ FixUpEventFromWindow(&ti->sprite, xi2, client->window, child, FALSE); ++ filter = GetEventFilter(client->device, xi2); ++ if (XaceHook(XACE_RECEIVE_ACCESS, client->client, client->window, xi2, 1) ++ != Success) ++ return FALSE; ++ err = TryClientEvents(client->client, client->device, 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; ++} ++ ++/** ++ * Deliver touch ownership event directly to client. ++ */ ++int ++DeliverTouchOwnershipEvent(TouchClientPtr client, TouchPointInfoPtr ti) ++{ ++ TouchOwnershipEvent event; ++ ++ memset(&event, 0, sizeof(TouchOwnershipEvent)); ++ event.header = ET_Internal; ++ event.type = ET_TouchOwnership; ++ event.length = sizeof(TouchOwnershipEvent); ++ event.time = GetTimeInMillis(); ++ event.deviceid = client->device->id; ++ event.sourceid = client->source->id; ++ event.touchid = ti->client_id; ++ ++ DeliverOneTouchEvent(client, ti, (InternalEvent *)&event); ++ ++ return 1; ++} ++ ++/* Add the given event to the history for the touch point. */ ++static void ++UpdateTouchHistory(TouchPointInfoPtr ti, InternalEvent *ev) ++{ ++ /* Copy begin events off to the side. This prevents the ring buffer ++ overrunning and erasing the begin event. */ ++ if (ev->any.type == ET_TouchBegin) ++ memcpy(ti->begin_event, ev, sizeof(InternalEvent)); ++ else ++ { ++ memcpy(ti->next_history, ev, sizeof(InternalEvent)); ++ ++ ti->next_history++; ++ if (ti->next_history == ti->history + ti->history_size) ++ ti->next_history = ti->history; ++ ++ /* If the ring overruns, advance the first pointer so we keep as many ++ events as possible. */ ++ if (ti->next_history == ti->first_history) ++ { ++ ti->first_history++; ++ if (ti->first_history == ti->history + ti->history_size) ++ ti->first_history = ti->history; ++ } ++ } ++} ++ ++/** ++ * Helper to get a static EventList for pointer emulation. ++ */ ++static EventList * ++GetEvents(void) ++{ ++ static EventList *events = NULL; ++ ++ /* Allocate twice the maximum number of events for motion and button ++ * emulation. */ ++ if (!events) ++ events = InitEventList(2 * GetMaximumEventsNum()); ++ ++ return events; ++} ++ ++/* Helper function to set up touch pointer emulation. */ ++static void ++SetTouchEmulationMask(InternalEvent *ev, ValuatorMask *mask, int x_axis, ++ int y_axis) ++{ ++ valuator_mask_zero(mask); ++ if (BitIsOn(ev->device_event.valuators.mask, x_axis)) ++ valuator_mask_set(mask, 0, ++ ev->device_event.valuators.data[x_axis]); ++ if (BitIsOn(ev->device_event.valuators.mask, y_axis)) ++ valuator_mask_set(mask, 1, ++ ev->device_event.valuators.data[y_axis]); ++} ++ ++/* Process touch emulation. */ ++static void ++EmulateTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev) ++{ ++ EventList *emulationEvents = GetEvents(); ++ ValuatorMask mask; ++ InternalEvent mevent; ++ DeviceIntPtr master = dev->u.master; ++ enum EventType evtype = ev->any.type; ++ int nevents = 0; ++ int x_axis = dev->touch->x_axis; ++ int y_axis = dev->touch->y_axis; ++ int i; ++ ++ /* Set the emulation touch for the device. Only one touch may be emulated ++ * at a time. */ ++ if (dev->touch->emulate != ti) ++ return; ++ ++ /* Emulate a normal event. */ ++ SetTouchEmulationMask(ev, &mask, x_axis, y_axis); ++ ++ if (evtype == ET_TouchBegin) ++ { ++ nevents = GetPointerEvents(emulationEvents, dev, ++ MotionNotify, 0, POINTER_ABSOLUTE, &mask); ++ nevents += GetPointerEvents(emulationEvents + nevents, dev, ++ ButtonPress, 1, POINTER_ABSOLUTE, &mask); ++ } ++ else if (evtype == ET_TouchMotion) ++ nevents = GetPointerEvents(emulationEvents, dev, MotionNotify, 0, ++ POINTER_ABSOLUTE, &mask); ++ else if (evtype == ET_TouchEnd) ++ { ++ nevents = GetPointerEvents(emulationEvents, dev, MotionNotify, 0, ++ POINTER_ABSOLUTE, &mask); ++ nevents += GetPointerEvents(emulationEvents + nevents, dev, ++ ButtonRelease, 1, POINTER_ABSOLUTE, &mask); ++ } ++ ++ if (ti->emulate_pointer) ++ { ++ for (i = 0; i < nevents; i++) ++ { ++ InternalEvent *event = (InternalEvent *)((emulationEvents + i)->event); ++ ++ event->device_event.flags |= XIPointerEmulated; ++ event->device_event.touchpoint = ev->device_event.touchpoint; ++ ++ if (master) ++ { ++ master->u.lastSlave = dev; ++ ++ CopyGetMasterEvent(dev, event, &mevent); ++ ++ /* If a grab has been activated but no event has been handled ++ * yet, then the grab is a touch grab. Store the pointer ++ * emulation event for now, ready for replay when the touch grab ++ * is relinquished. */ ++ if (master->deviceGrab.sync.state == FROZEN_NO_EVENT) ++ { ++ GrabInfoPtr grabinfo = &master->deviceGrab; ++ ++ grabinfo->sync.state = FROZEN_WITH_EVENT; ++ if (!grabinfo->sync.event) ++ grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); ++ *grabinfo->sync.event = event->device_event; ++ } ++ else ++ master->public.processInputProc(&mevent, master); ++ } ++ } ++ } ++ ++ /* If there are touch clients on a pointer emulated touchpoint, send touch ++ * events through traditional device processing as well. */ ++ if (master && ti->active_clients > 0 && ++ (ev->any.type != ET_TouchEnd || ++ (ti->clients[ti->active_clients - 1].type == TOUCH_SELECT || ++ ti->clients[ti->active_clients - 1].type == TOUCH_SELECT_UNOWNED))) ++ { ++ ev->device_event.flags |= XIPointerEmulated; ++ master->u.lastSlave = dev; ++ CopyGetMasterEvent(dev, ev, &mevent); ++ master->process_touch = TRUE; ++ master->public.processInputProc(&mevent, master); ++ master->process_touch = FALSE; ++ ++ /* If grabbed by an implicit touch grab from FindFirstGrab, release it ++ * now. */ ++ if (master->deviceGrab.grab && ++ master->deviceGrab.grab->type == ET_TouchBegin && ++ master->deviceGrab.implicitGrab) ++ master->deviceGrab.DeactivateGrab(master); ++ } ++} ++ ++#define ImplicitGrabMask (1 << 7) ++/** ++ * Find the first grab of a new touchpoint. Returns TRUE if a grab was found. ++ */ ++static Bool ++FindFirstGrab(DeviceIntPtr dev, TouchPointInfoPtr ti) ++{ ++ DeviceIntPtr master = dev->u.master; ++ InternalEvent p_event; ++ InternalEvent t_event; ++ GrabRec tempGrab; ++ int i, j; ++ ++ p_event.any.type = ET_ButtonPress; ++ t_event.any.type = ET_TouchBegin; ++ ++ j = ti->owner >= 0 ? ti->owner : 0; ++ ++ for (i = 0; i < ti->sprite.spriteTraceGood; i++) ++ { ++ WindowPtr win = ti->sprite.spriteTrace[i]; ++ TouchClientPtr client = &ti->clients[j]; ++ GrabPtr grab; ++ ++ /* If master pointer is already grabbed, bypass touch grabs above. */ ++ if (ti->emulate_pointer && master->deviceGrab.grab) ++ { ++ if (win == master->deviceGrab.grab->window) ++ { ++ if (j >= ti->active_clients - 1) ++ { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ } else ++ ti->owner = j + 1; ++ return TRUE; ++ } else ++ goto next; ++ } ++ ++ /* Check for a touch grab on this window. */ ++ if (j < ti->active_clients && win == client->window && ++ client->type == TOUCH_GRAB) ++ { ++ client->device->deviceGrab.ActivateGrab(client->device, ++ client->grab, currentTime, ++ TRUE); ++ ti->owner = j; ++ return TRUE; ++ } ++ ++ if (!ti->emulate_pointer) ++ goto next; ++ ++ /* Check for a passive pointer grab on this window. */ ++ grab = CheckPassiveGrabsOnWindow(win, dev, &p_event, TRUE, FALSE); ++ if (grab) ++ { ++ if (grab->pointerMode == GrabModeAsync) ++ { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ } ++ ++ return TRUE; ++ } ++ else if (master) ++ { ++ grab = CheckPassiveGrabsOnWindow(win, master, &p_event, TRUE, ++ FALSE); ++ if (grab) ++ { ++ if (grab->pointerMode == GrabModeAsync) ++ { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ } ++ ++ return TRUE; ++ } ++ } ++ ++next: ++ if (j < ti->active_clients && win == client->window) ++ j++; ++ } ++ ++ /* Even when there's no grabbing clients, we need to sync events so we can ++ * properly check for touch vs pointer selection in DeliverDeviceEvents. ++ * Create a temporary implicit touch grab here, and deactivate it after ++ * enqueuing emulated pointer events. */ ++ if (ti->emulate_pointer) ++ { ++ memset(&tempGrab, 0, sizeof(GrabRec)); ++ tempGrab.next = NULL; ++ tempGrab.device = master; ++ tempGrab.resource = 0; ++ tempGrab.window = ti->sprite.spriteTrace[0]; ++ tempGrab.ownerEvents = FALSE; ++ tempGrab.eventMask = 0; ++ tempGrab.keyboardMode = GrabModeAsync; ++ tempGrab.pointerMode = GrabModeSync; ++ tempGrab.confineTo = NullWindow; ++ tempGrab.cursor = NullCursor; ++ tempGrab.type = ET_TouchBegin; ++ tempGrab.grabtype = GRABTYPE_XI2; ++ tempGrab.deviceMask = 0; ++ ++ master->deviceGrab.ActivateGrab(master, &tempGrab, currentTime, ++ TRUE | ImplicitGrabMask); ++ } ++ ++ return FALSE; ++} ++ ++void ++ProcessTouchOwnership(DeviceIntPtr dev, TouchPointInfoPtr ti, uint8_t reason, ++ Bool touch_grab) ++{ ++ DeviceIntPtr sourcedev = ti->source; ++ DeviceIntPtr masterdev; ++ ++ masterdev = dev->u.master; ++ ++ if (reason == XITouchOwnerAccept) ++ { ++ TouchClientPtr client; ++ DeviceEvent event; ++ int i; ++ ++ init_event(dev, &event, GetTimeInMillis()); ++ event.type = ET_TouchEnd; ++ event.detail.touch = ti->client_id; ++ event.touchpoint = ti; ++ ++ for (i = ti->owner + 1; i < ti->active_clients; i++) ++ { ++ client = &ti->clients[i]; ++ ++ if (client->type == TOUCH_GRAB || ++ client->type == TOUCH_SELECT_UNOWNED) ++ { ++ event.deviceid = client->device->id; ++ event.sourceid = client->source->id; ++ ++ DeliverOneTouchEvent(client, ti, (InternalEvent *)&event); ++ } ++ } ++ ++ if (!touch_grab) ++ { ++ ti->active_clients = 0; ++ ti->owner = -1; ++ RemoveTouchEventsFromQueue(masterdev, TRUE, FALSE); ++ return; ++ } ++ ++ client = &ti->clients[ti->owner]; ++ ti->active_clients = ti->owner + 1; ++ ti->accepted = TRUE; ++ ++ RemoveTouchEventsFromQueue(masterdev, FALSE, FALSE); ++ RemoveTouchEventsFromQueue(masterdev, TRUE, FALSE); ++ ReleaseButton(masterdev, 1); ++ ++ if (ti->emulate_pointer) ++ masterdev->deviceGrab.DeactivateGrab(masterdev); ++ ++ ti->emulate_pointer = FALSE; ++ ++ if (ti->pending_finish) ++ { ++ event.deviceid = client->device->id; ++ event.sourceid = client->source->id; ++ ++ DeliverOneTouchEvent(client, ti, (InternalEvent *)&event); ++ EndTouchPoint(sourcedev, ti); ++ } ++ } else { ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ GrabPtr grab = masterdev->deviceGrab.grab; ++ ++ if (touch_grab) ++ { ++ DeviceEvent event; ++ ++ tc = &ti->clients[ti->owner]; ++ ++ init_event(tc->device, &event, GetTimeInMillis()); ++ event.type = ET_TouchEnd; ++ event.detail.touch = ti->client_id; ++ event.deviceid = tc->device->id; ++ event.sourceid = tc->source->id; ++ event.touchpoint = ti; ++ ++ DeliverOneTouchEvent(tc, ti, (InternalEvent *)&event); ++ ++ ti->owner++; ++ } ++ ++ if (ti->owner >= ti->active_clients) ++ { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ tc = NULL; ++ } else { ++ tc = &ti->clients[ti->owner]; ++ ++ if (tc->type == TOUCH_SELECT && !ti->emulate_pointer) ++ { ++ InternalEvent *ev; ++ Bool ret; ++ ++ /* Deliver the saved touch begin event. */ ++ ret = DeliverOneTouchEvent(tc, ti, ti->begin_event); ++ ++ /* Deliver all the touch motion events in the ring buffer. */ ++ ev = ti->first_history; ++ while (ret && ev != ti->next_history) ++ { ++ ret = DeliverOneTouchEvent(tc, ti, ev); ++ ++ if (ev->any.type == ET_TouchEnd) ++ { ++ ti->pending_finish = TRUE; ++ break; ++ } ++ ++ ev++; ++ if (ev == ti->history + ti->history_size) ++ ev = ti->history; ++ } ++ } else if (tc->type == TOUCH_SELECT_UNOWNED && ++ !ti->emulate_pointer) { ++ DeliverTouchOwnershipEvent(tc, ti); ++ } ++ } ++ ++ if (ti->emulate_pointer) ++ { ++ if (ti->active_clients && ++ ti->clients[ti->owner].type == TOUCH_SELECT_UNOWNED) ++ RemoveTouchEventsFromQueue(masterdev, TRUE, TRUE); ++ ++ syncEvents.replayDev = masterdev; ++ if (touch_grab) ++ syncEvents.replayWin = grab->window->parent; ++ else ++ syncEvents.replayWin = grab->window; ++ masterdev->deviceGrab.DeactivateGrab(masterdev); ++ syncEvents.replayDev = NULL; ++ } ++ ++ if (ti->pending_finish && ++ (!tc || (tc->type == TOUCH_SELECT || ++ tc->type == TOUCH_SELECT_UNOWNED)) && ++ (!ti->emulate_pointer || !masterdev->deviceGrab.grab)) ++ EndTouchPoint(sourcedev, ti); ++ } ++} ++ ++/** ++ * Processes and delivers a TouchBegin, TouchMotion, or a TouchEnd event. ++ * ++ * Due to having rather different delivery semantics (see the Xi 2.1 protocol ++ * spec for more information), this implements its own grab and event-selection ++ * delivery logic. ++ */ ++static void ++ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr sourcedev) ++{ ++ DeviceIntPtr masterdev = sourcedev->u.master; ++ TouchClassPtr t = sourcedev->touch; ++ TouchPointInfoPtr ti; ++ TouchClientPtr client; ++ uint32_t touchid; ++ int i; ++ ++ /* We handle deliveries to MDs through the SD, rather than copying ++ * the event and processing it twice. */ ++ if (IsMaster(sourcedev)) ++ return; ++ ++ if (!t) ++ return; ++ ++ /* If we hit 50% utilization of touches, double the number of touch ++ * frames. */ ++ if (t->active_touches > t->num_touches / 2) ++ { ++ void *tmp; ++ ++ tmp = realloc(t->touches, (t->num_touches * 2) * sizeof(*t->touches)); ++ if (tmp) ++ { ++ t->touches = tmp; ++ memset(t->touches + t->num_touches, 0, ++ t->num_touches * sizeof(*t->touches)); ++ ++ for (i = t->num_touches; i < t->num_touches * 2; i++) ++ { ++ if (!InitTouchPoint(t, i)) ++ { ++ LogMessage(X_ERROR, ++ "%s: failed to initialize new touchpoint %d\n", ++ sourcedev->name, i); ++ break; ++ } ++ } ++ t->num_touches = i; ++ ++ LogMessage(X_INFO, "%s: reallocated %d touches\n", sourcedev->name, ++ t->num_touches); ++ } else ++ LogMessage(X_ERROR, "%s: failed to allocate more touches (%d)\n", ++ sourcedev->name, t->num_touches * 2); ++ } ++ ++ touchid = ev->device_event.detail.touch; ++ ti = FindTouchPointByClientID(sourcedev, touchid); ++ if (!ti) ++ { ++ DebugF("[Xi] %s: Received event for inactive touchpoint %d\n", ++ sourcedev->name, touchid); ++ return; ++ } ++ ++ /* Set the emulation touch for a direct touch device. Only one touch may be ++ * emulated per master device at a time. */ ++ if (ev->any.type == ET_TouchBegin && t->mode == XIDirectTouch && ++ masterdev && !masterdev->emulate_dev) ++ { ++ ti->emulate_pointer = TRUE; ++ sourcedev->touch->emulate = ti; ++ masterdev->emulate_dev = sourcedev; ++ } ++ ++ /* Make sure we have a valid list of touch clients for event delivery. */ ++ if (!EnsureTouchClients(sourcedev, ti, ev)) ++ { ++ /* No touch clients, so only attempt to emulate a pointer. */ ++ EmulateTouchEvents(sourcedev, ti, ev); ++ ++ if (ti->active && ev->any.type == ET_TouchEnd) ++ EndTouchPoint(sourcedev, ti); ++ ++ return; ++ } ++ ++ if (ev->any.type == ET_TouchBegin) ++ { ++ if (ti->emulate_pointer) ++ { ++ if (!FindFirstGrab(sourcedev, ti)) ++ { ++ if (ti->clients[0].type == TOUCH_SELECT) ++ { ++ ti->owner = 0; ++ EmulateTouchEvents(sourcedev, ti, ev); ++ return; ++ } ++ else if (ti->clients[0].type == TOUCH_SELECT_UNOWNED) ++ { ++ ti->owner = 0; ++ client = &ti->clients[ti->owner]; ++ ev->device_event.deviceid = client->device->id; ++ ev->device_event.sourceid = client->source->id; ++ DeliverOneTouchEvent(client, ti, ev); ++ EmulateTouchEvents(sourcedev, ti, ev); ++ return; ++ } ++ } else if (ti->owner < 0) ++ /* Pointer grab found, check touch grab first when replayed. */ ++ ev->device_event.check_grab = TRUE; ++ } ++ else ++ ti->owner = 0; ++ } ++ ++ /* Update touch history for non-emulated touches. Emulated touch history is ++ * maintained in syncEvents queue. */ ++ if (!ti->emulate_pointer && !ti->accepted) ++ UpdateTouchHistory(ti, ev); ++ ++ EmulateTouchEvents(sourcedev, ti, ev); ++ ++ if (ti->owner >= 0) ++ client = &ti->clients[ti->owner]; ++ ++ /* Handle the special case where we are ending an emulated touch during an ++ * active pointer grab. */ ++ if (ti == t->emulate && masterdev && masterdev->deviceGrab.grab && ++ !masterdev->deviceGrab.fromPassiveGrab && ++ !masterdev->deviceGrab.implicitGrab && ev->any.type == ET_TouchEnd) ++ { ++ InternalEvent mevent; ++ ++ ev->device_event.flags |= XIPointerEmulated; ++ ++ masterdev->u.lastSlave = sourcedev; ++ CopyGetMasterEvent(sourcedev, ev, &mevent); ++ masterdev->process_touch = TRUE; ++ masterdev->public.processInputProc(&mevent, masterdev); ++ masterdev->process_touch = FALSE; ++ if (client && (client->type == TOUCH_SELECT || ++ client->type == TOUCH_SELECT_UNOWNED)) ++ EndTouchPoint(sourcedev, ti); ++ } ++ ++ /* If a touch is owned, deliver to the owning client. */ ++ if (ti->owner >= 0 && ++ (ti != t->emulate || ti->accepted || ++ ((!client->grab && !sourcedev->deviceGrab.grab && ++ !masterdev->deviceGrab.grab) || ++ (client->grab && sourcedev->deviceGrab.grab && ++ GrabMatchesSecond(sourcedev->deviceGrab.grab, client->grab, FALSE)) || ++ (client->grab && masterdev && masterdev->deviceGrab.grab && ++ GrabMatchesSecond(masterdev->deviceGrab.grab, client->grab, FALSE))))) ++ { ++ if (client->type == TOUCH_GRAB) ++ { ++ /* Mutate end event to a pending finish event for further ++ * clients. */ ++ if (ev->any.type == ET_TouchEnd && !ti->accepted) ++ { ++ ev->any.type = ET_TouchMotion; ++ ev->device_event.flags |= XITouchPendingEnd; ++ ti->pending_finish = TRUE; ++ } ++ ++ ev->device_event.deviceid = client->device->id; ++ ev->device_event.sourceid = client->source->id; ++ ++ DeliverOneTouchEvent(client, ti, ev); ++ if (ev->any.type == ET_TouchBegin) ++ DeliverTouchOwnershipEvent(client, ti); ++ else if (ev->any.type == ET_TouchEnd) ++ EndTouchPoint(sourcedev, ti); ++ } ++ else if (client->type == TOUCH_SELECT || ++ client->type == TOUCH_SELECT_UNOWNED) ++ { ++ ev->device_event.deviceid = client->device->id; ++ ev->device_event.sourceid = client->source->id; ++ ++ if (ev->any.type != ET_TouchEnd) ++ DeliverOneTouchEvent(client, ti, ev); ++ ++ else if (client->type == TOUCH_SELECT_UNOWNED && ++ ev->any.type == ET_TouchBegin) ++ DeliverTouchOwnershipEvent(client, ti); ++ ++ /* An ending emulated touchpoint must release the primary mouse ++ * button. */ ++ if (ev->any.type == ET_TouchEnd) ++ { ++ if (ti == sourcedev->touch->emulate) ++ ReleaseButton(masterdev, 1); ++ else ++ DeliverOneTouchEvent(client, ti, ev); ++ ++ EndTouchPoint(sourcedev, ti); ++ } ++ } ++ } ++ ++ /* Deliver to non-owners. */ ++ if (ev->any.type == ET_TouchMotion) ++ ev->any.type = ET_TouchMotionUnowned; ++ else if (ev->any.type == ET_TouchEnd) ++ { ++ ev->any.type = ET_TouchMotionUnowned; ++ ev->device_event.flags |= XITouchPendingEnd; ++ ti->pending_finish = TRUE; ++ } ++ ++ for (i = ti->owner + 1; i < ti->active_clients; i++) ++ { ++ TouchClientPtr client = &ti->clients[i]; ++ ++ ev->device_event.deviceid = client->device->id; ++ ev->device_event.sourceid = client->source->id; ++ ++ if (client->type == TOUCH_GRAB || ++ client->type == TOUCH_SELECT_UNOWNED) ++ DeliverOneTouchEvent(client, ti, ev); ++ } ++} ++ ++/** + * Main device event processing function. + * Called from when processing the events from the event queue. + * +@@ -925,6 +1929,33 @@ + { + DeliverRawEvent(&ev->raw_event, device); + return; ++ } else if ((!syncEvents.playingEvents && !device->process_touch) && ++ (ev->any.type == ET_TouchBegin || ++ ev->any.type == ET_TouchMotion || ++ ev->any.type == ET_TouchMotionUnowned || ++ ev->any.type == ET_TouchOwnership || ++ ev->any.type == ET_TouchEnd)) ++ { ++ /* The first time through we figure out what to do with the touch. ++ * Further times through (playingEvents or process_touch), we process ++ * the event like any other. */ ++ ProcessTouchEvent(ev, device); ++ return; ++ } ++ ++ /* Ownership events are smaller than device events, so we must handle them ++ * first or we'll corrupt the heap. */ ++ if (ev->any.type == ET_TouchOwnership) ++ { ++ grab = device->deviceGrab.grab; ++ ++ if (grab) ++ DeliverGrabbedEvent(ev, device, FALSE); ++ else ++ DeliverDeviceEvents(GetSpriteWindow(device), ev, NullGrab, ++ NullWindow, device); ++ ++ return; + } + + if (IsPointerDevice(device)) +@@ -1123,6 +2154,50 @@ + dev->proximity->in_proximity = FALSE; + } + ++void ++InitTouchValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, ++ int maxval, int resolution) ++{ ++ TouchAxisInfoPtr ax; ++ ++ if (!dev || !dev->touch || minval > maxval) ++ return; ++ if (axnum >= dev->touch->num_axes) ++ return; ++ ++ ax = dev->touch->axes + axnum; ++ ++ ax->min_value = minval; ++ ax->max_value = maxval; ++ ax->resolution = resolution; ++ ax->label = label; ++ ++ if (ax->label == XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_X)) ++ { ++ dev->touch->x_axis = axnum; ++ if (dev->touch->mode == XIDirectTouch && ++ (!dev->valuator || dev->valuator->numAxes < 1 || ++ dev->valuator->axes[0].min_value != minval || ++ dev->valuator->axes[0].max_value != maxval || ++ dev->valuator->axes[0].resolution != resolution)) ++ LogMessage(X_WARNING, "Touch X valuator does not match pointer X " ++ "valuator, pointer emulation may be " ++ "incorrect\n"); ++ } ++ else if (ax->label == XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_Y)) ++ { ++ dev->touch->y_axis = axnum; ++ if (dev->touch->mode == XIDirectTouch && ++ (!dev->valuator || dev->valuator->numAxes < 2 || ++ dev->valuator->axes[1].min_value != minval || ++ dev->valuator->axes[1].max_value != maxval || ++ dev->valuator->axes[1].resolution != resolution)) ++ LogMessage(X_WARNING, "Touch Y valuator does not match pointer Y " ++ "valuator, pointer emulation may be " ++ "incorrect\n"); ++ } ++} ++ + static void + FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, + ButtonClassPtr b, ValuatorClassPtr v, int first) +@@ -1533,6 +2608,38 @@ + 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, DixFreezeAccess); ++ if (rc != Success) ++ return rc; ++ ++ /* Touch grabs are asynchronous in protocol, but we need to freeze the ++ * pointer device if a touch grab is activated for pointer emulation. */ ++ param->other_devices_mode = GrabModeSync; ++ ++ grab = CreateGrab(client->index, dev, mod_dev, pWin, GRABTYPE_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) +@@ -1670,10 +2777,65 @@ + } + } + ++static void ++RemoveTouchClient(DeviceIntPtr dev, TouchPointInfoPtr ti, int index) ++{ ++ TouchClientPtr tc = &ti->clients[index]; ++ int i; ++ ++ if (index == ti->owner) { ++ if (tc->grab && dev->deviceGrab.grab && ++ GrabMatchesSecond(tc->grab, dev->deviceGrab.grab, ++ FALSE)) ++ ProcessTouchOwnership(dev, ti, XITouchOwnerRejectEnd, TRUE); ++ else { ++ ti->owner++; ++ if (ti->owner >= ti->active_clients) { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ } ++ } ++ return; ++ } ++ ++ for (i = index; i < ti->active_clients - 1; i++) ++ memcpy(ti->clients + i, ti->clients + i + 1, ++ sizeof(TouchClientRec)); ++ ti->active_clients--; ++} ++ ++ + int + InputClientGone(WindowPtr pWin, XID id) + { + InputClientsPtr other, prev; ++ 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++) { ++ TouchPointInfoPtr ti = &t->touches[i]; ++ int j; ++ ++ if (!ti->active || ti->active_clients == 0) ++ continue; ++ ++ j = (ti->owner < 0) ? 0 : ti->owner; ++ while (j < ti->active_clients) { ++ TouchClientPtr tc = &ti->clients[j]; ++ ++ if (clients[CLIENT_ID(id)] == tc->client) ++ RemoveTouchClient(dev, ti, j); ++ else ++ j++; ++ } ++ } ++ } + + if (!wOtherInputMasks(pWin)) + return Success; +@@ -1709,6 +2871,54 @@ + 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; ++ } ++ } ++ } ++ ++ for (i = 0; i < t->num_touches; i++) { ++ TouchPointInfoPtr ti = &t->touches[i]; ++ int j; ++ ++ if (!ti->active || ti->active_clients == 0) ++ continue; ++ ++ j = (ti->owner < 0) ? 0 : ti->owner; ++ while (j < ti->active_clients) { ++ TouchClientPtr tc = &ti->clients[j]; ++ ++ if (win == tc->window) ++ RemoveTouchClient(dev, ti, j); ++ else ++ j++; ++ } ++ } ++ } ++} ++ + int + SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate, + xEvent * ev, Mask mask, int count) +Index: xorg-server/Xi/extinit.c +=================================================================== +--- xorg-server.orig/Xi/extinit.c 2011-08-24 12:52:43.985647123 +0300 ++++ xorg-server/Xi/extinit.c 2011-08-24 12:56:49.855650623 +0300 +@@ -259,7 +259,8 @@ + ProcXIChangeProperty, /* 57 */ + ProcXIDeleteProperty, /* 58 */ + ProcXIGetProperty, /* 59 */ +- ProcXIGetSelectedEvents /* 60 */ ++ ProcXIGetSelectedEvents, /* 60 */ ++ ProcXIAllowTouchEvents, /* 61 */ + }; + + /* For swapped clients */ +@@ -324,7 +325,8 @@ + SProcXIChangeProperty, /* 57 */ + SProcXIDeleteProperty, /* 58 */ + SProcXIGetProperty, /* 59 */ +- SProcXIGetSelectedEvents /* 60 */ ++ SProcXIGetSelectedEvents, /* 60 */ ++ SProcXIAllowTouchEvents, /* 61 */ + }; + + /***************************************************************** +@@ -855,6 +857,21 @@ + swaps(&to->valuators_len, n); + } + ++static void STouchOwnershipEvent(xXITouchOwnershipEvent *from, ++ xXITouchOwnershipEvent *to) ++{ ++ char n; ++ ++ *to = *from; ++ swaps(&to->sequenceNumber, n); ++ swapl(&to->length, n); ++ swaps(&to->evtype, n); ++ swaps(&to->deviceid, n); ++ swapl(&to->time, n); ++ swaps(&to->sourceid, n); ++ swapl(&to->touchid, n); ++ swapl(&to->flags, n); ++} + + /** Event swapping function for XI2 events. */ + void +@@ -884,8 +901,16 @@ + case XI_KeyRelease: + case XI_ButtonPress: + case XI_ButtonRelease: ++ case XI_TouchBegin: ++ case XI_TouchUpdate: ++ case XI_TouchUpdateUnowned: ++ 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: +Index: xorg-server/Xi/xiallowev.c +=================================================================== +--- xorg-server.orig/Xi/xiallowev.c 2011-08-24 12:52:44.025647122 +0300 ++++ xorg-server/Xi/xiallowev.c 2011-08-24 12:56:49.855650623 +0300 +@@ -35,11 +35,15 @@ + + #include "inputstr.h" /* DeviceIntPtr */ + #include "windowstr.h" /* window structure */ ++#include "eventstr.h" ++#include "mi.h" + #include <X11/extensions/XI2.h> + #include <X11/extensions/XI2proto.h> + + #include "exglobals.h" /* BadDevice */ + #include "xiallowev.h" ++#include "exevents.h" ++#include "dixgrabs.h" + + int + SProcXIAllowEvents(ClientPtr client) +@@ -98,6 +102,113 @@ + ret = BadValue; + } + ++ /* If this is a master pointer with an active touch emulation and the touch ++ * has physically ceased, end the touchpoint state. */ ++ if (dev->emulate_dev) ++ { ++ DeviceIntPtr sourcedev = dev->emulate_dev; ++ TouchPointInfoPtr ti = sourcedev->touch->emulate; ++ ++ if (ti->pending_finish && ti->owner < 0) ++ EndTouchPoint(sourcedev, ti); ++ else if (ti->pending_finish) ++ { ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ if (tc->type == TOUCH_SELECT || tc->type == TOUCH_SELECT_UNOWNED) ++ EndTouchPoint(sourcedev, ti); ++ } ++ } ++ + return ret; + } + ++int ++SProcXIAllowTouchEvents(ClientPtr client) ++{ ++ char n; ++ ++ REQUEST(xXIAllowTouchEventsReq); ++ ++ swaps(&stuff->length, n); ++ swaps(&stuff->deviceid, n); ++ swapl(&stuff->touchid, n); ++ ++ return ProcXIAllowTouchEvents(client); ++} ++ ++int ++ProcXIAllowTouchEvents(ClientPtr client) ++{ ++ DeviceIntPtr dev; ++ TouchClassPtr t; ++ TouchPointInfoPtr ti; ++ TouchClientPtr tc; ++ int ret; ++ EventList *events = InitEventList(GetMaximumEventsNum()); ++ ++ REQUEST(xXIAllowTouchEventsReq); ++ REQUEST_SIZE_MATCH(xXIAllowTouchEventsReq); ++ ++ if (!events) ++ return BadAlloc; ++ ++ ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); ++ if (ret != Success) ++ return ret; ++ ++ if (!dev->touch) ++ { ++ client->errorValue = stuff->deviceid; ++ return BadDevice; ++ } ++ ++ t = dev->touch; ++ ++ ti = FindTouchPointByClientID(dev, stuff->touchid); ++ if (!ti) ++ { ++ client->errorValue = stuff->touchid; ++ return BadValue; ++ } ++ ++ tc = &ti->clients[ti->owner]; ++ ++ if (client != tc->client || !tc->grab) ++ return BadAccess; ++ ++ if (ti == t->emulate) ++ { ++ DeviceIntPtr master = dev->u.master; ++ ++ if (!master || !master->deviceGrab.grab || ++ !GrabMatchesSecond(master->deviceGrab.grab, tc->grab, FALSE)) ++ return BadAccess; ++ } ++ ++ if (stuff->mode & XITouchOwnerAccept) ++ { ++ if (stuff->mode & ~XITouchOwnerAccept) ++ { ++ client->errorValue = stuff->mode; ++ return BadValue; ++ } ++ } ++ else if (stuff->mode & XITouchOwnerRejectEnd) ++ { ++ if (stuff->mode & ~XITouchOwnerRejectEnd) ++ { ++ client->errorValue = stuff->mode; ++ return BadValue; ++ } ++ } ++ else ++ { ++ client->errorValue = stuff->mode; ++ return BadValue; ++ } ++ ++ ProcessTouchOwnership(dev, ti, stuff->mode, TRUE); ++ ++ return Success; ++} +Index: xorg-server/Xi/xiallowev.h +=================================================================== +--- xorg-server.orig/Xi/xiallowev.h 2011-08-24 12:52:43.975647121 +0300 ++++ xorg-server/Xi/xiallowev.h 2011-08-24 12:56:49.855650623 +0300 +@@ -32,5 +32,7 @@ + + int ProcXIAllowEvents(ClientPtr client); + int SProcXIAllowEvents(ClientPtr client); ++int ProcXIAllowTouchEvents(ClientPtr client); ++int SProcXIAllowTouchEvents(ClientPtr client); + + #endif /* XIALLOWEV_H */ +Index: xorg-server/Xi/xipassivegrab.c +=================================================================== +--- xorg-server.orig/Xi/xipassivegrab.c 2011-08-24 12:52:43.995647122 +0300 ++++ xorg-server/Xi/xipassivegrab.c 2011-08-24 12:56:49.855650623 +0300 +@@ -110,19 +110,30 @@ + 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 != GrabModeAsync || ++ stuff->paired_device_mode != GrabModeAsync)) ++ { ++ client->errorValue = GrabModeSync; ++ return BadValue; ++ } ++ + if (XICheckInvalidMaskBits(client, (unsigned char*)&stuff[1], + stuff->mask_len * 4) != Success) + return BadValue; +@@ -192,6 +203,9 @@ + status = GrabWindow(client, dev, stuff->grab_type, + ¶m, &mask); + break; ++ case XIGrabtypeTouchBegin: ++ status = GrabTouch(client, dev, mod_dev, ¶m, &mask); ++ break; + } + + if (status != GrabSuccess) +Index: xorg-server/Xi/xiquerydevice.c +=================================================================== +--- xorg-server.orig/Xi/xiquerydevice.c 2011-08-24 12:52:43.955647122 +0300 ++++ xorg-server/Xi/xiquerydevice.c 2011-08-24 12:56:49.855650623 +0300 +@@ -235,6 +235,12 @@ + if (dev->valuator) + len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; + ++ if (dev->touch) ++ { ++ len += sizeof(xXITouchInfo); ++ len += sizeof(xXITouchValuatorInfo) * dev->touch->num_axes; ++ } ++ + return len; + } + +@@ -376,6 +382,73 @@ + swaps(&info->sourceid, n); + } + ++/** ++ * 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 = dev->id; ++ touch->mode = dev->touch->mode; ++ touch->num_touches = dev->touch->num_touches; ++ ++ return touch->length << 2; ++} ++ ++static void ++SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo* touch) ++{ ++ char n; ++ swaps(&touch->type, n); ++ swaps(&touch->length, n); ++ swaps(&touch->sourceid, n); ++} ++ ++/** ++ * List multitouch axis information ++ * ++ * @return The number of bytes written into info. ++ */ ++int ++ListTouchValuatorInfo(DeviceIntPtr dev, xXITouchValuatorInfo* val, ++ int axisnumber) ++{ ++ TouchClassPtr t = dev->touch; ++ ++ val->type = XITouchValuatorClass; ++ val->length = sizeof(xXITouchValuatorInfo) >> 2; ++ val->sourceid = dev->id; ++ val->number = axisnumber; ++ val->label = t->axes[axisnumber].label; ++ val->min.integral = t->axes[axisnumber].min_value; ++ val->min.frac = 0; ++ val->max.integral = t->axes[axisnumber].max_value; ++ val->max.frac = 0; ++ val->resolution = t->axes[axisnumber].resolution; ++ ++ return val->length << 2; ++} ++ ++static void ++SwapTouchValuatorInfo(DeviceIntPtr dev, xXITouchValuatorInfo* val) ++{ ++ char n; ++ swaps(&val->type, n); ++ swaps(&val->length, n); ++ swaps(&val->sourceid, n); ++ swaps(&val->number, n); ++ swapl(&val->label, n); ++ swapl(&val->min.integral, n); ++ swapl(&val->min.frac, n); ++ swapl(&val->max.integral, n); ++ swapl(&val->max.frac, n); ++ swapl(&val->resolution, n); ++} ++ + int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment) + { + DeviceIntPtr master = dev->u.master; +@@ -465,6 +538,22 @@ + total_len += len; + } + ++ if (dev->touch) ++ { ++ (*nclasses)++; ++ len = ListTouchInfo(dev, (xXITouchInfo*)any); ++ any += len; ++ total_len += len; ++ ++ for (i = 0; i < dev->touch->num_axes; i++) ++ { ++ (*nclasses)++; ++ len = ListTouchValuatorInfo(dev, (xXITouchValuatorInfo*)any, i); ++ any += len; ++ total_len += len; ++ } ++ } ++ + return total_len; + } + +@@ -492,6 +581,12 @@ + case XIValuatorClass: + SwapValuatorInfo(dev, (xXIValuatorInfo*)any); + break; ++ case XITouchClass: ++ SwapTouchInfo(dev, (xXITouchInfo*)any); ++ break; ++ case XITouchValuatorClass: ++ SwapTouchValuatorInfo(dev, (xXITouchValuatorInfo*)any); ++ break; + } + + any += len * 4; +Index: xorg-server/Xi/xiquerydevice.h +=================================================================== +--- xorg-server.orig/Xi/xiquerydevice.h 2011-08-24 12:52:44.015647121 +0300 ++++ xorg-server/Xi/xiquerydevice.h 2011-08-24 12:56:49.855650623 +0300 +@@ -44,4 +44,7 @@ + int ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info); + int ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, + int axisnumber, Bool reportState); ++int ListTouchInfo(DeviceIntPtr dev, xXITouchInfo* info); ++int ListTouchValuatorInfo(DeviceIntPtr dev, xXITouchValuatorInfo* val, ++ int axisnumber); + #endif /* QUERYDEV_H */ +Index: xorg-server/Xi/xiselectev.c +=================================================================== +--- xorg-server.orig/Xi/xiselectev.c 2011-08-24 12:52:44.005647120 +0300 ++++ xorg-server/Xi/xiselectev.c 2011-08-24 12:56:49.855650623 +0300 +@@ -152,6 +152,60 @@ + } + } + ++ if (evmask->mask_len >= 1) ++ { ++ unsigned char *bits = (unsigned char*)&evmask[1]; ++ ++ /* Check validity of touch selections */ ++ if (BitIsOn(bits, XI_TouchBegin) || ++ BitIsOn(bits, XI_TouchUpdate) || ++ BitIsOn(bits, XI_TouchEnd)) ++ { ++ /* All three touch events must be selected at once */ ++ if (!BitIsOn(bits, XI_TouchBegin) || ++ !BitIsOn(bits, XI_TouchUpdate) || ++ !BitIsOn(bits, XI_TouchEnd)) ++ { ++ client->errorValue = XI_TouchBegin; ++ return BadValue; ++ } ++ ++ /* Unowned and ownership events must both be selected */ ++ if ((BitIsOn(bits, XI_TouchUpdateUnowned) || ++ BitIsOn(bits, XI_TouchOwnership)) && ++ (!BitIsOn(bits, XI_TouchUpdateUnowned) || ++ !BitIsOn(bits, XI_TouchOwnership))) ++ { ++ 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) ++ { ++ if (CLIENT_ID(iclient->resource) == client->index) ++ continue; ++ if (BitIsOn(iclient->xi2mask[evmask->deviceid], ++ XI_TouchBegin) || ++ BitIsOn(iclient->xi2mask[XIAllDevices], ++ XI_TouchBegin) || ++ (dev && (IsMaster(dev) || dev->u.master) && ++ BitIsOn(iclient->xi2mask[XIAllMasterDevices], ++ XI_TouchBegin))) ++ return BadAccess; ++ } ++ } ++ } ++ + if (XICheckInvalidMaskBits(client, (unsigned char*)&evmask[1], + evmask->mask_len * 4) != Success) + return BadValue; +Index: xorg-server/configure.ac +=================================================================== +--- xorg-server.orig/configure.ac 2011-08-24 12:56:49.795650626 +0300 ++++ xorg-server/configure.ac 2011-08-24 12:57:14.755650981 +0300 +@@ -795,7 +795,7 @@ + APPLEWMPROTO="applewmproto >= 1.4" + + dnl Core modules for most extensions, et al. +-SDK_REQUIRED_MODULES="[xproto >= 7.0.17] [randrproto >= 1.2.99.3] [renderproto >= 0.11] [xextproto >= 7.1.99] [inputproto >= 1.9.99.902] [kbproto >= 1.0.3] fontsproto" ++SDK_REQUIRED_MODULES="[xproto >= 7.0.17] [randrproto >= 1.2.99.3] [renderproto >= 0.11] [xextproto >= 7.1.99] [inputproto >= 2.0.2] [kbproto >= 1.0.3] fontsproto" + # Make SDK_REQUIRED_MODULES available for inclusion in xorg-server.pc + AC_SUBST(SDK_REQUIRED_MODULES) + +Index: xorg-server/dix/devices.c +=================================================================== +--- xorg-server.orig/dix/devices.c 2011-08-24 12:52:43.855647120 +0300 ++++ xorg-server/dix/devices.c 2011-08-24 12:56:49.855650623 +0300 +@@ -754,6 +754,20 @@ + 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].clients); ++ } ++ ++ free((*t)); ++ break; ++ } + case FocusClass: + { + FocusClassPtr *f = (FocusClassPtr*)class; +@@ -862,6 +876,7 @@ + + 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); +@@ -1574,6 +1589,151 @@ + InitPtrFeedbackClassDeviceStruct(dev, controlProc)); + } + ++Bool ++InitTouchPoint(TouchClassPtr t, int index) ++{ ++ TouchPointInfoPtr ti; ++ ++ if (!index >= t->num_touches) ++ return FALSE; ++ ti = &t->touches[index]; ++ ++ ti->valuators = calloc(t->num_axes, sizeof(*ti->valuators)); ++ if (!ti->valuators) ++ return FALSE; ++ ti->num_valuators = t->num_axes; ++ ++ ti->sprite.spriteTrace = calloc(32, sizeof(*ti->sprite.spriteTrace)); ++ if (!ti->sprite.spriteTrace) ++ { ++ free(ti->valuators); ++ ti->valuators = NULL; ++ ti->num_valuators = 0; ++ 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->ddx_id = -1; ++ ti->client_id = -1; ++ ++ ti->history_size = GetMotionHistorySize(); ++ ti->begin_event = malloc((ti->history_size + 1) * sizeof(InternalEvent)); ++ if (!ti->begin_event) ++ { ++ free(ti->sprite.spriteTrace); ++ free(ti->valuators); ++ ti->sprite.spriteTrace = NULL; ++ ti->valuators = NULL; ++ ti->num_valuators = 0; ++ return FALSE; ++ } ++ ti->history = ti->begin_event + 1; ++ ti->first_history = ti->history; ++ ti->next_history = ti->history; ++ ++ return TRUE; ++} ++ ++void ++FreeTouchPoint(DeviceIntPtr device, int index) ++{ ++ TouchPointInfoPtr ti; ++ ++ if (!device->touch || index >= device->touch->num_touches) ++ return; ++ ti = &device->touch->touches[index]; ++ ++ if (ti->active) ++ EndTouchPoint(device, ti); ++ ++ free(ti->valuators); ++ ti->valuators = NULL; ++ ti->num_valuators = 0; ++ free(ti->sprite.spriteTrace); ++ ti->sprite.spriteTrace = NULL; ++ free(ti->begin_event); ++ ti->begin_event = NULL; ++ free(ti->clients); ++ ti->clients = NULL; ++ ti->num_clients = 0; ++} ++ ++/** ++ * 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) ++ 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->axes = calloc(num_axes, sizeof(*touch->axes)); ++ if (!touch->axes) ++ goto err; ++ touch->num_axes = num_axes; ++ ++ touch->max_touches = max_touches; ++ if (max_touches == 0) ++ max_touches = 5; /* arbitrary number plucked out of the air */ ++ ++ /* Need cushion for clients who may hold on to touches after they physically ++ * end. So double the initial allocation of touches. */ ++ touch->touches = calloc(max_touches * 2, sizeof(*touch->touches)); ++ if (!touch->touches) ++ goto err; ++ touch->num_touches = max_touches * 2; ++ for (i = 0; i < touch->num_touches; i++) ++ InitTouchPoint(touch, i); ++ ++ touch->mode = mode; ++ touch->x_axis = -1; ++ touch->y_axis = -1; ++ touch->next_client_id = 1; ++ ++ device->touch = touch; ++ ++ return TRUE; ++ ++err: ++ for (i = 0; i < touch->num_touches; i++) ++ FreeTouchPoint(device, i); ++ ++ free(touch->touches); ++ free(touch->axes); ++ free(touch); ++ ++ return FALSE; ++} ++ + /* + * Check if the given buffer contains elements between low (inclusive) and + * high (inclusive) only. +@@ -2446,6 +2606,58 @@ + FreeEventList(eventlist, GetMaximumEventsNum()); + } + ++static void ++DropTouchSelectionsOnWindow(DeviceIntPtr dev, WindowPtr win) ++{ ++ WindowPtr child; ++ ++ if (wOtherInputMasks(win) && ++ BitIsOn(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchBegin)) ++ { ++ InputClientsPtr client = wOtherInputMasks(win)->inputClients; ++ ++ /* Don't bother deleting client record if there are no other ++ * selections. The client will likely reselect when it gets the ++ * HierarchyChange event. */ ++ while (client) ++ { ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchBegin); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchEnd); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchOwnership); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchUpdate); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchUpdateUnowned); ++ ++ client = client->next; ++ } ++ ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchBegin); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchEnd); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchOwnership); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchUpdate); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchUpdateUnowned); ++ } ++ ++ child = win->firstChild; ++ while (child) ++ { ++ DropTouchSelectionsOnWindow(dev, child); ++ child = child->nextSib; ++ } ++} ++ ++static void ++DropTouchSelections(DeviceIntPtr dev) ++{ ++ int i; ++ ++ for (i = 0; i < screenInfo.numScreens; i++) ++ { ++ WindowPtr win = screenInfo.screens[i]->root; ++ ++ DropTouchSelectionsOnWindow(dev, win); ++ } ++} ++ + /** + * Attach device 'dev' to device 'master'. + * Client is set to the client that issued the request, or NULL if it comes +@@ -2511,6 +2723,12 @@ + dev->spriteInfo->spriteOwner = FALSE; + + RecalculateMasterButtons(master); ++ ++ /* Only one client may select for touch events from a device on a window ++ * at any time. Reattaching could break this, so drop all touch event ++ * selections for this specific slave device on all windows. */ ++ if (dev->touch) ++ DropTouchSelections(dev); + } + + /* XXX: in theory, the MD should change back to its old, original +Index: xorg-server/dix/eventconvert.c +=================================================================== +--- xorg-server.orig/dix/eventconvert.c 2011-08-24 12:52:43.825647118 +0300 ++++ xorg-server/dix/eventconvert.c 2011-08-24 12:56:49.855650623 +0300 +@@ -55,6 +55,7 @@ + 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); +@@ -139,6 +140,11 @@ + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: ++ case ET_TouchBegin: ++ case ET_TouchEnd: ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: ++ case ET_TouchOwnership: + return BadMatch; + default: + /* XXX: */ +@@ -184,6 +190,11 @@ + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: ++ case ET_TouchBegin: ++ case ET_TouchEnd: ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: ++ case ET_TouchOwnership: + *count = 0; + *xi = NULL; + return BadMatch; +@@ -225,7 +236,13 @@ + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: ++ case ET_TouchBegin: ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: ++ 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; +@@ -581,6 +598,7 @@ + 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->key_repeat) + xde->flags |= XIKeyRepeat; + +@@ -618,6 +636,27 @@ + } + + 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((InternalEvent*)ev); ++ xtoe->deviceid = ev->deviceid; ++ xtoe->time = ev->time; ++ xtoe->sourceid = ev->sourceid; ++ xtoe->touchid = ev->touchid; ++ xtoe->flags = ev->flags; ++ ++ return Success; ++} ++ ++static int + eventToRawEvent(RawDeviceEvent *ev, xEvent **xi) + { + xXIRawEvent* raw; +@@ -732,6 +771,11 @@ + 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_TouchMotion: xi2type = XI_TouchUpdate; break; ++ case ET_TouchMotionUnowned: xi2type = XI_TouchUpdateUnowned; break; ++ case ET_TouchOwnership: xi2type = XI_TouchOwnership; break; + default: + break; + } +Index: xorg-server/dix/events.c +=================================================================== +--- xorg-server.orig/dix/events.c 2011-08-24 12:56:49.835650626 +0300 ++++ xorg-server/dix/events.c 2011-08-24 12:57:17.885651026 +0300 +@@ -1096,7 +1096,7 @@ + void + EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) + { +- QdEventPtr tail = *syncEvents.pendtail; ++ QdEventPtr tail = syncEvents.pendtail; + QdEventPtr qe; + SpritePtr pSprite = device->spriteInfo->sprite; + int eventlen; +@@ -1167,8 +1167,10 @@ + qe->event = (InternalEvent *)(qe + 1); + memcpy(qe->event, event, eventlen); + if (tail) +- syncEvents.pendtail = &tail->next; +- *syncEvents.pendtail = qe; ++ tail->next = qe; ++ else ++ syncEvents.pending = qe; ++ syncEvents.pendtail = qe; + } + + /** +@@ -1183,18 +1185,19 @@ + static void + PlayReleasedEvents(void) + { +- QdEventPtr *prev, qe; ++ QdEventPtr prev, qe = syncEvents.pending; + DeviceIntPtr dev; + DeviceIntPtr pDev; + +- prev = &syncEvents.pending; +- while ( (qe = *prev) ) ++ prev = NULL; ++ while (qe) + { + if (!qe->device->deviceGrab.sync.frozen) + { +- *prev = qe->next; ++ if (syncEvents.pending == qe) ++ syncEvents.pending = qe->next; + pDev = qe->device; +- if (*syncEvents.pendtail == *prev) ++ if (syncEvents.pendtail == qe) + syncEvents.pendtail = prev; + if (qe->event->any.type == ET_Motion) + CheckVirtualMotion(pDev, qe, NullWindow); +@@ -1226,6 +1229,7 @@ + + } + #endif ++ + (*qe->device->public.processInputProc)(qe->event, qe->device); + free(qe); + for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen; dev = dev->next) +@@ -1234,10 +1238,14 @@ + break; + /* Playing the event may have unfrozen another device. */ + /* So to play it safe, restart at the head of the queue */ +- prev = &syncEvents.pending; ++ qe = syncEvents.pending; ++ prev = NULL; + } + else +- prev = &qe->next; ++ { ++ prev = qe; ++ qe = qe->next; ++ } + } + } + +@@ -1259,6 +1267,76 @@ + dev->public.processInputProc = dev->public.realInputProc; + } + ++void ++RemoveTouchEventsFromQueue(DeviceIntPtr dev, Bool touch, Bool ignoreOwned) ++{ ++ QdEventPtr qe = syncEvents.pending; ++ QdEventPtr prev_qe = NULL; ++ QdEventPtr first = NULL; ++ Bool end = FALSE; ++ ++ while (qe && !end) ++ { ++ QdEventPtr tmp; ++ ++ if (qe->device != dev) ++ continue; ++ ++ if (ignoreOwned && (qe->event->any.type == ET_TouchOwnership || ++ qe->event->any.type == ET_TouchEnd)) ++ break; ++ ++ if (qe->event->any.type == ET_TouchEnd) ++ end = TRUE; ++ ++ if ((touch && !IsTouchEvent(qe->event)) || ++ (!touch && !IsPointerEvent(qe->event)) || ++ (ignoreOwned && qe->event->any.type == ET_TouchBegin)) ++ { ++ if (!first) ++ first = qe; ++ prev_qe = qe; ++ qe = qe->next; ++ continue; ++ } ++ ++ tmp = qe; ++ qe = qe->next; ++ if (prev_qe) ++ prev_qe->next = qe; ++ if (syncEvents.pending == tmp) ++ syncEvents.pending = qe; ++ ++ free(tmp); ++ ++ if (!qe) ++ syncEvents.pendtail = prev_qe; ++ } ++ ++ if (qe && !qe->next) ++ syncEvents.pendtail = qe; ++ ++ if (dev->deviceGrab.sync.event && ++ ((touch && IsTouchEvent((InternalEvent *)dev->deviceGrab.sync.event)) || ++ (!touch && ++ IsPointerEvent((InternalEvent *)dev->deviceGrab.sync.event)))) ++ { ++ free(dev->deviceGrab.sync.event); ++ if (first) ++ { ++ dev->deviceGrab.sync.event = malloc(sizeof(DeviceEvent)); ++ memcpy(dev->deviceGrab.sync.event, first->event, ++ sizeof(DeviceEvent)); ++ } ++ else ++ dev->deviceGrab.sync.event = NULL; ++ syncEvents.pending = first->next; ++ free(first); ++ if (!syncEvents.pending) ++ syncEvents.pendtail = NULL; ++ } ++} ++ + /** + * Unfreeze devices and replay all events to the respective clients. + * +@@ -1285,6 +1363,14 @@ + { + DeviceEvent* event = replayDev->deviceGrab.sync.event; + ++ if (event->type == ET_TouchBegin) ++ { ++ ProcessTouchOwnership(replayDev, event->touchpoint, ++ XITouchOwnerAccept, FALSE); ++ if (!replayDev->deviceGrab.sync.event) ++ goto no_sync; ++ } ++ + syncEvents.replayDev = (DeviceIntPtr)NULL; + + w = XYToWindow(replayDev->spriteInfo->sprite, +@@ -1298,6 +1384,7 @@ + NullWindow, replayDev); + } + } ++no_sync: + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!dev->deviceGrab.sync.frozen) +@@ -1517,6 +1604,20 @@ + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(mouse); + ++ if (mouse->deviceGrab.sync.event && ++ (mouse->deviceGrab.sync.event->flags & XIPointerEmulated) && ++ (grab->grabtype != GRABTYPE_XI2 || grab->type != XI_TouchBegin)) ++ { ++ InternalEvent event; ++ ++ event.any.type = ET_TouchBegin; ++ ++ if (CheckPassiveGrabsOnWindow(grab->window, mouse, &event, FALSE, TRUE)) ++ syncEvents.playingEvents = TRUE; ++ } ++ else ++ syncEvents.playingEvents = FALSE; ++ + ComputeFreezes(); + } + +@@ -1764,6 +1865,25 @@ + client->errorValue = stuff->mode; + return BadValue; + } ++ ++ /* If this is a master pointer with an active touch emulation and the touch ++ * has physically ceased, end the touchpoint state. */ ++ if (mouse->emulate_dev) ++ { ++ DeviceIntPtr sourcedev = mouse->emulate_dev; ++ TouchPointInfoPtr ti = sourcedev->touch->emulate; ++ ++ if (ti->pending_finish && ti->owner < 0) ++ EndTouchPoint(sourcedev, ti); ++ else if (ti->pending_finish) ++ { ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ if (tc->type == TOUCH_SELECT || tc->type == TOUCH_SELECT_UNOWNED) ++ EndTouchPoint(sourcedev, ti); ++ } ++ } ++ + return Success; + } + +@@ -2391,7 +2511,7 @@ + + static Window FindChildForEvent(SpritePtr pSprite, WindowPtr event) + { +- WindowPtr w = pSprite->spriteTrace[pSprite->spriteTraceGood-1]; ++ WindowPtr w = DeepestSpriteWin(pSprite); + Window child = None; + + /* If the search ends up past the root should the child field be +@@ -2449,7 +2569,8 @@ + event->evtype == XI_RawMotion || + event->evtype == XI_DeviceChanged || + event->evtype == XI_HierarchyChanged || +- event->evtype == XI_PropertyEvent) ++ event->evtype == XI_PropertyEvent || ++ event->evtype == XI_TouchOwnership) + return; + + event->root = RootWindow(pSprite)->drawable.id; +@@ -2586,12 +2707,119 @@ + xEvent core; + xEvent *xE = NULL; + int rc, mask, count = 0; ++ InternalEvent touch_dummy; ++ Bool check_touch = FALSE; + + CHECKEVENT(event); + ++ /* If we are replaying a pointer emulated button press event, find the first ++ * pointer or touch selecting client. */ ++ if (syncEvents.playingEvents && event->any.type == ET_ButtonPress && ++ (event->device_event.flags & XIPointerEmulated) && ++ event->device_event.touchpoint && ++ event->device_event.touchpoint->active_clients > 0) ++ { ++ QdEventPtr qe; ++ DeviceEvent *te; ++ TouchPointInfoPtr ti; ++ TouchClientPtr tc = NULL; ++ ++ for (qe = syncEvents.pending; qe; qe = qe->next) ++ if (qe->device == dev && qe->event->any.type == ET_TouchBegin) ++ break; ++ if (!qe) ++ { ++ LogMessage(X_ERROR, "no touch for emulated button press\n"); ++ goto no_touch_event; ++ } ++ ++ te = &qe->event->device_event; ++ ti = te->touchpoint; ++ ++ if (ti->active_clients > 0) ++ { ++ tc = &ti->clients[ti->active_clients - 1]; ++ te->deviceid = tc->device->id; ++ } ++ ++ while (pWin) ++ { ++ Bool touch = FALSE; ++ Bool pointer = FALSE; ++ ++ if (tc && ++ EventIsDeliverable(tc->device, (InternalEvent *)te, pWin) && ++ (tc->type == TOUCH_SELECT || tc->type == TOUCH_SELECT_UNOWNED)) ++ { ++ ti->owner = ti->active_clients - 1; ++ if (tc->type == TOUCH_SELECT_UNOWNED) ++ DeliverTouchOwnershipEvent(tc, ti); ++ touch = TRUE; ++ } ++ ++ if (EventIsDeliverable(dev, event, pWin)) ++ pointer = TRUE; ++ ++ if (touch && pointer) ++ break; ++ else if (touch || pointer) ++ { ++ /* Remove unselected events from queue. */ ++ RemoveTouchEventsFromQueue(dev, pointer, FALSE); ++ ++ if (touch) ++ { ++ /* If only touch events are selected, release mouse ++ * button. */ ++ ReleaseButton(dev, 1); ++ ti->emulate_pointer = FALSE; ++ if (IsPointerEvent(event)) ++ return 0; ++ } else { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ if (IsTouchEvent(event)) ++ return 0; ++ } ++ ++ break; ++ } ++ ++ pWin = pWin->parent; ++ } ++ } ++ else if (IsPointerEvent(event) && !syncEvents.playingEvents && ++ (event->device_event.flags & XIPointerEmulated) && ++ event->device_event.touchpoint && ++ event->device_event.touchpoint->active_clients > 0) ++ { ++ /* Non-grabbed emulated pointer event, so check for touch selections. */ ++ check_touch = TRUE; ++ touch_dummy.any.type = ET_TouchBegin; ++ } ++ else if (IsTouchEvent(event)) ++ { ++ TouchPointInfoPtr ti = event->device_event.touchpoint; ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ pWin = tc->window; ++ } ++ ++no_touch_event: + while (pWin) + { +- if ((mask = EventIsDeliverable(dev, event, pWin))) ++ DeviceIntPtr check_dev = dev; ++ ++ if (IsTouchEvent(event)) ++ { ++ TouchPointInfoPtr ti = event->device_event.touchpoint; ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ event->device_event.deviceid = tc->device->id; ++ check_dev = tc->device; ++ } ++ ++ if ((mask = EventIsDeliverable(check_dev, event, pWin))) + { + /* XI2 events first */ + if (mask & XI2_MASK) +@@ -2600,10 +2828,25 @@ + rc = EventToXI2(event, &xi2); + if (rc == Success) + { ++ if (event->any.type == ET_TouchBegin || ++ event->any.type == ET_TouchMotionUnowned) ++ { ++ OtherInputMasks *masks = wOtherInputMasks(pWin); ++ ++ if (BitIsOn(masks->xi2mask[XIAllDevices], ++ XI_TouchOwnership) || ++ BitIsOn(masks->xi2mask[check_dev->id], ++ XI_TouchOwnership) || ++ (IsMaster(check_dev) && ++ BitIsOn(masks->xi2mask[XIAllMasterDevices], ++ XI_TouchOwnership))) ++ goto unwind; ++ } ++ + /* XXX: XACE */ +- filter = GetEventFilter(dev, xi2); ++ filter = GetEventFilter(check_dev, xi2); + FixUpEventFromWindow(pSprite, xi2, pWin, child, FALSE); +- deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1, ++ deliveries = DeliverEventsToWindow(check_dev, pWin, xi2, 1, + filter, grab); + free(xi2); + if (deliveries > 0) +@@ -2656,6 +2899,14 @@ + goto unwind; + } + } ++ else if (check_touch && EventIsDeliverable(dev, &touch_dummy, pWin)) ++ { ++ /* Only touch events wanted on this window. Skip this event and ++ * stop pointer emulation. Future touch events will be sent ++ * instead. */ ++ event->device_event.touchpoint->emulate_pointer = FALSE; ++ goto unwind; ++ } + + child = pWin->drawable.id; + pWin = pWin->parent; +@@ -2808,7 +3059,7 @@ + else + pWin = pWin->nextSib; + } +- return pSprite->spriteTrace[pSprite->spriteTraceGood-1]; ++ return DeepestSpriteWin(pSprite); + } + + /** +@@ -2846,7 +3097,8 @@ + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; +- rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE, TRUE) != NULL); ++ rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE, ++ TRUE) != NULL); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + return rc; +@@ -2883,7 +3135,8 @@ + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; +- rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE, TRUE) != NULL); ++ rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE, ++ TRUE) != NULL); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab); + return rc; +@@ -3570,7 +3823,7 @@ + CheckPassiveGrabsOnWindow( + WindowPtr pWin, + DeviceIntPtr device, +- DeviceEvent *event, ++ InternalEvent *event, + BOOL checkCore, + BOOL activate) + { +@@ -3587,9 +3840,22 @@ + return NULL; + /* Fill out the grab details, but leave the type for later before + * comparing */ ++ switch (event->any.type) ++ { ++ case ET_KeyPress: ++ case ET_KeyRelease: ++ tempGrab.detail.exact = event->device_event.detail.key; ++ break; ++ case ET_ButtonPress: ++ case ET_ButtonRelease: ++ tempGrab.detail.exact = event->device_event.detail.button; ++ break; ++ default: ++ tempGrab.detail.exact = 0; ++ break; ++ } + tempGrab.window = pWin; + tempGrab.device = device; +- tempGrab.detail.exact = event->detail.key; + tempGrab.detail.pMask = NULL; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.next = NULL; +@@ -3597,6 +3863,9 @@ + { + DeviceIntPtr gdev; + XkbSrvInfoPtr xkbi = NULL; ++ int rc, count = 0; ++ xEvent *xE = NULL; ++ xEvent core; + + gdev= grab->modifierDevice; + if (grab->grabtype == GRABTYPE_CORE) +@@ -3622,16 +3891,15 @@ + tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0; + + /* Check for XI2 and XI grabs first */ +- tempGrab.type = GetXI2Type((InternalEvent*)event); ++ tempGrab.type = GetXI2Type(event); + tempGrab.grabtype = GRABTYPE_XI2; + if (GrabMatchesSecond(&tempGrab, grab, FALSE)) + match = XI2_MATCH; + +- tempGrab.detail.exact = event->detail.key; + if (!match) + { + tempGrab.grabtype = GRABTYPE_XI; +- if ((tempGrab.type = GetXIType((InternalEvent*)event)) && ++ if ((tempGrab.type = GetXIType(event)) && + (GrabMatchesSecond(&tempGrab, grab, FALSE))) + match = XI_MATCH; + } +@@ -3640,125 +3908,152 @@ + if (!match && checkCore) + { + tempGrab.grabtype = GRABTYPE_CORE; +- if ((tempGrab.type = GetCoreType((InternalEvent*)event)) && ++ if ((tempGrab.type = GetCoreType(event)) && + (GrabMatchesSecond(&tempGrab, grab, TRUE))) + match = CORE_MATCH; + } + +- if (match && (!grab->confineTo || +- (grab->confineTo->realized && +- BorderSizeNotEmpty(device, grab->confineTo)))) +- { +- int rc, count = 0; +- xEvent *xE = NULL; +- xEvent core; ++ if (!match || (grab->confineTo && ++ (!grab->confineTo->realized || ++ !BorderSizeNotEmpty(device, grab->confineTo)))) ++ continue; + +- event->corestate &= 0x1f00; +- event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00); +- grabinfo = &device->deviceGrab; +- /* In some cases a passive core grab may exist, but the client +- * already has a core grab on some other device. In this case we +- * must not get the grab, otherwise we may never ungrab the +- * device. +- */ +- +- if (grab->grabtype == GRABTYPE_CORE) +- { +- DeviceIntPtr other; +- BOOL interfering = FALSE; +- +- /* A passive grab may have been created for a different device +- than it is assigned to at this point in time. +- Update the grab's device and modifier device to reflect the +- current state. +- Since XGrabDeviceButton requires to specify the +- modifierDevice explicitly, we don't override this choice. +- */ +- if (tempGrab.type < GenericEvent) +- { +- grab->device = device; +- grab->modifierDevice = GetPairedDevice(device); +- } ++ grabinfo = &device->deviceGrab; ++ /* In some cases a passive core grab may exist, but the client ++ * already has a core grab on some other device. In this case we ++ * must not get the grab, otherwise we may never ungrab the ++ * device. ++ */ ++ ++ if (grab->grabtype == GRABTYPE_CORE) ++ { ++ DeviceIntPtr other; ++ BOOL interfering = FALSE; ++ ++ /* A passive grab may have been created for a different device ++ than it is assigned to at this point in time. ++ Update the grab's device and modifier device to reflect the ++ current state. ++ Since XGrabDeviceButton requires to specify the ++ modifierDevice explicitly, we don't override this choice. ++ */ ++ if (tempGrab.type < GenericEvent) ++ { ++ grab->device = device; ++ grab->modifierDevice = GetPairedDevice(device); ++ } + +- for (other = inputInfo.devices; other; other = other->next) ++ for (other = inputInfo.devices; other; other = other->next) ++ { ++ GrabPtr othergrab = other->deviceGrab.grab; ++ if (othergrab && othergrab->grabtype == GRABTYPE_CORE && ++ SameClient(grab, rClient(othergrab)) && ++ ((IsPointerDevice(grab->device) && ++ IsPointerDevice(othergrab->device)) || ++ (IsKeyboardDevice(grab->device) && ++ IsKeyboardDevice(othergrab->device)))) + { +- GrabPtr othergrab = other->deviceGrab.grab; +- if (othergrab && othergrab->grabtype == GRABTYPE_CORE && +- SameClient(grab, rClient(othergrab)) && +- ((IsPointerDevice(grab->device) && +- IsPointerDevice(othergrab->device)) || +- (IsKeyboardDevice(grab->device) && +- IsKeyboardDevice(othergrab->device)))) +- { +- interfering = TRUE; +- break; +- } ++ interfering = TRUE; ++ break; + } +- if (interfering) +- continue; + } ++ if (interfering) ++ continue; ++ } + +- if (!activate) +- return grab; ++ if (!activate) ++ { ++ return grab; ++ } ++ else if (!GetXIType(event) && !GetCoreType(event)) ++ { ++ ErrorF("Event type %d in CheckPassiveGrabsOnWindow is neither" ++ " XI 1.x nor core\n", event->any.type); ++ return NULL; ++ } + +- if (match & CORE_MATCH) ++ /* The only consumers of corestate are Xi 1.x and core events, which ++ * are guaranteed to come from DeviceEvents. */ ++ if (match & (XI_MATCH | CORE_MATCH)) ++ { ++ event->device_event.corestate &= 0x1f00; ++ event->device_event.corestate |= tempGrab.modifiersDetail.exact & ++ (~0x1f00); ++ } ++ ++ if (match & CORE_MATCH) ++ { ++ rc = EventToCore(event, &core); ++ if (rc != Success) + { +- rc = EventToCore((InternalEvent*)event, &core); +- if (rc != Success) +- { +- if (rc != BadMatch) +- ErrorF("[dix] %s: core conversion failed in CPGFW " +- "(%d, %d).\n", device->name, event->type, rc); +- continue; +- } +- xE = &core; +- count = 1; +- } else if (match & XI2_MATCH) ++ if (rc != BadMatch) ++ ErrorF("[dix] %s: core conversion failed in CPGFW " ++ "(%d, %d).\n", device->name, event->any.type, rc); ++ continue; ++ } ++ xE = &core; ++ count = 1; ++ } else if (match & XI2_MATCH) ++ { ++ rc = EventToXI2(event, &xE); ++ if (rc != Success) + { +- rc = EventToXI2((InternalEvent*)event, &xE); +- if (rc != Success) +- { +- if (rc != BadMatch) +- ErrorF("[dix] %s: XI2 conversion failed in CPGFW " +- "(%d, %d).\n", device->name, event->type, rc); +- continue; +- } +- count = 1; +- } else ++ if (rc != BadMatch) ++ ErrorF("[dix] %s: XI2 conversion failed in CPGFW " ++ "(%d, %d).\n", device->name, event->any.type, rc); ++ continue; ++ } ++ count = 1; ++ } else ++ { ++ rc = EventToXI(event, &xE, &count); ++ if (rc != Success) + { +- rc = EventToXI((InternalEvent*)event, &xE, &count); +- if (rc != Success) +- { +- if (rc != BadMatch) +- ErrorF("[dix] %s: XI conversion failed in CPGFW " +- "(%d, %d).\n", device->name, event->type, rc); +- continue; +- } ++ if (rc != BadMatch) ++ ErrorF("[dix] %s: XI conversion failed in CPGFW " ++ "(%d, %d).\n", device->name, event->any.type, rc); ++ continue; + } ++ } + +- (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); ++ (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); + +- if (xE) ++ /* Don't send touch events if you activate a touch grab. Touch grabs ++ * are handled separately. */ ++ if (xE && grab->type != ET_TouchBegin) ++ { ++ FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE); ++ ++ TryClientEvents(rClient(grab), device, xE, count, ++ GetEventFilter(device, xE), ++ GetEventFilter(device, xE), grab); ++ ++ if (grab->pointerMode == GrabModeAsync && ++ event->device_event.touchpoint) + { +- FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE); ++ TouchPointInfoPtr ti = event->device_event.touchpoint; + +- TryClientEvents(rClient(grab), device, xE, count, +- GetEventFilter(device, xE), +- GetEventFilter(device, xE), grab); ++ ProcessTouchOwnership(ti->source, ti, XITouchOwnerAccept, ++ FALSE); + } ++ } + +- if (grabinfo->sync.state == FROZEN_NO_EVENT) +- { ++ if (grabinfo->sync.state == FROZEN_NO_EVENT) ++ { ++ /* Touch events are enqueued differently due to pointer ++ * emulation. */ ++ if (grab->type != ET_TouchBegin) ++ { + if (!grabinfo->sync.event) +- grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); +- *grabinfo->sync.event = *event; +- grabinfo->sync.state = FROZEN_WITH_EVENT; ++ grabinfo->sync.event = calloc(1, sizeof(DeviceEvent)); ++ *grabinfo->sync.event = event->device_event; + } ++ grabinfo->sync.state = FROZEN_WITH_EVENT; ++ } + +- if (match & (XI_MATCH | XI2_MATCH)) +- free(xE); /* on core match xE == &core */ +- return grab; +- } ++ if (match & (XI_MATCH | XI2_MATCH)) ++ free(xE); /* on core match xE == &core */ ++ return grab; + } + return NULL; + #undef CORE_MATCH +@@ -3797,8 +4092,13 @@ + { + int i; + WindowPtr pWin = NULL; +- FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus; ++ FocusClassPtr focus = device->focus; + BOOL sendCore = (IsMaster(device) && device->coreEvents); ++ DeviceEvent *touch_event = NULL; ++ ++ if (IsPointerEvent((InternalEvent *)event) || ++ IsTouchEvent((InternalEvent *)event)) ++ focus = NULL; + + if (event->type != ET_ButtonPress && + event->type != ET_KeyPress) +@@ -3826,7 +4126,8 @@ + for (; i < focus->traceGood; i++) + { + pWin = focus->trace[i]; +- if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE)) ++ if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event, ++ sendCore, TRUE)) + return TRUE; + } + +@@ -3836,11 +4137,54 @@ + return FALSE; + } + ++ if (syncEvents.pending && event->type == ET_ButtonPress && ++ (event->flags & XIPointerEmulated)) ++ { ++ QdEventPtr qe; ++ ++ for (qe = syncEvents.pending; qe; qe = qe->next) ++ if (qe->device == device && qe->event->any.type == ET_TouchBegin) ++ break; ++ if (qe) ++ touch_event = &qe->event->device_event; ++ } ++ + for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) + { +- pWin = device->spriteInfo->sprite->spriteTrace[i]; +- if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE)) +- return TRUE; ++ pWin = device->spriteInfo->sprite->spriteTrace[i]; ++ ++ if (!pWin->optional) ++ continue; ++ ++ /* Touch grabs are checked before pointer grabs. When a touch grab ++ * should be checked first, check_grab is TRUE. */ ++ if (touch_event && touch_event->check_grab) ++ { ++ GrabPtr grab; ++ ++ grab = CheckPassiveGrabsOnWindow(pWin, device, ++ (InternalEvent *)touch_event, ++ FALSE, FALSE); ++ if (grab) ++ { ++ TouchPointInfoPtr ti = touch_event->touchpoint; ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ device->deviceGrab.ActivateGrab(device, grab, currentTime, ++ TRUE); ++ touch_event->check_grab = FALSE; ++ DeliverTouchOwnershipEvent(tc, ti); ++ return TRUE; ++ } ++ } ++ ++ if (touch_event) ++ touch_event->check_grab = TRUE; ++ ++ if (pWin->optional && ++ CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *)event, ++ sendCore, TRUE)) ++ return TRUE; + } + + return FALSE; +@@ -3962,6 +4306,17 @@ + grabinfo = &thisDev->deviceGrab; + grab = grabinfo->grab; + ++ /* Touch grab deliver is handled in ProcessTouchEvent. */ ++ if (event->any.type == ET_TouchBegin || ++ event->any.type == ET_TouchMotionUnowned) ++ { ++ if (BitIsOn(grab->xi2mask[XIAllDevices], XI_TouchOwnership) || ++ BitIsOn(grab->xi2mask[thisDev->id], XI_TouchOwnership) || ++ (IsMaster(thisDev) && ++ BitIsOn(grab->xi2mask[XIAllMasterDevices], XI_TouchOwnership))) ++ return; ++ } ++ + if (grab->ownerEvents) + { + WindowPtr focus; +@@ -4038,6 +4393,9 @@ + mask = grab->xi2mask[XIAllDevices][evtype/8] | + grab->xi2mask[XIAllMasterDevices][evtype/8] | + grab->xi2mask[thisDev->id][evtype/8]; ++ if (IsTouchEvent(event)) ++ mask |= ++ grab->xi2mask[event->device_event.sourceid][evtype/8]; + /* try XI2 event */ + FixUpEventFromWindow(pSprite, xi2, grab->window, None, TRUE); + /* XXX: XACE */ +@@ -5171,7 +5529,7 @@ + free(syncEvents.pending); + syncEvents.pending = next; + } +- syncEvents.pendtail = &syncEvents.pending; ++ syncEvents.pendtail = NULL; + syncEvents.playingEvents = FALSE; + syncEvents.time.months = 0; + syncEvents.time.milliseconds = 0; /* hardly matters */ +Index: xorg-server/dix/getevents.c +=================================================================== +--- xorg-server.orig/dix/getevents.c 2011-08-24 12:56:49.825650624 +0300 ++++ xorg-server/dix/getevents.c 2011-08-24 12:57:12.195650944 +0300 +@@ -47,6 +47,7 @@ + #include "eventstr.h" + #include "eventconvert.h" + #include "inpututils.h" ++#include "windowstr.h" + + #include <X11/extensions/XKBproto.h> + #include "xkbsrv.h" +@@ -160,7 +161,7 @@ + (1 << (key_code & 7))); + } + +-static void ++void + init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms) + { + memset(event, 0, sizeof(DeviceEvent)); +@@ -172,6 +173,18 @@ + } + + 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; ++ event->sourceid = dev->id; ++} ++ ++static void + init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail) + { + memset(event, 0, sizeof(RawDeviceEvent)); +@@ -212,7 +225,8 @@ + if (valuator_mask_isset(mask, i)) + { + SetBit(event->valuators.mask, i); +- if (valuator_get_mode(dev, i) == Absolute) ++ if (!IsTouchEvent((InternalEvent *)event) && ++ valuator_get_mode(dev, i) == Absolute) + SetBit(event->valuators.mode, i); + event->valuators.data[i] = valuator_mask_get(mask, i); + event->valuators.data_frac[i] = +@@ -1067,24 +1081,14 @@ + } + + static void +-transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask) ++transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask, int *x, int *y) + { +- struct pixman_f_vector p; +- +- /* p' = M * p in homogeneous coordinates */ +- p.v[0] = (valuator_mask_isset(mask, 0) ? valuator_mask_get(mask, 0) : +- dev->last.valuators[0]); +- p.v[1] = (valuator_mask_isset(mask, 1) ? valuator_mask_get(mask, 1) : +- dev->last.valuators[1]); +- p.v[2] = 1.0; ++ struct pixman_f_vector p = {.v = {*x, *y, 1}}; + + pixman_f_transform_point(&dev->transform, &p); + +- if (valuator_mask_isset(mask, 0)) +- valuator_mask_set(mask, 0, lround(p.v[0])); +- +- if (valuator_mask_isset(mask, 1)) +- valuator_mask_set(mask, 1, lround(p.v[1])); ++ *x = lround(p.v[0]); ++ *y = lround(p.v[1]); + } + + /** +@@ -1126,7 +1130,10 @@ + switch (type) + { + case MotionNotify: +- if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0) ++ if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0 || ++ (pDev->touch && pDev->touch->active_touches > 1 && ++ (pDev->touch->mode == XIDependentTouch || ++ pDev->touch->mode == XISemiMultitouch))) + return 0; + break; + case ButtonPress: +@@ -1178,7 +1185,16 @@ + } + } + +- transformAbsolute(pDev, &mask); ++ x = (valuator_mask_isset(&mask, 0) ? valuator_mask_get(&mask, 0) : ++ pDev->last.valuators[0]); ++ y = (valuator_mask_isset(&mask, 1) ? valuator_mask_get(&mask, 1) : ++ pDev->last.valuators[1]); ++ transformAbsolute(pDev, &mask, &x, &y); ++ if (valuator_mask_isset(&mask, 0)) ++ valuator_mask_set(&mask, 0, x); ++ if (valuator_mask_isset(&mask, 1)) ++ valuator_mask_set(&mask, 1, y); ++ + moveAbsolute(pDev, &x, &y, &mask); + } else { + if (flags & POINTER_ACCELERATE) { +@@ -1301,6 +1317,130 @@ + return num_events; + } + ++int ++GetTouchOwnershipEvents(EventList *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; ++ ++ if (reason != XITouchOwnerAccept && reason != XITouchOwnerRejectEnd) ++ return 0; ++ ++ event = (TouchOwnershipEvent *) events->event; ++ init_touch_ownership(pDev, event, ms); ++ ++ event->touchid = ti->client_id; ++ event->resource = resource; ++ event->flags = flags; ++ ++ return 1; ++} ++ ++/** ++ * Get events for a touch. Generates a TouchBegin event if end is not set and ++ * the touch id is not active. Generates a TouchMotion 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. ++ */ ++int ++GetTouchEvents(EventList *events, DeviceIntPtr pDev, TouchPointInfoPtr ti, ++ uint16_t type, uint32_t flags, const ValuatorMask *mask_in) ++{ ++ ScreenPtr scr = pDev->spriteInfo->sprite->hotPhys.pScreen; ++ TouchClassPtr t = pDev->touch; ++ DeviceEvent *event; ++ CARD32 ms = GetTimeInMillis(); ++ ValuatorMask mask; ++ int x, y; /* in screen co-ord space */ ++ float x_frac = 0.0, y_frac = 0.0; /* as above */ ++ int i; ++ ++ if (!pDev->enabled || !t || t->x_axis == -1 || t->y_axis == -1) ++ return 0; ++ ++ event = (DeviceEvent *) events->event; ++ init_event(pDev, 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 (!valuator_mask_isset(mask_in, t->x_axis) || ++ !valuator_mask_isset(mask_in, t->y_axis)) ++ { ++ DebugF("%s: Attempted to start touch without x/y (driver bug)\n", ++ pDev->name); ++ return 0; ++ } ++ break; ++ case XI_TouchUpdate: ++ event->type = ET_TouchMotion; ++ break; ++ case XI_TouchEnd: ++ event->type = ET_TouchEnd; ++ break; ++ default: ++ return 0; ++ } ++ ++ event->touchpoint = ti; ++ ++ valuator_mask_copy(&mask, mask_in); ++ ++ /* 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) { ++ if (valuator_mask_isset(&mask, t->x_axis)) ++ x = valuator_mask_get(&mask, t->x_axis); ++ else ++ x = ti->valuators[t->x_axis]; ++ x = rescaleValuatorAxis(x, 0.0, &x_frac, ++ (AxisInfoPtr)(t->axes + t->x_axis), ++ NULL, scr->width); ++ ++ if (valuator_mask_isset(&mask, t->y_axis)) ++ y = valuator_mask_get(&mask, t->y_axis); ++ else ++ y = ti->valuators[t->y_axis]; ++ y = rescaleValuatorAxis(y, 0.0, &y_frac, ++ (AxisInfoPtr)(t->axes + t->y_axis), ++ NULL, scr->height); ++ ++ transformAbsolute(pDev, &mask, &x, &y); ++ } ++ else { ++ x = pDev->spriteInfo->sprite->hotPhys.x; ++ y = pDev->spriteInfo->sprite->hotPhys.y; ++ } ++ ++ event->root_x = x; ++ event->root_y = y; ++ event->root_x_frac = x_frac; ++ event->root_y_frac = y_frac; ++ event->detail.touch = ti->client_id; ++ event->flags = flags; ++ ++ set_valuators(pDev, event, &mask); ++ for (i = 0; i < t->num_axes; i++) ++ { ++ if (valuator_mask_isset(&mask, i)) ++ ti->valuators[i] = valuator_mask_get(&mask, i); ++ } ++ ++ return 1; ++} ++ + /** + * Synthesize a single motion event for the core pointer. + * +Index: xorg-server/dix/grabs.c +=================================================================== +--- xorg-server.orig/dix/grabs.c 2011-08-24 12:52:43.795647119 +0300 ++++ xorg-server/dix/grabs.c 2011-08-24 12:56:49.855650623 +0300 +@@ -60,6 +60,7 @@ + #include "dixgrabs.h" + #include "xace.h" + #include "exevents.h" ++#include "mi.h" + + #define BITMASK(i) (((Mask)1) << ((i) & 31)) + #define MASKIDX(i) ((i) >> 5) +@@ -243,6 +244,25 @@ + } + + /** ++ * Returns the event type to match when comparing grabs. ++ */ ++static uint32_t ++GetGrabEventMatch(GrabPtr pGrab) ++{ ++ if (pGrab->grabtype != GRABTYPE_XI2) ++ return pGrab->type; ++ ++ if (pGrab->type == XI_TouchBegin || ++ pGrab->type == XI_TouchUpdate || ++ pGrab->type == XI_TouchUpdateUnowned || ++ pGrab->type == XI_TouchOwnership || ++ pGrab->type == XI_TouchEnd) ++ return XI_TouchBegin; ++ ++ return pGrab->type; ++} ++ ++/** + * Compares two grabs and returns TRUE if the first grab matches the second + * grab. + * +@@ -261,6 +281,8 @@ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; ++ uint32_t first_type = GetGrabEventMatch(pFirstGrab); ++ uint32_t second_type = GetGrabEventMatch(pSecondGrab); + + if (pFirstGrab->grabtype != pSecondGrab->grabtype) + return FALSE; +@@ -288,8 +310,8 @@ + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) + return FALSE; + +- if (pFirstGrab->type != pSecondGrab->type) +- return FALSE; ++ if (first_type != second_type) ++ return FALSE; + + if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || + GrabSupersedesSecond(pSecondGrab, pFirstGrab)) +Index: xorg-server/dix/inpututils.c +=================================================================== +--- xorg-server.orig/dix/inpututils.c 2011-08-24 12:52:43.835647119 +0300 ++++ xorg-server/dix/inpututils.c 2011-08-24 12:56:49.855650623 +0300 +@@ -36,6 +36,7 @@ + #include "xkbsrv.h" + #include "xkbstr.h" + #include "inpututils.h" ++#include "eventstr.h" + + /* Check if a button map change is okay with the device. + * Returns -1 for BadValue, as it collides with MappingBusy. */ +@@ -556,3 +557,158 @@ + + return ret; + } ++ ++/** ++ * Given the DDX-facing ID (which is _not_ DeviceEvent::detail.touch), find the ++ * associated TouchPointInfoRec. ++ */ ++TouchPointInfoPtr ++FindTouchPointByDDXID(DeviceIntPtr dev, uint32_t ddx_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->ddx_id == ddx_id && !ti->ddx_pending_finish) ++ return ti; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * Given a client-facing ID (e.g. DeviceEvent::detail.touch), find the ++ * associated TouchPointInfoRec. ++ */ ++TouchPointInfoPtr ++FindTouchPointByClientID(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 DDX ID for a touchpoint, create a touchpoint record in the ++ * server and return the client-facing ID. ++ * ++ * Returns 0 on failure (i.e. if another touch with that ID is already active, ++ * allocation failure). ++ */ ++_X_EXPORT TouchPointInfoPtr ++BeginTouchPoint(DeviceIntPtr dev, uint32_t ddx_id) ++{ ++ int i; ++ TouchClassPtr t = dev->touch; ++ TouchPointInfoPtr ti; ++ ++ if (!t) ++ return NULL; ++ ++ /* Look for another active touchpoint with the same DDX ID. It's entirely ++ * legitimate for a touchpoint to still exist with the same DDX ID but ++ * be in the pending_finish state as it waits for a client to release its ++ * grab, so allow for that. */ ++ if (FindTouchPointByDDXID(dev, ddx_id)) ++ return NULL; ++ ++ for (i = 0; i < t->num_touches; i++) ++ { ++ ti = &t->touches[i]; ++ if (!ti->active) { ++ ti->source = dev; ++ ti->active = TRUE; ++ ti->ddx_id = ddx_id; ++ ti->client_id = t->next_client_id; ++ ti->owner = -1; ++ ti->active_clients = 0; ++ ti->accepted = FALSE; ++ ti->pending_finish = FALSE; ++ t->active_touches++; ++next_touch_id: ++ t->next_client_id++; ++ if (t->next_client_id == 0) ++ t->next_client_id = 1; ++ if (FindTouchPointByClientID(dev, t->next_client_id)) ++ goto next_touch_id; /* n'th time's a charm */ ++ return ti; ++ } ++ } ++ ++ /* If we get here, then we've run out of touches. */ ++ LogMessage(X_WARNING, "%s: no more touches available\n", dev->name); ++ ++ 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 ++EndTouchPoint(DeviceIntPtr dev, TouchPointInfoPtr ti) ++{ ++ int i; ++ TouchClassPtr t = dev->touch; ++ DeviceIntPtr masterdev = dev->u.master; ++ QdEventPtr qe; ++ ++ if (dev->deviceGrab.sync.event && ++ dev->deviceGrab.sync.event->touchpoint == ti) ++ dev->deviceGrab.sync.event->touchpoint = NULL; ++ ++ if (masterdev && masterdev->deviceGrab.sync.event && ++ masterdev->deviceGrab.sync.event->touchpoint == ti) ++ masterdev->deviceGrab.sync.event->touchpoint = NULL; ++ ++ ti->source = NULL; ++ ti->pending_finish = FALSE; ++ ti->sprite.spriteTraceGood = 0; ++ ti->ddx_id = 0; ++ ti->first_history = ti->history; ++ ti->next_history = ti->history; ++ ti->emulate_pointer = FALSE; ++ ti->owner = -1; ++ ti->accepted = FALSE; ++ ti->active_clients = 0; ++ ti->ddx_pending_finish = FALSE; ++ t->active_touches--; ++ ++ if (dev->touch->emulate == ti) ++ { ++ dev->touch->emulate = NULL; ++ if (dev->u.master) ++ dev->u.master->emulate_dev = NULL; ++ ++ for (qe = syncEvents.pending; qe; qe = qe->next) ++ if ((qe->event->any.type == ET_TouchEnd || ++ qe->event->any.type == ET_ButtonRelease) && ++ qe->event->device_event.touchpoint == ti) ++ qe->event->device_event.touchpoint = NULL; ++ } ++ ++ for (i = 0; i < ti->num_valuators; i++) ++ ti->valuators[i] = 0; ++ ++ ti->client_id = 0; ++ ti->active = FALSE; ++} +Index: xorg-server/dix/window.c +=================================================================== +--- xorg-server.orig/dix/window.c 2011-08-24 12:52:43.845647121 +0300 ++++ xorg-server/dix/window.c 2011-08-24 12:57:14.735650978 +0300 +@@ -110,6 +110,7 @@ + #include "windowstr.h" + #include "input.h" + #include "inputstr.h" ++#include "exevents.h" + #include "resource.h" + #include "colormapst.h" + #include "cursorstr.h" +@@ -2875,8 +2876,10 @@ + if (!fromConfigure && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap); + } +- if (wasRealized && !fromConfigure) ++ if (wasRealized && !fromConfigure) { + WindowsRestructured (); ++ WindowGone(pWin); ++ } + return Success; + } + +@@ -2959,8 +2962,10 @@ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap); + } +- if (wasRealized) ++ if (wasRealized) { + WindowsRestructured (); ++ WindowGone(pWin); ++ } + } + + +Index: xorg-server/hw/xfree86/common/xf86Module.h +=================================================================== +--- xorg-server.orig/hw/xfree86/common/xf86Module.h 2011-08-24 12:52:43.775647117 +0300 ++++ xorg-server/hw/xfree86/common/xf86Module.h 2011-08-24 12:56:49.855650623 +0300 +@@ -83,7 +83,7 @@ + */ + #define ABI_ANSIC_VERSION SET_ABI_VERSION(0, 4) + #define ABI_VIDEODRV_VERSION SET_ABI_VERSION(10, 0) +-#define ABI_XINPUT_VERSION SET_ABI_VERSION(12, 2) ++#define ABI_XINPUT_VERSION SET_ABI_VERSION(12, 3) + #define ABI_EXTENSION_VERSION SET_ABI_VERSION(5, 0) + #define ABI_FONT_VERSION SET_ABI_VERSION(0, 6) + +Index: xorg-server/hw/xfree86/common/xf86Xinput.c +=================================================================== +--- xorg-server.orig/hw/xfree86/common/xf86Xinput.c 2011-08-24 12:52:43.755647120 +0300 ++++ xorg-server/hw/xfree86/common/xf86Xinput.c 2011-08-24 12:57:17.855651025 +0300 +@@ -1358,6 +1358,16 @@ + max_res, mode); + } + ++void ++xf86InitTouchValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, ++ int minval, int maxval, int resolution) ++{ ++ if (!dev || !dev->touch) ++ return; ++ ++ InitTouchValuatorAxisStruct(dev, axnum, label, minval, maxval, resolution); ++} ++ + /* + * Set the valuator values to be in synch with dix/event.c + * DefineInitialRootWindow(). +@@ -1409,4 +1419,50 @@ + 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. If end is TRUE, ++ * then this is taken to be the last touch in the touch sequence. ++ */ ++void ++xf86PostTouchEvent(DeviceIntPtr dev, uint32_t touchid, uint16_t type, ++ uint32_t flags, const ValuatorMask *mask) ++{ ++ int i, nevents; ++ TouchPointInfoPtr ti = FindTouchPointByDDXID(dev, touchid); ++ ++ if (ti && type == XI_TouchBegin) ++ { ++ xf86Msg(X_ERROR, ++ "%s: Tried to post touch begin for existing touch %u\n", ++ dev->name, touchid); ++ return; ++ } ++ ++ if (!ti) ++ { ++ if (type != XI_TouchBegin) ++ { ++ xf86Msg(X_ERROR, ++ "%s: Tried to post event for non-existent touch %u\n", ++ dev->name, touchid); ++ return; ++ } ++ ++ ti = BeginTouchPoint(dev, touchid); ++ if (!ti) ++ { ++ xf86Msg(X_ERROR, "%s: Couldn't create touchpoint\n", dev->name); ++ return; ++ } ++ } ++ ++ if (type == XI_TouchEnd) ++ ti->ddx_pending_finish = TRUE; ++ ++ nevents = GetTouchEvents(xf86Events, dev, ti, type, flags, mask); ++ for (i = 0; i < nevents; i++) ++ mieqEnqueue(dev, (InternalEvent *)((xf86Events + i)->event)); ++} ++ + /* end of xf86Xinput.c */ +Index: xorg-server/hw/xfree86/common/xf86Xinput.h +=================================================================== +--- xorg-server.orig/hw/xfree86/common/xf86Xinput.h 2011-08-24 12:52:43.785647118 +0300 ++++ xorg-server/hw/xfree86/common/xf86Xinput.h 2011-08-24 12:57:17.875651024 +0300 +@@ -141,6 +141,9 @@ + 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 xf86XInputSetScreen(InputInfoPtr pInfo, int screen_number, int x, int y); +@@ -148,6 +151,8 @@ + extern _X_EXPORT void xf86InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, + int maxval, int resolution, int min_res, + int max_res, int mode); ++extern _X_EXPORT void xf86InitTouchValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, ++ int minval, int maxval, int resolution); + extern _X_EXPORT void xf86InitValuatorDefaults(DeviceIntPtr dev, int axnum); + extern _X_EXPORT void xf86AddEnabledDevice(InputInfoPtr pInfo); + extern _X_EXPORT void xf86RemoveEnabledDevice(InputInfoPtr pInfo); +Index: xorg-server/include/dix.h +=================================================================== +--- xorg-server.orig/include/dix.h 2011-08-24 12:56:49.835650626 +0300 ++++ xorg-server/include/dix.h 2011-08-24 12:56:49.865650624 +0300 +@@ -375,7 +375,7 @@ + extern GrabPtr CheckPassiveGrabsOnWindow( + WindowPtr /* pWin */, + DeviceIntPtr /* device */, +- DeviceEvent * /* event */, ++ InternalEvent * /* event */, + BOOL /* checkCore */, + BOOL /* activate */); + +@@ -520,6 +520,11 @@ + DeviceIntPtr /* dev */, + xEvent* /* events */); + ++extern void RemoveTouchEventsFromQueue( ++ DeviceIntPtr /* dev */, ++ Bool /*touch*/, ++ Bool /*ignoreOwned*/); ++ + #ifdef PANORAMIX + extern _X_EXPORT void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff); + #endif +@@ -531,6 +536,8 @@ + + extern _X_EXPORT int ffs(int i); + ++extern void init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms); ++ + + /* + * ServerGrabCallback stuff +@@ -574,6 +581,7 @@ + extern Bool _X_EXPORT IsPointerDevice( DeviceIntPtr dev); + extern Bool _X_EXPORT 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); + +Index: xorg-server/include/events.h +=================================================================== +--- xorg-server.orig/include/events.h 2011-08-24 12:52:43.905647121 +0300 ++++ xorg-server/include/events.h 2011-08-24 12:57:17.895651025 +0300 +@@ -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 +Index: xorg-server/include/eventstr.h +=================================================================== +--- xorg-server.orig/include/eventstr.h 2011-08-24 12:52:43.915647119 +0300 ++++ xorg-server/include/eventstr.h 2011-08-24 12:57:14.785650979 +0300 +@@ -65,6 +65,11 @@ + ET_RawButtonRelease, + ET_RawMotion, + ET_XQuartz, ++ ET_TouchBegin, ++ ET_TouchEnd, ++ ET_TouchMotion, ++ ET_TouchMotionUnowned, ++ ET_TouchOwnership, + ET_Internal = 0xFF /* First byte */ + }; + +@@ -90,6 +95,7 @@ + union { + uint32_t button; /**< Button number */ + uint32_t key; /**< Key code */ ++ uint32_t touch; /**< Touch ID (client_id) */ + } detail; + int16_t root_x; /**< Pos relative to root window in integral data */ + float root_x_frac; /**< Pos relative to root window in frac part */ +@@ -117,8 +123,28 @@ + Window root; /**< Root window of the event */ + int corestate; /**< Core key/button state BEFORE the event */ + int key_repeat; /**< Internally-generated key repeat event */ ++ uint32_t flags; /**< Flags to be copied into the generated event */ ++ TouchPointInfoPtr touchpoint; ++ Bool check_grab; + }; + ++/** ++ * 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) */ ++ 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 +@@ -234,6 +260,7 @@ + } any; + DeviceEvent device_event; + DeviceChangedEvent changed_event; ++ TouchOwnershipEvent touch_ownership_event; + #if XFreeXDGA + DGAEvent dga_event; + #endif +Index: xorg-server/include/exevents.h +=================================================================== +--- xorg-server.orig/include/exevents.h 2011-08-24 12:52:43.935647121 +0300 ++++ xorg-server/include/exevents.h 2011-08-24 12:56:49.865650624 +0300 +@@ -51,6 +51,14 @@ + int /* max_res */, + int /* mode */); + ++extern _X_EXPORT void InitTouchValuatorAxisStruct( ++ DeviceIntPtr /* dev */, ++ int /* axnum */, ++ Atom /* label */, ++ int /* minval */, ++ int /* maxval */, ++ int /* resolution */); ++ + /* Input device properties */ + extern _X_EXPORT void XIDeleteAllDeviceProperties( + DeviceIntPtr /* device */ +@@ -199,6 +207,14 @@ + GrabMask* /* eventMask */); + + extern int ++GrabTouch( ++ ClientPtr /* client */, ++ DeviceIntPtr /* dev */, ++ DeviceIntPtr /* mod_dev */, ++ GrabParameters* /* param */, ++ GrabMask* /* eventMask */); ++ ++extern int + SelectForWindow( + DeviceIntPtr /* dev */, + WindowPtr /* pWin */, +@@ -222,6 +238,10 @@ + WindowPtr /* pWin */, + XID /* id */); + ++extern void ++WindowGone( ++ WindowPtr /* win */); ++ + extern int + SendEvent ( + ClientPtr /* client */, +@@ -309,4 +329,14 @@ + extern int + XICheckInvalidMaskBits(ClientPtr client, unsigned char *mask, int len); + ++extern void ++ProcessTouchOwnership(DeviceIntPtr dev, TouchPointInfoPtr ti, uint8_t reason, ++ Bool touch_grab); ++ ++extern int ++DeliverTouchOwnershipEvent(TouchClientPtr client, TouchPointInfoPtr ti); ++ ++extern int ++ReleaseButton(DeviceIntPtr device, int button); ++ + #endif /* EXEVENTS_H */ +Index: xorg-server/include/input.h +=================================================================== +--- xorg-server.orig/include/input.h 2011-08-24 12:52:43.895647122 +0300 ++++ xorg-server/include/input.h 2011-08-24 12:56:49.865650624 +0300 +@@ -106,6 +106,8 @@ + typedef struct _ValuatorClassRec *ValuatorClassPtr; + typedef struct _ClassesRec *ClassesPtr; + typedef struct _SpriteRec *SpritePtr; ++typedef struct _TouchClassRec *TouchClassPtr; ++typedef struct _TouchPointInfo *TouchPointInfoPtr; + typedef union _GrabMask GrabMask; + + typedef struct _EventList { +@@ -320,6 +322,12 @@ + 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*/, +@@ -469,6 +477,22 @@ + int key_code, + const ValuatorMask *mask); + ++extern int GetTouchEvents( ++ EventListPtr events, ++ DeviceIntPtr pDev, ++ TouchPointInfoPtr ti, ++ uint16_t type, ++ uint32_t flags, ++ const ValuatorMask *mask); ++ ++extern int GetTouchOwnershipEvents( ++ EventListPtr events, ++ DeviceIntPtr pDev, ++ TouchPointInfoPtr ti, ++ uint8_t mode, ++ XID resource, ++ uint32_t flags); ++ + extern int GetProximityEvents( + EventListPtr events, + DeviceIntPtr pDev, +@@ -533,6 +557,18 @@ + extern _X_EXPORT InputAttributes *DuplicateInputAttributes(InputAttributes *attrs); + extern _X_EXPORT void FreeInputAttributes(InputAttributes *attrs); + ++/* DDX touch API: create with CreateTouchPoint, use its returned ID to lookup ++ * with FindTouchPoint, and eventually end with FinishTouchPoint. */ ++extern TouchPointInfoPtr BeginTouchPoint(DeviceIntPtr dev, uint32_t ddx_id); ++extern TouchPointInfoPtr FindTouchPointByDDXID(DeviceIntPtr dev, ++ uint32_t ddx_id); ++extern TouchPointInfoPtr FindTouchPointByClientID(DeviceIntPtr dev, ++ uint32_t client_id); ++extern void EndTouchPoint(DeviceIntPtr dev, TouchPointInfoPtr ti); ++/* Internal use only, DDX this is not for you */ ++extern Bool InitTouchPoint(TouchClassPtr touch, int index); ++extern void FreeTouchPoint(DeviceIntPtr dev, int index); ++ + /* misc event helpers */ + extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients); + extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event); +Index: xorg-server/include/inputstr.h +=================================================================== +--- xorg-server.orig/include/inputstr.h 2011-08-24 12:52:43.885647120 +0300 ++++ xorg-server/include/inputstr.h 2011-08-24 12:57:12.215650943 +0300 +@@ -49,6 +49,8 @@ + #ifndef INPUTSTRUCT_H + #define INPUTSTRUCT_H + ++#include <X11/extensions/XI2proto.h> ++ + #include <pixman.h> + #include "input.h" + #include "window.h" +@@ -71,7 +73,7 @@ + * 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_TouchUpdateUnowned + #define XI2MASKSIZE ((XI2LASTEVENT + 7)/8) /* no of bits for masks */ + + /** +@@ -244,6 +246,9 @@ + + } SpriteRec; + ++#define DeepestSpriteWin(sprite) \ ++ ((sprite)->spriteTrace[(sprite)->spriteTraceGood - 1]) ++ + typedef struct _KeyClassRec { + int sourceid; + CARD8 down[DOWN_LENGTH]; +@@ -254,11 +259,11 @@ + + typedef struct _AxisInfo { + int resolution; +- int min_resolution; +- int max_resolution; + int min_value; + int max_value; + Atom label; ++ int min_resolution; ++ int max_resolution; + CARD8 mode; + } AxisInfo, *AxisInfoPtr; + +@@ -284,6 +289,75 @@ + ValuatorAccelerationRec accelScheme; + } ValuatorClassRec; + ++typedef enum { ++ TOUCH_GRAB, ++ TOUCH_SELECT, ++ TOUCH_SELECT_UNOWNED ++} TouchClientType; ++ ++typedef struct _TouchClientRec { ++ ClientPtr client; ++ WindowPtr window; ++ TouchClientType type; ++ DeviceIntPtr device; ++ DeviceIntPtr source; ++ GrabPtr grab; ++} TouchClientRec, *TouchClientPtr; ++ ++typedef struct _TouchPointInfo { ++ DeviceIntPtr source; ++ 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 */ ++ Bool ddx_pending_finish; ++ uint32_t client_id; /* touch ID as seen in client events */ ++ uint32_t ddx_id; /* touch ID given by the DDX */ ++ SpriteRec sprite; /* window trace for delivery */ ++ TouchClientPtr clients; ++ int num_clients; ++ int active_clients; ++ int owner; ++ Bool accepted; ++ int *valuators; /* last recorded axis values */ ++ int num_valuators; /* == TouchClassInfo::num_axes */ ++#if 0 ++ XID *listeners; /* grabs/event selection IDs receiving ++ * events for this touch */ ++ int num_listeners; ++ int num_grabs; /* number of open grabs on this touch ++ * which have not accepted or rejected */ ++ WindowPtr select_win; ++ Bool select_unowned; ++#endif ++ Bool emulate_pointer; ++ InternalEvent *begin_event; /* Touch begin event for history */ ++ InternalEvent *history; /* Touch motion and end history events */ ++ unsigned int history_size; /* Size of history ring buffer */ ++ InternalEvent *first_history; /* Pointer to first event in history */ ++ InternalEvent *next_history; /* Pointer to next available event */ ++} TouchPointInfoRec; ++ ++typedef struct _TouchAxisInfo { ++ int resolution; ++ int min_value; ++ int max_value; ++ Atom label; ++} TouchAxisInfoRec, *TouchAxisInfoPtr; ++ ++typedef struct _TouchClassRec { ++ TouchAxisInfoPtr axes; ++ unsigned short num_axes; ++ TouchPointInfoPtr touches; ++ unsigned short num_touches; /* number of allocated touches */ ++ unsigned short max_touches; /* maximum number of touches, may be 0 */ ++ unsigned short active_touches; /* number of active touches */ ++ CARD8 mode; /* ::XIDirectTouch, XIDependentTouch */ ++ uint32_t next_client_id; /* next client_id to give out */ ++ int x_axis; /* axis number of x axis */ ++ int y_axis; /* axis number of y axis */ ++ TouchPointInfoPtr emulate; ++} TouchClassRec; ++ + typedef struct _ButtonClassRec { + int sourceid; + CARD8 numButtons; +@@ -388,6 +462,7 @@ + typedef struct _ClassesRec { + KeyClassPtr key; + ValuatorClassPtr valuator; ++ TouchClassPtr touch; + ButtonClassPtr button; + FocusClassPtr focus; + ProximityClassPtr proximity; +@@ -512,6 +587,7 @@ + int id; + KeyClassPtr key; + ValuatorClassPtr valuator; ++ TouchClassPtr touch; + ButtonClassPtr button; + FocusClassPtr focus; + ProximityClassPtr proximity; +@@ -533,6 +609,8 @@ + DeviceIntPtr master; /* master device */ + DeviceIntPtr lastSlave; /* last slave device used */ + } u; ++ DeviceIntPtr emulate_dev; ++ Bool process_touch; + + /* last valuator values recorded, not posted to client; + * for slave devices, valuators is in device coordinates +@@ -592,7 +670,7 @@ + */ + typedef struct _EventSyncInfo { + QdEventPtr pending, /**< list of queued events */ +- *pendtail; /**< last event in list */ ++ pendtail; /**< last event in list */ + /** The device to replay events for. Only set in AllowEvents(), in which + * case it is set to the device specified in the request. */ + DeviceIntPtr replayDev; /* kludgy rock to put flag for */ +Index: xorg-server/include/protocol-versions.h +=================================================================== +--- xorg-server.orig/include/protocol-versions.h 2011-08-24 12:56:49.825650624 +0300 ++++ xorg-server/include/protocol-versions.h 2011-08-24 12:57:14.795650980 +0300 +@@ -131,7 +131,7 @@ + + /* X Input */ + #define SERVER_XI_MAJOR_VERSION 2 +-#define SERVER_XI_MINOR_VERSION 0 ++#define SERVER_XI_MINOR_VERSION 1 + + /* XKB */ + #define SERVER_XKB_MAJOR_VERSION 1 +Index: xorg-server/mi/mieq.c +=================================================================== +--- xorg-server.orig/mi/mieq.c 2011-08-24 12:52:43.945647123 +0300 ++++ xorg-server/mi/mieq.c 2011-08-24 12:57:14.815650981 +0300 +@@ -269,8 +269,15 @@ + case ET_ProximityOut: + case ET_Hierarchy: + case ET_DeviceChanged: ++ case ET_TouchBegin: ++ case ET_TouchEnd: ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: + event->device_event.deviceid = dev->id; + break; ++ case ET_TouchOwnership: ++ event->touch_ownership_event.deviceid = dev->id; ++ break; + #if XFreeXDGA + case ET_DGAEvent: + break; +@@ -419,7 +426,7 @@ + + /* Check for the SD's master in case the device got detached + * during event processing */ +- if (master && dev->u.master) ++ if (master && dev->u.master && !IsTouchEvent(&mevent)) + master->public.processInputProc(&mevent, master); + } + } +Index: xorg-server/test/input.c +=================================================================== +--- xorg-server.orig/test/input.c 2011-08-24 12:52:43.725647116 +0300 ++++ xorg-server/test/input.c 2011-08-24 12:56:49.865650624 +0300 +@@ -278,6 +278,11 @@ + dix_event_to_core_fail(ET_ProximityOut + 1, BadImplementation); + dix_event_to_core_fail(ET_ProximityIn, BadMatch); + dix_event_to_core_fail(ET_ProximityOut, BadMatch); ++ dix_event_to_core_fail(ET_TouchBegin, BadMatch); ++ dix_event_to_core_fail(ET_TouchMotion, BadMatch); ++ dix_event_to_core_fail(ET_TouchMotionUnowned, BadMatch); ++ dix_event_to_core_fail(ET_TouchOwnership, BadMatch); ++ dix_event_to_core_fail(ET_TouchEnd, BadMatch); + + dix_event_to_core(ET_KeyPress); + dix_event_to_core(ET_KeyRelease); +@@ -423,6 +428,32 @@ + } + + ++static void dix_event_to_xi2_conversion(void) ++{ ++ DeviceEvent ev; ++ xXIDeviceEvent *xi2, *xi2_flags; ++ int rc; ++ ++ memset(&ev, 0, sizeof(ev)); ++ ++ ev.header = 0xFF; ++ ev.length = sizeof(DeviceEvent); ++ ev.type = ET_TouchBegin; ++ ++ rc = EventToXI2((InternalEvent*)&ev, (xEvent**)&xi2); ++ g_assert(rc == Success); ++ g_assert(xi2->type == GenericEvent); ++ g_assert(xi2->evtype == XI_TouchBegin); ++ g_assert(xi2->flags == 0); ++ ++ rc = EventToXI2((InternalEvent*)&ev, (xEvent**)&xi2_flags); ++ g_assert(rc == Success); ++ g_assert(xi2_flags->type == GenericEvent); ++ g_assert(xi2_flags->evtype == XI_TouchBegin); ++ xi2_flags->flags = 0; ++ g_assert(memcmp(xi2, xi2_flags, sizeof(*xi2)) == 0); ++} ++ + static void xi2_struct_sizes(void) + { + #define compare(req) \ +@@ -812,6 +843,38 @@ + g_assert(rc == TRUE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == TRUE); ++ ++ /* All touch grabs must match a TouchBegin grab. */ ++ a.grabtype = GRABTYPE_XI2; ++ b.grabtype = GRABTYPE_XI2; ++ a.type = XI_TouchBegin; ++ b.type = XI_TouchUpdate; ++ a.detail.exact = 0; ++ b.detail.exact = 0; ++ a.modifiersDetail.exact = 0; ++ b.modifiersDetail.exact = 0; ++ rc = GrabMatchesSecond(&a, &b, FALSE); ++ g_assert(rc == TRUE); ++ rc = GrabMatchesSecond(&b, &a, FALSE); ++ g_assert(rc == TRUE); ++ ++ b.type = XI_TouchUpdateUnowned; ++ rc = GrabMatchesSecond(&a, &b, FALSE); ++ g_assert(rc == TRUE); ++ rc = GrabMatchesSecond(&b, &a, FALSE); ++ g_assert(rc == TRUE); ++ ++ b.type = XI_TouchOwnership; ++ rc = GrabMatchesSecond(&a, &b, FALSE); ++ g_assert(rc == TRUE); ++ rc = GrabMatchesSecond(&b, &a, FALSE); ++ g_assert(rc == TRUE); ++ ++ b.type = XI_TouchEnd; ++ rc = GrabMatchesSecond(&a, &b, FALSE); ++ g_assert(rc == TRUE); ++ rc = GrabMatchesSecond(&b, &a, FALSE); ++ g_assert(rc == TRUE); + } + + static void test_bits_to_byte(int i) +@@ -1224,6 +1287,101 @@ + free(v); + } + ++static void touch_create(void) ++{ ++ DeviceIntRec dev; ++ TouchClassRec touch; ++ TouchPointInfoRec touches[2]; ++ TouchPointInfoPtr ti; ++ ++ memset(&dev, 0, sizeof(dev)); ++ memset(&touch, 0, sizeof(touch)); ++ memset(touches, 0, sizeof(*touches) * 2); ++ touch.touches = touches; ++ touch.num_touches = 2; ++ touch.num_axes = 2; ++ touch.next_client_id = 1; ++ dev.touch = &touch; ++ ++ /* Make sure we get a valid touchpoint back. */ ++ ti = BeginTouchPoint(&dev, 0xdeadbeef); ++ g_assert(ti); ++ g_assert(ti->active == TRUE); ++ g_assert(ti->ddx_id == 0xdeadbeef); ++ g_assert(ti->client_id != 0); ++ g_assert(ti->pending_finish == 0); ++ g_assert(ti->sprite.spriteTraceGood == 0); ++} ++ ++static void touch_find_point(void) ++{ ++ DeviceIntRec dev; ++ TouchClassRec touch; ++ TouchPointInfoRec touches[2]; ++ TouchPointInfoPtr create_ret, find_ret; ++ ++ memset(&dev, 0, sizeof(dev)); ++ memset(&touch, 0, sizeof(touch)); ++ memset(touches, 0, sizeof(*touches) * 2); ++ touch.touches = touches; ++ touch.num_touches = 2; ++ touch.num_axes = 2; ++ touch.next_client_id = 1; ++ dev.touch = &touch; ++ ++ create_ret = BeginTouchPoint(&dev, 0xdeadbeef); ++ g_assert(create_ret); ++ ++ /* Make sure we can find the touch by both DDX and client ID. */ ++ find_ret = FindTouchPointByDDXID(&dev, 0xdeadbeef); ++ g_assert(create_ret == find_ret); ++ find_ret = FindTouchPointByClientID(&dev, create_ret->client_id); ++ g_assert(find_ret->active == TRUE); ++ g_assert(find_ret->ddx_id == 0xdeadbeef); ++ ++ /* Touches which are pending finish must be findable by their client ID, ++ * but not by their DDX ID, as only the DIX can inject ownership change ++ * events. */ ++ find_ret->ddx_pending_finish = 1; ++ find_ret = FindTouchPointByClientID(&dev, create_ret->client_id); ++ g_assert(find_ret == create_ret); ++ find_ret = FindTouchPointByDDXID(&dev, 0xdeadbeef); ++ g_assert(!find_ret); ++} ++ ++static void touch_finish(void) ++{ ++ DeviceIntRec dev; ++ TouchClassRec touch; ++ TouchPointInfoRec touches[2]; ++ TouchPointInfoPtr ti; ++ uint32_t client_id; ++ ++ memset(&dev, 0, sizeof(dev)); ++ memset(&touch, 0, sizeof(touch)); ++ memset(touches, 0, sizeof(*touches) * 2); ++ touch.touches = touches; ++ touch.num_touches = 2; ++ touch.num_axes = 2; ++ touch.next_client_id = 1; ++ dev.touch = &touch; ++ ++ /* Make sure the touch is in a sane state once we kill it, and that we ++ * can't find it once it's gone. */ ++ ti = BeginTouchPoint(&dev, 0xdeadbeef); ++ g_assert(ti); ++ client_id = ti->client_id; ++ EndTouchPoint(&dev, ti); ++ g_assert(ti->active == FALSE); ++ g_assert(ti->pending_finish == 0); ++ g_assert(ti->sprite.spriteTraceGood == 0); ++ g_assert(ti->client_id == 0); ++ g_assert(ti->ddx_id == 0); ++ ++ g_assert(FindTouchPointByDDXID(&dev, 0xdeadbeef) == NULL); ++ g_assert(FindTouchPointByClientID(&dev, client_id) == NULL); ++} ++ + int main(int argc, char** argv) + { + g_test_init(&argc, &argv,NULL); +@@ -1234,6 +1392,7 @@ + g_test_add_func("/dix/input/init-valuators", dix_init_valuators); + g_test_add_func("/dix/input/event-core-conversion", dix_event_to_core_conversion); + g_test_add_func("/dix/input/event-xi1-conversion", dix_event_to_xi1_conversion); ++ g_test_add_func("/dix/input/event-xi2-conversion", dix_event_to_xi2_conversion); + g_test_add_func("/dix/input/check-grab-values", dix_check_grab_values); + g_test_add_func("/dix/input/xi2-struct-sizes", xi2_struct_sizes); + g_test_add_func("/dix/input/grab_matching", dix_grab_matching); +@@ -1242,6 +1401,9 @@ + g_test_add_func("/include/bit_test_macros", include_bit_test_macros); + g_test_add_func("/Xi/xiproperty/register-unregister", xi_unregister_handlers); + g_test_add_func("/dix/input/valuator-alloc", dix_valuator_alloc); ++ g_test_add_func("/dix/input/touch-create", touch_create); ++ g_test_add_func("/dix/input/touch-find-point", touch_find_point); ++ g_test_add_func("/dix/input/touch-finish", touch_finish); + + return g_test_run(); + } +Index: xorg-server/test/xi2/protocol-eventconvert.c +=================================================================== +--- xorg-server.orig/test/xi2/protocol-eventconvert.c 2011-08-24 12:52:43.735647117 +0300 ++++ xorg-server/test/xi2/protocol-eventconvert.c 2011-08-24 12:56:49.865650624 +0300 +@@ -149,6 +149,59 @@ + free(swapped); + } + ++static void test_values_XITouchOwnershipEvent(TouchOwnershipEvent *in, ++ xXITouchOwnershipEvent *out, ++ BOOL swap) ++{ ++ char n; ++ ++ if (swap) ++ { ++ swaps(&out->sequenceNumber, n); ++ swapl(&out->length, n); ++ swaps(&out->evtype, n); ++ swaps(&out->deviceid, n); ++ swapl(&out->time, n); ++ swaps(&out->sourceid, n); ++ swapl(&out->touchid, n); ++ swapl(&out->flags, n); ++ } ++ ++ g_assert(out->type == GenericEvent); ++ g_assert(out->extension == 0); ++ g_assert(out->length == bytes_to_int32(sizeof(*out) - sizeof(xEvent))); ++ g_assert(out->evtype == XI_TouchOwnership); ++ g_assert(out->deviceid == in->deviceid); ++ g_assert(out->time == in->time); ++ g_assert(out->sourceid == in->sourceid); ++ g_assert(out->touchid == in->touchid); ++ g_assert(out->flags == in->flags); ++} ++ ++static void test_convert_XITouchOwnershipEvent(void) ++{ ++ TouchOwnershipEvent in; ++ xXITouchOwnershipEvent *out, swapped; ++ int rc; ++ ++ in.header = ET_Internal; ++ in.type = ET_TouchOwnership; ++ in.touchid = 0xdeadbeef; ++ in.time = 234; ++ in.deviceid = 12; ++ in.sourceid = 14; ++ in.resource = 0xcafebabe; ++ in.flags = 0; ++ rc = EventToXI2((InternalEvent *) &in, (xEvent **) &out); ++ g_assert(rc == Success); ++ ++ test_values_XITouchOwnershipEvent(&in, out, FALSE); ++ XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)&swapped); ++ test_values_XITouchOwnershipEvent(&in, &swapped, TRUE); ++ ++ free(out); ++} ++ + static void test_convert_XIFocusEvent(void) + { + xEvent *out; +@@ -272,7 +325,7 @@ + int buttons, valuators; + int i; + unsigned char *ptr; +- uint32_t flagmask = 0; ++ uint32_t flagmask; + FP3232 *values; + + if (swap) { +@@ -311,9 +364,16 @@ + g_assert(out->sourceid == in->sourceid); + + switch (in->type) { ++ case ET_ButtonPress: ++ case ET_ButtonRelease: ++ case ET_Motion: ++ flagmask = XIPointerEmulated; ++ break; + case ET_KeyPress: + flagmask = XIKeyRepeat; + break; ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: + default: + flagmask = 0; + break; +@@ -636,6 +696,49 @@ + } + } + ++static void test_convert_XITouch(void) ++{ ++ DeviceEvent in; ++ ++ memset(&in, 0, sizeof(in)); ++ ++ g_test_message("Testing TouchBegin"); ++ in.header = ET_Internal; ++ in.type = ET_TouchBegin; ++ in.length = sizeof(DeviceEvent); ++ in.time = 0; ++ in.deviceid = 1; ++ in.sourceid = 2; ++ in.root = 3; ++ in.root_x = 4; ++ in.root_x_frac = 5; ++ in.root_y = 6; ++ in.root_y_frac = 7; ++ in.detail.button = 8; ++ in.mods.base = 9; ++ in.mods.latched = 10; ++ in.mods.locked = 11; ++ in.mods.effective = 11; ++ in.group.base = 12; ++ in.group.latched = 13; ++ in.group.locked = 14; ++ in.group.effective = 15; ++ test_XIDeviceEvent(&in); ++ ++ in.flags = 0; ++ g_test_message("Testing TouchMotion"); ++ in.type = ET_TouchMotion; ++ test_XIDeviceEvent(&in); ++ ++ g_test_message("Testing TouchMotionUnowned"); ++ in.type = ET_TouchMotionUnowned; ++ test_XIDeviceEvent(&in); ++ ++ g_test_message("Testing TouchEnd"); ++ in.type = ET_TouchEnd; ++ test_XIDeviceEvent(&in); ++} ++ + static void test_values_XIDeviceChangedEvent(DeviceChangedEvent *in, + xXIDeviceChangedEvent *out, + BOOL swap) +@@ -912,6 +1015,8 @@ + g_test_add_func("/xi2/eventconvert/XIFocusEvent", test_convert_XIFocusEvent); + g_test_add_func("/xi2/eventconvert/XIDeviceEvent", test_convert_XIDeviceEvent); + g_test_add_func("/xi2/eventconvert/XIDeviceChangedEvent", test_convert_XIDeviceChangedEvent); ++ g_test_add_func("/xi2/eventconvert/XITouch", test_convert_XITouch); ++ g_test_add_func("/xi2/eventconvert/XITouchOwnership", test_convert_XITouchOwnershipEvent); + + return g_test_run(); + } +Index: xorg-server/test/xi2/protocol-xiselectevents.c +=================================================================== +--- xorg-server.orig/test/xi2/protocol-xiselectevents.c 2011-08-24 12:52:43.745647118 +0300 ++++ xorg-server/test/xi2/protocol-xiselectevents.c 2011-08-24 12:56:49.865650624 +0300 +@@ -159,9 +159,33 @@ + memset(bits, 0, mask->mask_len * 4); + for (j = 0; j <= XI2LASTEVENT; j++) + { ++ /* Can't select for these events alone */ ++ if (j == XI_TouchBegin || j == XI_TouchOwnership || ++ j == XI_TouchEnd) ++ continue; ++ + SetBit(bits, j); ++ ++ /* Must select for TouchBegin + TouchMotion + TouchEnd together, ++ * and optionally also TouchMotionUnowned and TouchOwnerhip. */ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ SetBit(bits, XI_TouchBegin); ++ SetBit(bits, XI_TouchUpdate); ++ SetBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ SetBit(bits, XI_TouchOwnership); ++ } ++ + request_XISelectEvent(req, Success); + ClearBit(bits, j); ++ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ ClearBit(bits, XI_TouchBegin); ++ ClearBit(bits, XI_TouchUpdate); ++ ClearBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ ClearBit(bits, XI_TouchOwnership); ++ } + } + + /* Test 2: +@@ -175,7 +199,23 @@ + + for (j = 0; j <= XI2LASTEVENT; j++) + { ++ /* Can't select for these events alone */ ++ if (j == XI_TouchBegin || j == XI_TouchOwnership || ++ j == XI_TouchEnd) ++ continue; ++ + SetBit(bits, j); ++ ++ /* Must select for TouchBegin + TouchMotion + TouchEnd together, ++ * and optionally also TouchMotionUnowned and TouchOwnerhip. */ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ SetBit(bits, XI_TouchBegin); ++ SetBit(bits, XI_TouchUpdate); ++ SetBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ SetBit(bits, XI_TouchOwnership); ++ } ++ + request_XISelectEvent(req, Success); + } + +@@ -189,7 +229,23 @@ + + for (j = XI2LASTEVENT + 1; j < mask->mask_len * 4; j++) + { ++ /* Can't select for these events alone */ ++ if (j == XI_TouchBegin || j == XI_TouchOwnership || ++ j == XI_TouchEnd) ++ continue; ++ + SetBit(bits, j); ++ ++ /* Must select for TouchBegin + TouchMotion + TouchEnd together, ++ * and optionally also TouchMotionUnowned and TouchOwnerhip. */ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ SetBit(bits, XI_TouchBegin); ++ SetBit(bits, XI_TouchUpdate); ++ SetBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ SetBit(bits, XI_TouchOwnership); ++ } ++ + request_XISelectEvent(req, BadValue); + ClearBit(bits, j); + } +@@ -202,7 +258,23 @@ + memset(bits, 0, mask->mask_len * 4); + for (j = 0; j <= XI2LASTEVENT; j++) + { ++ /* Can't select for these events alone */ ++ if (j == XI_TouchBegin || j == XI_TouchOwnership || ++ j == XI_TouchEnd) ++ continue; ++ + SetBit(bits, j); ++ ++ /* Must select for TouchBegin + TouchMotion + TouchEnd together, ++ * and optionally also TouchMotionUnowned and TouchOwnerhip. */ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ SetBit(bits, XI_TouchBegin); ++ SetBit(bits, XI_TouchUpdate); ++ SetBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ SetBit(bits, XI_TouchOwnership); ++ } ++ + request_XISelectEvent(req, Success); + } + |