diff options
-rw-r--r-- | dix/touch.c | 68 | ||||
-rw-r--r-- | test/touch.c | 51 |
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(); |