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