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