summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Willich <sabotageandi@gmail.com>2011-10-29 21:43:27 +0200
committerAndreas Willich <sabotageandi@gmail.com>2011-10-29 21:43:27 +0200
commitc920e8daaa4a4a4a601f606eaa4764750fe80639 (patch)
tree6ee77ae8a68b6a41965a39bdef398543731d3b35 /x11-base/xorg-server
parentUpdate patch with latest nathy release (diff)
downloadsabotageandi-c920e8daaa4a4a4a601f606eaa4764750fe80639.tar.gz
sabotageandi-c920e8daaa4a4a4a601f606eaa4764750fe80639.tar.bz2
sabotageandi-c920e8daaa4a4a4a601f606eaa4764750fe80639.zip
update versions
Diffstat (limited to 'x11-base/xorg-server')
-rw-r--r--x11-base/xorg-server/Manifest12
-rw-r--r--x11-base/xorg-server/files/xorg-cve-2011-4028+4029.patch22
-rw-r--r--x11-base/xorg-server/files/xorg-server-1.10.4-r2-Xi_ensure_replayed_touch_events_have_devices.patch35
-rw-r--r--x11-base/xorg-server/files/xorg-server-1.10.4-r2-Xi_ensure_touch_events_update_currentTime.patch27
-rw-r--r--x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_masked_transformed_valuators.patch106
-rw-r--r--x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_no_coords.patch66
-rw-r--r--x11-base/xorg-server/files/xorg-server-1.10.4-r2-fix_touchpad_touch_event_removal.patch16
-rw-r--r--x11-base/xorg-server/files/xorg-server-1.10.4-r2-gestures-extension.patch1482
-rw-r--r--x11-base/xorg-server/files/xorg-server-1.10.4-r2-touch_grab_reject_send_ownership.patch12
-rw-r--r--x11-base/xorg-server/files/xorg-server-1.10.4-r2-xf86CoordinatesToWindow.patch97
-rw-r--r--x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch4603
-rw-r--r--x11-base/xorg-server/xorg-server-1.10.4-r2.ebuild258
12 files changed, 6736 insertions, 0 deletions
diff --git a/x11-base/xorg-server/Manifest b/x11-base/xorg-server/Manifest
index 78fb8d2..a4d01d2 100644
--- a/x11-base/xorg-server/Manifest
+++ b/x11-base/xorg-server/Manifest
@@ -2,7 +2,17 @@ AUX diff 1314 RMD160 4e6315e4672e82c2bbe7c07edc5c88ede05400ca SHA1 878bf857b98ae
AUX xdm-setup.initd-1 339 RMD160 dd3f50da114627d2be776b41a0d7d967ebbff477 SHA1 d86813f810aab72b81a72c298c2d230554d8e82e SHA256 018bc6acc70c708d8e3935617b8da2b84a3f5502a4db4c4731c2eaea7d3f04c0
AUX xdm.confd-3 853 RMD160 363cd18f760650923e16579bf55f661e93dad63b SHA1 0027b98f2aeb5c43219fa4f9b7d81a05101bec6f SHA256 00af0d957ff1b4f31c1aa4701d93a54080408548792deafac5414cbfa13b89ec
AUX xdm.initd-3 5551 RMD160 7af6e239e3e75ea88a0766ef2f4976a8b5c51c95 SHA1 bd30222c7941d50fc0f62c5008a0e3b97e2d00e0 SHA256 8f1d35638559d12ed14e8cc2e26800e0ee9a10f14c7be912c834c73d12913601
+AUX xorg-cve-2011-4028+4029.patch 671 RMD160 f9c607b5bfe20259f2adb320b6a1a0819f59f7ab SHA1 84797b66434aa05acc9f6881050d1b46487caf77 SHA256 76b9bb4a928fa7179eb52ab3b2bd2ef6d7db83e0543ba80de37cdab05efa601c
AUX xorg-server-1.10.2-xi2.patch 151994 RMD160 c3b23f7b01db5e50ae791a18588b781744efbe5f SHA1 84e9f899d7aeb1aa9a950ac170eb4e5fc83a777a SHA256 f711608e6de2dcb5e38db7d44ba0c0b441e37310f3f0faae75c3a61f84a7fdd1
+AUX xorg-server-1.10.4-r2-Xi_ensure_replayed_touch_events_have_devices.patch 1354 RMD160 2ec7d8d7f4ec90f086920665bb578e49b1364d3f SHA1 cd76af2111138977a89cbae879c55ab765b38536 SHA256 428b2cac4ecaae21b8b0fa02b8e5c35e0546af13ee210fc696a4d1dd4c501a7c
+AUX xorg-server-1.10.4-r2-Xi_ensure_touch_events_update_currentTime.patch 841 RMD160 9ca2c1f579b423a7574feb09dd4ec7aa1ffe5b11 SHA1 40366d68d49e3429788a453e2cb8fa643839ed34 SHA256 679ddea1436649782c1f9ac378636499e1c911b8841fd0457b1f0139457eb1e9
+AUX xorg-server-1.10.4-r2-fix_masked_transformed_valuators.patch 4084 RMD160 5afd69602bf795815eb5fa4c697a54f35eec13ae SHA1 07c8a1af79adfd0782579df18b3092e13fbece3e SHA256 0caf67bcde65be04efe1dd7853757972a71d79f6b21996eb662fba318f598f31
+AUX xorg-server-1.10.4-r2-fix_no_coords.patch 2443 RMD160 b0c56934c4fc4129777b98caa1ef861ba9090cf5 SHA1 7cfe696f1bfaf570ef98cda41f99bc86dc96616b SHA256 e0283ee39a357891b35f29486b2fec67eb263c97bb94a370990b1211e14eeb13
+AUX xorg-server-1.10.4-r2-fix_touchpad_touch_event_removal.patch 570 RMD160 308608604d55555d6ce529e30a87097645a83d7f SHA1 90982f2c4d843333880080872f56176892968432 SHA256 4db65cb116aa717e35c5acd60b94b3584f02ed392028de50c697aba989c269a0
+AUX xorg-server-1.10.4-r2-gestures-extension.patch 51444 RMD160 cbad0f5d0ad745da23dbba77fc2c7196bbe1a4a9 SHA1 002987cd6081782a858c6a80cdf7eb61a4a73aa8 SHA256 98a0653e56c17e140d025911b553fd08bce8fe2da8cc744ca6241d69938ded06
+AUX xorg-server-1.10.4-r2-touch_grab_reject_send_ownership.patch 516 RMD160 cc2cce7c466e0cbec1eda5432382e6a977aa9a52 SHA1 96bd512777956d4c10a091bbfa44b9efb76c6908 SHA256 c1424cae208dd3e76f3b4fc3a4a356fae7569d6f0b0291342644f5eee6d154fd
+AUX xorg-server-1.10.4-r2-xf86CoordinatesToWindow.patch 3219 RMD160 9d3193333484d239827a90583ec5736ff1e7cbb9 SHA1 1cb1623a2aa5597279cd96796c1181de5798034e SHA256 ff44f8039194816abd3c948f656dac76dd0523f790e2d79537bf2e4a536155a9
+AUX xorg-server-1.10.4-r2-xi2.1.patch 154422 RMD160 4945ccf5ca36b689975fc8acbf4e91251629fa7f SHA1 31115b7e8321e431a082dab4d79c2874ad78cba3 SHA256 9e7d489014fb79b2a22e27017681c99973770b6868d8c7040b287018678f673e
AUX xorg-server-1.9-nouveau-default.patch 916 RMD160 0ebdf0fb76364b7fd0c520c3a2f7cc2cc1a83446 SHA1 daddde0f4f4276e12b87354d2e6825ed5c74c6eb SHA256 a7ff421dd928e3025194279f9afb7cc033a896b3417abe339741e9c6ed4b54ea
AUX xorg-server-disable-acpi.patch 663 RMD160 7074ca5276369b746ea7606a0795232aafe07c90 SHA1 d300a37dd2e0a8aa3965948c13f6995e6767841d SHA256 5b3cc7c8bea18fe3ba81851d2846d19ffd8fab9cdf5d8f3a274846847e734200
AUX xorg-server-gestures-extension.patch 50539 RMD160 750aac5c86c9006fc02e3effc3dbf5d1814d4954 SHA1 7cea9924080d9ed89929af477281eddb0310155a SHA256 6b4ebcd5a5e69f8978b78aa1a7f4726f529484aaf3f469c9e9cb09362b229517
@@ -15,6 +25,7 @@ DIST xorg-server-1.10.1.901.tar.bz2 5333795 RMD160 a20397a1cbdae631ed0235b1a1576
DIST xorg-server-1.10.1.tar.bz2 5344169 RMD160 f0333f67f8226c21bfad395bb3ee72e6d10784f6 SHA1 59ada4c9a59f7f1eb4b68c359e9cd58272aa4809 SHA256 143c7c3d7d4428352e1153dffa34fd64af391f72d30b2a03e911e54e36f00b5d
DIST xorg-server-1.10.2.tar.bz2 5334473 RMD160 3d1ad6b236772ebe0400a69a03b9093bb210fd4b SHA1 fd831b3c6297d1a68830c602d767752d87b9ca54 SHA256 65264f6640568b9db8d738aec1ddd036c3ae21b7ba05b98d006759d11a72792c
DIST xorg-server-1.10.3.tar.bz2 5338354 RMD160 dfa59ac6d3f3f7fd059e6f92cead352845e08228 SHA1 1699be5c0edeca553cfa3ee6caa228483465136b SHA256 05ec05fbc8ec336127071db38cfb61c618e43b720edbd8d51d171c0cd359e290
+DIST xorg-server-1.10.4.tar.bz2 5386174 RMD160 13eeaf7497e63ecddba46010c075d27121e18aae SHA1 857d6377025c77851a3cc5f8ec2ce84164a2fdc6 SHA256 fafc16b97b9a61b62dfaa74e8d336baa0cea752ce9ed8103c4d212baa8031ca5
EBUILD xorg-server-1.10.0.901-r1.ebuild 7468 RMD160 1ba24286737bbd786dd9f0374a34e466a27b2d89 SHA1 900417293a95a20ae0ccb5de1dc5b0f82ac1d8d7 SHA256 dfdae8ea718430170aac89a3b0258c5f133bb2c790768d1af98c754d870ea848
EBUILD xorg-server-1.10.0.902-r1.ebuild 7478 RMD160 44a339ca7f765082db7eddd2d4f56e205b7ef892 SHA1 45dd41487e6781da98ceb8ec900249679390b704 SHA256 489bfe1731cc7fd3f27219cf4dfc54d1f73d093e9a3fa0e1217a04c5cbb4ff49
EBUILD xorg-server-1.10.1-r1.ebuild 7478 RMD160 44a339ca7f765082db7eddd2d4f56e205b7ef892 SHA1 45dd41487e6781da98ceb8ec900249679390b704 SHA256 489bfe1731cc7fd3f27219cf4dfc54d1f73d093e9a3fa0e1217a04c5cbb4ff49
@@ -22,4 +33,5 @@ EBUILD xorg-server-1.10.1.901-r1.ebuild 7079 RMD160 ac0f9f268114cd762f03de6c4e47
EBUILD xorg-server-1.10.1.ebuild 7285 RMD160 be4ef109bc4283fc1eb95fddfb91470c7cca3a16 SHA1 5c1e089c125930a977f78bb9510ec8522e421f05 SHA256 d359e216185b19e56de4338b5ae2b7bd5d5936dac594f035694f3b95a122a287
EBUILD xorg-server-1.10.2-r1.ebuild 7119 RMD160 018d5084b72ab1d675d88b32e35027c6cf2f4b76 SHA1 d1820c2c41018a396834fa15655d5c39dd01f94a SHA256 ac45ed8ec1a34c7d0f93ad68ca497dd5b026d0cbfc23dff7cc40178175231ad9
EBUILD xorg-server-1.10.3-r1.ebuild 7211 RMD160 e0419eea946584f04ee647aeaa69df71a98bcad3 SHA1 97cf885bfe8507683c6a941e846cd744ccb54f67 SHA256 91b3ca4c7e710d50a43567bd4f4de17f5aaaac8ec7df470639b3795c2a5cf741
+EBUILD xorg-server-1.10.4-r2.ebuild 7823 RMD160 ba79f6e6fc3878ce01447cb6113aebfed5395750 SHA1 e7749940c9cfc5b7c2ff5f452c74212b6d6e34a1 SHA256 45d0a8648b22a202889f07959ef089a096a415bffb5132c8050d1b3c33b5754a
MISC metadata.xml 493 RMD160 ec65f5d2366b47e4af3b5c3878067dfd60b56fc1 SHA1 b2035802eabc77fccfaf65c495289a0b8057bf86 SHA256 88cefe886a81d725df9c137d15ac51ae6b05a225f52f13b478fa48e10e71fdff
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,
+ &param, &mask);
+ break;
++ case XIGrabtypeTouchBegin:
++ status = GrabTouch(client, dev, mod_dev, &param, &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);
+ }
+
diff --git a/x11-base/xorg-server/xorg-server-1.10.4-r2.ebuild b/x11-base/xorg-server/xorg-server-1.10.4-r2.ebuild
new file mode 100644
index 0000000..0d4120b
--- /dev/null
+++ b/x11-base/xorg-server/xorg-server-1.10.4-r2.ebuild
@@ -0,0 +1,258 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/x11-base/xorg-server/xorg-server-1.10.4-r1.ebuild,v 1.4 2011/10/22 16:57:28 xarthisius Exp $
+
+EAPI=4
+
+XORG_EAUTORECONF=yes
+XORG_DOC=doc
+inherit xorg-2 multilib versionator
+EGIT_REPO_URI="git://anongit.freedesktop.org/git/xorg/xserver"
+
+DESCRIPTION="X.Org X servers"
+KEYWORDS="alpha amd64 arm hppa ia64 ~mips ppc ppc64 sh sparc x86 ~x86-fbsd"
+
+IUSE_SERVERS="dmx kdrive xnest xorg xvfb"
+IUSE="${IUSE_SERVERS} ipv6 minimal nptl tslib +udev utouch"
+
+RDEPEND=">=app-admin/eselect-opengl-1.0.8
+ dev-libs/openssl
+ media-libs/freetype
+ >=x11-apps/iceauth-1.0.2
+ >=x11-apps/rgb-1.0.3
+ >=x11-apps/xauth-1.0.3
+ x11-apps/xkbcomp
+ >=x11-libs/libpciaccess-0.10.3
+ >=x11-libs/libXau-1.0.4
+ >=x11-libs/libXdmcp-1.0.2
+ >=x11-libs/libXfont-1.4.2
+ >=x11-libs/libxkbfile-1.0.4
+ >=x11-libs/pixman-0.21.8
+ >=x11-libs/xtrans-1.2.2
+ >=x11-misc/xbitmaps-1.0.1
+ >=x11-misc/xkeyboard-config-1.4
+ dmx? (
+ x11-libs/libXt
+ >=x11-libs/libdmx-1.0.99.1
+ >=x11-libs/libX11-1.1.5
+ >=x11-libs/libXaw-1.0.4
+ >=x11-libs/libXext-1.0.99.4
+ >=x11-libs/libXfixes-4.0.3
+ >=x11-libs/libXi-1.2.99.1
+ >=x11-libs/libXmu-1.0.3
+ >=x11-libs/libXres-1.0.3
+ >=x11-libs/libXtst-1.0.99.2
+ )
+ kdrive? (
+ >=x11-libs/libXext-1.0.5
+ x11-libs/libXv
+ )
+ !minimal? (
+ >=x11-libs/libX11-1.1.5
+ >=x11-libs/libXext-1.0.5
+ >=media-libs/mesa-7.8_rc[nptl=]
+ )
+ tslib? ( >=x11-libs/tslib-1.0 x11-proto/xcalibrateproto )
+ udev? ( >=sys-fs/udev-150 )
+ >=x11-apps/xinit-1.3"
+
+# dmx+doc DEPEND is a hack, a proper solution needs to be implemented in the
+# xorg-2.eclass for next release
+DEPEND="${RDEPEND}
+ sys-devel/flex
+ >=x11-proto/bigreqsproto-1.1.0
+ >=x11-proto/compositeproto-0.4
+ >=x11-proto/damageproto-1.1
+ >=x11-proto/fixesproto-4.1
+ >=x11-proto/fontsproto-2.0.2
+ >=x11-proto/glproto-1.4.11
+ >=x11-proto/inputproto-1.9.99.902
+ >=x11-proto/kbproto-1.0.3
+ >=x11-proto/randrproto-1.2.99.3
+ >=x11-proto/recordproto-1.13.99.1
+ >=x11-proto/renderproto-0.11
+ >=x11-proto/resourceproto-1.0.2
+ >=x11-proto/scrnsaverproto-1.1
+ >=x11-proto/trapproto-3.4.3
+ >=x11-proto/videoproto-2.2.2
+ >=x11-proto/xcmiscproto-1.2.0
+ >=x11-proto/xextproto-7.1.99
+ >=x11-proto/xf86dgaproto-2.0.99.1
+ >=x11-proto/xf86rushproto-1.1.2
+ >=x11-proto/xf86vidmodeproto-2.2.99.1
+ >=x11-proto/xineramaproto-1.1.3
+ >=x11-proto/xproto-7.0.17
+ dmx? (
+ >=x11-proto/dmxproto-2.2.99.1
+ doc? (
+ || (
+ www-client/links
+ www-client/lynx
+ www-client/w3m
+ )
+ )
+ )
+ !minimal? (
+ >=x11-proto/xf86driproto-2.1.0
+ >=x11-proto/dri2proto-2.3
+ >=x11-libs/libdrm-2.4.20
+ )"
+
+PDEPEND="
+ xorg? ( >=x11-base/xorg-drivers-$(get_version_component_range 1-2) )"
+
+REQUIRED_USE="!minimal? (
+ || ( ${IUSE_SERVERS} )
+ )"
+
+#UPSTREAMED_PATCHES=(
+# "${WORKDIR}/patches/"
+#)
+
+PATCHES=(
+ "${UPSTREAMED_PATCHES[@]}"
+ "${FILESDIR}"/${PN}-disable-acpi.patch
+ "${FILESDIR}"/${PN}-1.9-nouveau-default.patch
+ "${FILESDIR}"/xorg-cve-2011-4028+4029.patch
+ "${FILESDIR}"/xorg-server-1.10.4-r2-xi2.1.patch
+ "${FILESDIR}"/xorg-server-1.10.4-r2-xf86CoordinatesToWindow.patch
+ "${FILESDIR}"/xorg-server-1.10.4-r2-gestures-extension.patch
+ "${FILESDIR}"/xorg-server-1.10.4-r2-fix_masked_transformed_valuators.patch
+ "${FILESDIR}"/xorg-server-1.10.4-r2-fix_no_coords.patch
+ "${FILESDIR}"/xorg-server-1.10.4-r2-Xi_ensure_replayed_touch_events_have_devices.patch
+ "${FILESDIR}"/xorg-server-1.10.4-r2-Xi_ensure_touch_events_update_currentTime.patch
+ "${FILESDIR}"/xorg-server-1.10.4-r2-touch_grab_reject_send_ownership.patch
+ "${FILESDIR}"/xorg-server-1.10.4-r2-fix_touchpad_touch_event_removal.patch
+)
+
+pkg_pretend() {
+ # older gcc is not supported
+ [[ $(gcc-major-version) -lt 4 ]] && \
+ die "Sorry, but gcc earlier than 4.0 wont work for xorg-server."
+}
+
+pkg_setup() {
+ xorg-2_pkg_setup
+
+ # localstatedir is used for the log location; we need to override the default
+ # from ebuild.sh
+ # sysconfdir is used for the xorg.conf location; same applies
+ # --enable-install-setuid needed because sparcs default off
+ # NOTE: fop is used for doc generating ; and i have no idea if gentoo
+ # package it somewhere
+ XORG_CONFIGURE_OPTIONS=(
+ $(use_enable ipv6)
+ $(use_enable dmx)
+ $(use_enable kdrive)
+ $(use_enable kdrive kdrive-kbd)
+ $(use_enable kdrive kdrive-mouse)
+ $(use_enable kdrive kdrive-evdev)
+ $(use_enable tslib)
+ $(use_enable tslib xcalibrate)
+ $(use_enable !minimal record)
+ $(use_enable !minimal xfree86-utils)
+ $(use_enable !minimal install-libxf86config)
+ $(use_enable !minimal dri)
+ $(use_enable !minimal dri2)
+ $(use_enable !minimal glx)
+ $(use_enable xnest)
+ $(use_enable xorg)
+ $(use_enable xvfb)
+ $(use_enable nptl glx-tls)
+ $(use_enable utouch gestures)
+ $(use_enable udev config-udev)
+ $(use_with doc doxygen)
+ $(use_with doc xmlto)
+ --sysconfdir=/etc/X11
+ --localstatedir=/var
+ --enable-install-setuid
+ --with-fontrootdir=/usr/share/fonts
+ --with-xkb-output=/var/lib/xkb
+ --disable-config-hal
+ --without-dtrace
+ --without-fop
+ --with-os-vendor=Gentoo
+ )
+
+ # Xorg-server requires includes from OS mesa which are not visible for
+ # users of binary drivers.
+ mkdir -p "${T}/mesa-symlinks/GL"
+ for i in gl glx glxmd glxproto glxtokens; do
+ ln -s "${EROOT}usr/$(get_libdir)/opengl/xorg-x11/include/$i.h" "${T}/mesa-symlinks/GL/$i.h" || die
+ done
+ for i in glext glxext; do
+ ln -s "${EROOT}usr/$(get_libdir)/opengl/global/include/$i.h" "${T}/mesa-symlinks/GL/$i.h" || die
+ done
+ append-cppflags "-I${T}/mesa-symlinks"
+}
+
+src_install() {
+ xorg-2_src_install
+
+ dynamic_libgl_install
+
+ server_based_install
+
+ if ! use minimal && use xorg; then
+ # Install xorg.conf.example into docs
+ dodoc "${AUTOTOOLS_BUILD_DIR}"/hw/xfree86/xorg.conf.example
+ fi
+
+ newinitd "${FILESDIR}"/xdm-setup.initd-1 xdm-setup
+ newinitd "${FILESDIR}"/xdm.initd-3 xdm
+ newconfd "${FILESDIR}"/xdm.confd-3 xdm
+
+ # install the @x11-module-rebuild set for Portage
+ insinto /usr/share/portage/config/sets
+ newins "${FILESDIR}"/xorg-sets.conf xorg.conf
+}
+
+pkg_postinst() {
+ # sets up libGL and DRI2 symlinks if needed (ie, on a fresh install)
+ eselect opengl set xorg-x11 --use-old
+
+ if [[ ${PV} != 9999 && $(get_version_component_range 2 ${REPLACING_VERSIONS}) != $(get_version_component_range 2 ${PV}) ]]; then
+ elog "You should consider reading upgrade guide for this release:"
+ elog " http://www.gentoo.org/proj/en/desktop/x/x11/xorg-server-$(get_version_component_range 1-2)-upgrade-guide.xml"
+ echo
+ ewarn "You must rebuild all drivers if upgrading from <xorg-server-$(get_version_component_range 1-2)"
+ ewarn "because the ABI changed. If you cannot start X because"
+ ewarn "of module version mismatch errors, this is your problem."
+
+ echo
+ ewarn "You can generate a list of all installed packages in the x11-drivers"
+ ewarn "category using this command:"
+ ewarn " emerge portage-utils; qlist -I -C x11-drivers/"
+ ewarn "or using sets from portage-2.2:"
+ ewarn " emerge @x11-module-rebuild"
+ fi
+}
+
+pkg_postrm() {
+ # Get rid of module dir to ensure opengl-update works properly
+ if [[ -z ${REPLACED_BY_VERSION} && -e ${ROOT}/usr/$(get_libdir)/xorg/modules ]]; then
+ rm -rf "${ROOT}"/usr/$(get_libdir)/xorg/modules
+ fi
+}
+
+dynamic_libgl_install() {
+ # next section is to setup the dynamic libGL stuff
+ ebegin "Moving GL files for dynamic switching"
+ dodir /usr/$(get_libdir)/opengl/xorg-x11/extensions
+ local x=""
+ for x in "${D}"/usr/$(get_libdir)/xorg/modules/extensions/lib{glx,dri,dri2}*; do
+ if [ -f ${x} -o -L ${x} ]; then
+ mv -f ${x} "${D}"/usr/$(get_libdir)/opengl/xorg-x11/extensions
+ fi
+ done
+ eend 0
+}
+
+server_based_install() {
+ if ! use xorg; then
+ rm "${D}"/usr/share/man/man1/Xserver.1x \
+ "${D}"/usr/$(get_libdir)/xserver/SecurityPolicy \
+ "${D}"/usr/$(get_libdir)/pkgconfig/xorg-server.pc \
+ "${D}"/usr/share/man/man1/Xserver.1x
+ fi
+}