Xi 2.1 adds TouchClasses to devices, as well as TouchBegin, TouchMotion and TouchEnd events, to allow support for multiple touchpoints on a single device.
Based on work from both myself and Chase Douglas. Signed-off-by: Daniel Stone <[email protected]> Signed-off-by: Chase Douglas <[email protected]> --- Xi/exevents.c | 346 ++++++++++++++++++++++++++++++++++++++++ Xi/extinit.c | 9 +- Xi/xiallowev.c | 110 +++++++++++++ Xi/xiallowev.h | 2 + Xi/xipassivegrab.c | 18 ++- Xi/xiquerydevice.c | 95 +++++++++++ Xi/xiquerydevice.h | 3 + Xi/xiselectev.c | 41 +++++ configure.ac | 2 +- dix/devices.c | 93 +++++++++++ dix/eventconvert.c | 13 ++ dix/events.c | 7 +- dix/getevents.c | 113 +++++++++++++ dix/grabs.c | 55 +++++++ dix/inpututils.c | 58 +++++++ dix/window.c | 9 +- hw/xfree86/common/xf86Xinput.c | 21 +++ hw/xfree86/common/xf86Xinput.h | 4 + include/eventstr.h | 5 + include/exevents.h | 20 +++ include/input.h | 17 ++ include/inputstr.h | 118 +++++++++----- include/protocol-versions.h | 2 +- mi/mieq.c | 3 + 24 files changed, 1111 insertions(+), 53 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 327873e..c401634 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -77,6 +77,7 @@ SOFTWARE. #include "xiquerydevice.h" /* For List*Info */ #include "eventconvert.h" #include "eventstr.h" +#include "xserver-properties.h" #include <X11/extensions/XKBproto.h> #include "xkbsrv.h" @@ -926,6 +927,263 @@ ProcessRawEvent(RawDeviceEvent *ev, DeviceIntPtr device) } /** + * 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 selection + * delivery logic. + */ +static void +ProcessTouchEvent(DeviceEvent *ev, DeviceIntPtr sourcedev) +{ + TouchClassPtr t; + TouchPointInfoPtr ti; + DeviceIntPtr masterdev = NULL, deliverdev = NULL; + Window child; + WindowPtr win; + SpritePtr sprite; + xXIDeviceEvent *xi2; + Mask filter; + int err, touch, i, j, deliveries; + + /* We handle deliveries to MDs through the SD, rather than copying + * the event and processing it twice. */ + if (ev->sourceid != ev->deviceid) + return; + + if (sourcedev->u.master) + masterdev = sourcedev->u.master; + + if (!sourcedev->touch) + return; + t = sourcedev->touch; + + touch = FindTouchPoint(sourcedev, ev->detail.touch); + if (touch < 0) + { + DebugF("[Xi] %s: Received event for inactive touchpoint %d\n", + sourcedev->name, ev->detail.touch); + return; + } + ti = &t->touches[touch]; + + /* Find our window trace, or construct one if necessary. In direct touch + * mode, we focus immediately under the touchpoint, so we need to build a + * window trace; in Relative, we just use the device's sprite, or reuse + * an existing touch's sprite if possible. */ + sprite = &ti->sprite; + if (ev->type == ET_TouchBegin) + { + if (t->mode == XIDirectTouch) + { + /* XXX: Do we need to handle crossing screens here? */ + sprite->spriteTrace[0] = + sourcedev->spriteInfo->sprite->hotPhys.pScreen->root; + XYToWindow(sprite, ev->root_x, ev->root_y); + } + else + { + WindowPtr *trace; + SpritePtr srcsprite; + + for (i = 0; i < t->num_touches; i++) + if (t->touches[i].sprite.spriteTraceGood > 0) + break; + if (i < t->num_touches) + srcsprite = &t->touches[i].sprite; + else if (sourcedev->spriteInfo->sprite) + srcsprite = sourcedev->spriteInfo->sprite; + else + return; + + if (srcsprite->spriteTraceGood > sprite->spriteTraceSize) + { + trace = realloc(sprite->spriteTrace, + srcsprite->spriteTraceSize * sizeof(*trace)); + if (!trace) + { + sprite->spriteTraceGood = 0; + return; + } + sprite->spriteTrace = trace; + sprite->spriteTraceSize = srcsprite->spriteTraceGood; + } + memcpy(sprite->spriteTrace, srcsprite->spriteTrace, + srcsprite->spriteTraceGood * sizeof(*trace)); + sprite->spriteTraceGood = srcsprite->spriteTraceGood; + } + + if (sprite->spriteTraceGood <= 0) + return; + + /* Mark which grabs/selections we're delivering to: max one grab per + * window plus the bottom-most selection. */ + ti->listeners = calloc(sprite->spriteTraceGood + 1, + sizeof(*ti->listeners)); + if (!ti->listeners) + { + sprite->spriteTraceGood = 0; + return; + } + ti->num_listeners = 0; + } + else + { + if (sprite->spriteTraceGood <= 0) + return; + } + + /* If we get a TouchEnd event but someone still has an open grab, just + * flip pending_finish and wait for ownership to settle. */ + if (ev->type == ET_TouchEnd && ti->num_grabs) + { + ev->type = ET_TouchMotion; + ti->pending_finish = TRUE; + ev->flags |= XITouchPendingFinish; + } + + /* The first delivery we make will be to the owner, so set the owner flag + * here, and clear it once we've made a delivery. */ + ev->flags |= XITouchOwner; + + err = EventToXI2((InternalEvent *) ev, (xEvent **) &xi2); + if (err != Success) + { + ErrorF("[Xi] %s: XI2 conversion failed in ProcessTouchEvent (%d)\n", + sourcedev->name, err); + return; + } + filter = GetEventFilter(sourcedev, (xEvent *) xi2); + child = sprite->spriteTrace[sprite->spriteTraceGood - 1]->drawable.id; + + /* First search the stack going from root to child looking for grabs, + * delivering to every grab we find ... */ + ti->num_grabs = 0; + for (i = 0; i < sprite->spriteTraceGood; i++) + { + GrabPtr grab; + enum EventType saved_evtype = ev->type; + + win = sprite->spriteTrace[i]; + + /* Grabs can only be established on one type, so fool + * CheckPassiveGrabsOnWindow into thinking that it's a TouchBegin. */ + ev->type = ET_TouchBegin; + deliverdev = sourcedev; + grab = CheckPassiveGrabsOnWindow(win, deliverdev, ev, FALSE, FALSE); + if (!grab && masterdev) + { + deliverdev = masterdev; + grab = CheckPassiveGrabsOnWindow(win, deliverdev, ev, FALSE, FALSE); + } + ev->type = saved_evtype; + if (!grab) + continue; + xi2->deviceid = deliverdev->id; + + /* Stash the list of currently-active listeners away at TouchBegin time, + * then subsequently check against that list to make sure we only + * deliver to that same list later on, so we don't deliver TouchMotion + * events to clients which have never seen the corresponding + * TouchBegin. */ + if (ev->type != ET_TouchBegin) + { + for (j = 0; j < ti->num_listeners; j++) + { + if (ti->listeners[j] == grab->resource) + break; + } + if (j == ti->num_listeners) + continue; + } + + if (XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), win, + (xEvent *) xi2, 1) != Success) + continue; + FixUpEventFromWindow(sprite, (xEvent *) xi2, win, child, FALSE); + deliveries = TryClientEvents(rClient(grab), deliverdev, + (xEvent *) xi2, 1, filter, filter, + NullGrab); + if (deliveries > 0) + { + ti->num_grabs++; + xi2->flags &= ~XITouchOwner; + if (ev->type == ET_TouchBegin) + ti->listeners[ti->num_listeners++] = grab->resource; + } + } + + /* ... then go backwards looking for selections, but stop at the first + * one we find. */ + deliveries = 0; + while (--i >= 0) + { + int evbyte = xi2->evtype / 8; + OtherInputMasks *inputMasks; + InputClients *iclients; + + win = sprite->spriteTrace[i]; + inputMasks = wOtherInputMasks(win); + if (!inputMasks) + continue; + iclients = inputMasks->inputClients; + if (!iclients) + continue; + + FixUpEventFromWindow(sprite, (xEvent *) xi2, win, child, FALSE); + if (!(inputMasks->xi2mask[sourcedev->id][evbyte] & filter) && + !(inputMasks->xi2mask[XIAllDevices][evbyte] & filter) && + !(masterdev && + ((inputMasks->xi2mask[masterdev->id][evbyte] & filter) || + (inputMasks->xi2mask[XIAllMasterDevices][evbyte] & filter)))) + continue; + + for (; iclients; iclients = iclients->next) + { + if ((iclients->xi2mask[sourcedev->id][evbyte] & filter) || + (iclients->xi2mask[XIAllDevices][evbyte] & filter)) + deliverdev = sourcedev; + else if (masterdev && + ((iclients->xi2mask[masterdev->id][evbyte] & filter) || + (iclients->xi2mask[XIAllMasterDevices][evbyte] & filter))) + deliverdev = masterdev; + else + continue; + xi2->deviceid = deliverdev->id; + + /* See comment in grab-delivery TouchBegin branch. */ + if (ev->type != ET_TouchBegin) { + for (j = 0; j < ti->num_listeners; j++) + { + if (ti->listeners[j] == iclients->resource) + break; + } + if (j == ti->num_listeners) + continue; + } + + if (XaceHook(XACE_RECEIVE_ACCESS, rClient(iclients), win, + (xEvent *) xi2, 1) != Success) + continue; + deliveries = TryClientEvents(rClient(iclients), deliverdev, + (xEvent *) xi2, 1, filter, filter, + NullGrab); + if (ev->type == ET_TouchBegin && deliveries > 0) + ti->listeners[ti->num_listeners++] = iclients->resource; + break; + } + + if (deliveries > 0) + break; + } + + if (ev->type == ET_TouchEnd) + FinishTouchPoint(sourcedev, ev->detail.touch); + + free(xi2); +} + +/** * Main device event processing function. * Called from when processing the events from the event queue. * @@ -954,6 +1212,12 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device) { ProcessRawEvent(&ev->raw_event, device); return; + } else if (ev->any.type == ET_TouchBegin || + ev->any.type == ET_TouchMotion || + ev->any.type == ET_TouchEnd) + { + ProcessTouchEvent(&ev->device_event, device); + return; } if (IsPointerDevice(device)) @@ -1152,6 +1416,30 @@ InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int 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; + else if (ax->label == XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_Y)) + dev->touch->y_axis = axnum; +} + static void FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, ButtonClassPtr b, ValuatorClassPtr v, int first) @@ -1562,6 +1850,34 @@ GrabWindow(ClientPtr client, DeviceIntPtr dev, int type, 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, DixGrabAccess); + if (rc != Success) + return rc; + + 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) @@ -1734,6 +2050,36 @@ InputClientGone(WindowPtr pWin, XID id) 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; + } + } + } + } +} + int SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate, xEvent * ev, Mask mask, int count) diff --git a/Xi/extinit.c b/Xi/extinit.c index 546ccb4..940ef98 100644 --- a/Xi/extinit.c +++ b/Xi/extinit.c @@ -258,7 +258,8 @@ static int (*ProcIVector[])(ClientPtr) = { ProcXIChangeProperty, /* 57 */ ProcXIDeleteProperty, /* 58 */ ProcXIGetProperty, /* 59 */ - ProcXIGetSelectedEvents /* 60 */ + ProcXIGetSelectedEvents, /* 60 */ + ProcXIAllowTouchEvents, /* 61 */ }; /* For swapped clients */ @@ -323,7 +324,8 @@ static int (*SProcIVector[])(ClientPtr) = { SProcXIChangeProperty, /* 57 */ SProcXIDeleteProperty, /* 58 */ SProcXIGetProperty, /* 59 */ - SProcXIGetSelectedEvents /* 60 */ + SProcXIGetSelectedEvents, /* 60 */ + SProcXIAllowTouchEvents, /* 61 */ }; /***************************************************************** @@ -880,6 +882,9 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to) case XI_KeyRelease: case XI_ButtonPress: case XI_ButtonRelease: + case XI_TouchBegin: + case XI_TouchMotion: + case XI_TouchEnd: SDeviceEvent((xXIDeviceEvent*)from, (xXIDeviceEvent*)to); break; case XI_RawMotion: diff --git a/Xi/xiallowev.c b/Xi/xiallowev.c index 3077e1a..6b9fcc6 100644 --- a/Xi/xiallowev.c +++ b/Xi/xiallowev.c @@ -35,6 +35,8 @@ #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> @@ -101,3 +103,111 @@ ProcXIAllowEvents(ClientPtr client) 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; + TouchPointInfoPtr ti; + int ret, touch, i, nev; + ValuatorMask *mask = valuator_mask_new(0); + EventList *events = InitEventList(GetMaximumEventsNum()); + DeviceEvent *ev; + + REQUEST(xXIAllowTouchEventsReq); + REQUEST_SIZE_MATCH(xXIAllowTouchEventsReq); + + if (!mask || !events) + return BadAlloc; + + ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); + if (ret != Success) + return ret; + if (!dev->touch) + { + client->errorValue = stuff->deviceid; + return BadDevice; + } + + touch = FindTouchPoint(dev, stuff->touchid); + if (touch < 0) + { + client->errorValue = touch; + return BadValue; + } + ti = &dev->touch->touches[touch]; + + if (ti->num_listeners == 0 || + CLIENT_ID(ti->listeners[0]) != client->index) + return BadAccess; + + if (stuff->mode & XITouchOwnerAccept) + { + ProcessInputEvents(); + + if (stuff->mode & ~(XITouchOwnerAccept | XITouchNoPointerEmulation)) + { + client->errorValue = stuff->mode; + return BadValue; + } + + if (stuff->mode & XITouchNoPointerEmulation) + ti->emulate_pointer = FALSE; + + /* XXX: Should probably take flags in GetTouchEvents. */ + nev = GetTouchEvents(events, dev, stuff->touchid, mask, 0); + if (nev == 0) + return BadAlloc; + for (i = 0; i < nev; i++) + { + ev = (DeviceEvent *)((events + i)->event); + if (ev->type == ET_TouchMotion) + ev->flags |= XITouchOwnerAccepted; + mieqProcessDeviceEvent(dev, (InternalEvent *) ev, NULL); + } + + ti->num_listeners = 1; + } + else if (stuff->mode & XITouchOwnerReject) + { + if (stuff->mode & ~XITouchOwnerReject) + { + client->errorValue = stuff->mode; + return BadValue; + } + + for (i = 0; i < ti->num_listeners - 1; i++) + ti->listeners[i] = ti->listeners[i + 1]; + ti->num_listeners--; + + ProcessInputEvents(); + nev = GetTouchEvents(events, dev, stuff->touchid, mask, 0); + if (nev == 0) + return BadAlloc; + for (i = 0; i < nev; i++) + { + ev = (DeviceEvent *)((events + i)->event); + mieqProcessDeviceEvent(dev, (InternalEvent *) ev, NULL); + } + } + else + { + client->errorValue = stuff->mode; + return BadValue; + } + + return Success; +} diff --git a/Xi/xiallowev.h b/Xi/xiallowev.h index 3a417b9..ca45ee3 100644 --- a/Xi/xiallowev.h +++ b/Xi/xiallowev.h @@ -32,5 +32,7 @@ int ProcXIAllowEvents(ClientPtr client); int SProcXIAllowEvents(ClientPtr client); +int ProcXIAllowTouchEvents(ClientPtr client); +int SProcXIAllowTouchEvents(ClientPtr client); #endif /* XIALLOWEV_H */ diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c index 2966145..c5f7bf0 100644 --- a/Xi/xipassivegrab.c +++ b/Xi/xipassivegrab.c @@ -105,19 +105,30 @@ ProcXIPassiveGrabDevice(ClientPtr client) 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((unsigned char*)&stuff[1], stuff->mask_len * 4) != Success) return BadValue; @@ -185,6 +196,9 @@ ProcXIPassiveGrabDevice(ClientPtr client) status = GrabWindow(client, dev, stuff->grab_type, ¶m, &mask); break; + case XIGrabtypeTouchBegin: + status = GrabTouch(client, dev, mod_dev, ¶m, &mask); + break; } if (status != GrabSuccess) diff --git a/Xi/xiquerydevice.c b/Xi/xiquerydevice.c index fdd2c05..947cd8d 100644 --- a/Xi/xiquerydevice.c +++ b/Xi/xiquerydevice.c @@ -232,6 +232,12 @@ SizeDeviceClasses(DeviceIntPtr dev) if (dev->valuator) len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; + if (dev->touch) + { + len += sizeof(xXITouchInfo); + len += sizeof(xXITouchValuatorInfo) * dev->touch->num_axes; + } + return len; } @@ -373,6 +379,73 @@ SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info) 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; @@ -462,6 +535,22 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev, 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; } @@ -489,6 +578,12 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) case XIValuatorClass: SwapValuatorInfo(dev, (xXIValuatorInfo*)any); break; + case XITouchClass: + SwapTouchInfo(dev, (xXITouchInfo*)any); + break; + case XITouchValuatorClass: + SwapTouchValuatorInfo(dev, (xXITouchValuatorInfo*)any); + break; } any += len * 4; diff --git a/Xi/xiquerydevice.h b/Xi/xiquerydevice.h index 02f0659..59326f7 100644 --- a/Xi/xiquerydevice.h +++ b/Xi/xiquerydevice.h @@ -44,4 +44,7 @@ int ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info, Bool reportState); 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 */ diff --git a/Xi/xiselectev.c b/Xi/xiselectev.c index 7aa3f0a..64ee173 100644 --- a/Xi/xiselectev.c +++ b/Xi/xiselectev.c @@ -141,6 +141,47 @@ ProcXISelectEvents(ClientPtr client) return BadValue; } + if (evmask->mask_len >= 1) + { + unsigned char *bits = (unsigned char*)&evmask[1]; + + /* All three touch events must be selected at once */ + if ((BitIsOn(bits, XI_TouchBegin) || + BitIsOn(bits, XI_TouchMotion) || + BitIsOn(bits, XI_TouchEnd)) && + (!BitIsOn(bits, XI_TouchBegin) || + !BitIsOn(bits, XI_TouchMotion) || + !BitIsOn(bits, XI_TouchEnd))) + { + 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 client 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((unsigned char*)&evmask[1], evmask->mask_len * 4) != Success) return BadValue; diff --git a/configure.ac b/configure.ac index a5967ad..532412d 100644 --- a/configure.ac +++ b/configure.ac @@ -783,7 +783,7 @@ WINDOWSWMPROTO="windowswmproto" APPLEWMPROTO="applewmproto >= 1.4" dnl Core modules for most extensions, et al. -SDK_REQUIRED_MODULES="[xproto >= 7.0.17] [randrproto >= 1.4] [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.4] [renderproto >= 0.11] [xextproto >= 7.1.99] [inputproto >= 2.0.99.1] [kbproto >= 1.0.3] fontsproto" # Make SDK_REQUIRED_MODULES available for inclusion in xorg-server.pc AC_SUBST(SDK_REQUIRED_MODULES) diff --git a/dix/devices.c b/dix/devices.c index 6c0dc42..c532db8 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -754,6 +754,20 @@ FreeDeviceClass(int type, pointer *class) 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].listeners); + } + + free((*t)); + break; + } case FocusClass: { FocusClassPtr *f = (FocusClassPtr*)class; @@ -862,6 +876,7 @@ FreeAllDeviceClasses(ClassesPtr classes) 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); @@ -1543,6 +1558,84 @@ InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, Atom* btn_ InitPtrFeedbackClassDeviceStruct(dev, controlProc)); } +/** + * 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 *valuators; + int i; + + if (device->touch) + return FALSE; + + if ((mode != XIDirectTouch && mode != XIDependentTouch) || + max_touches == 0 || num_axes < 2) + return FALSE; + + if (num_axes > MAX_VALUATORS) + { + LogMessage(X_WARNING, + "Device '%s' has %d axes, only using first %d.\n", + device->name, num_axes, MAX_VALUATORS); + num_axes = MAX_VALUATORS; + } + + touch = calloc(1, + sizeof(TouchClassRec) + + num_axes * sizeof(TouchAxisInfoRec) + + max_touches * sizeof(TouchPointInfoRec) + + max_touches * num_axes * sizeof(int)); + if (!touch) + return FALSE; + + touch->axes = (TouchAxisInfoPtr)(touch + 1); + touch->touches = (TouchPointInfoPtr)(touch->axes + num_axes); + + valuators = (int *)(touch->touches + max_touches); + for (i = 0; i < max_touches; i++) + { + touch->touches[i].valuators = valuators; + valuators += num_axes; + } + + for (i = 0; i < max_touches; i++) + { + SpritePtr sprite = &touch->touches[i].sprite; + + sprite->spriteTrace = calloc(32, sizeof(*sprite->spriteTrace)); + if (!sprite->spriteTrace) + { + free(touch); + return FALSE; + } + sprite->spriteTraceSize = 32; + sprite->spriteTrace[0] = screenInfo.screens[0]->root; + sprite->hot.pScreen = screenInfo.screens[0]; + sprite->hotPhys.pScreen = screenInfo.screens[0]; + + touch->touches[i].id = -1; + } + + touch->num_axes = num_axes; + touch->num_touches = max_touches; + touch->mode = mode; + touch->last_touchid = (unsigned int) -1; + touch->x_axis = -1; + touch->y_axis = -1; + + device->touch = touch; + + return TRUE; +} + /* * Check if the given buffer contains elements between low (inclusive) and * high (inclusive) only. diff --git a/dix/eventconvert.c b/dix/eventconvert.c index 7b894f0..75a00ac 100644 --- a/dix/eventconvert.c +++ b/dix/eventconvert.c @@ -139,6 +139,9 @@ EventToCore(InternalEvent *event, xEvent *core) case ET_RawButtonPress: case ET_RawButtonRelease: case ET_RawMotion: + case ET_TouchBegin: + case ET_TouchEnd: + case ET_TouchMotion: return BadMatch; default: /* XXX: */ @@ -184,6 +187,9 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count) case ET_RawButtonPress: case ET_RawButtonRelease: case ET_RawMotion: + case ET_TouchBegin: + case ET_TouchEnd: + case ET_TouchMotion: *count = 0; *xi = NULL; return BadMatch; @@ -225,6 +231,9 @@ EventToXI2(InternalEvent *ev, xEvent **xi) case ET_ButtonRelease: case ET_KeyPress: case ET_KeyRelease: + case ET_TouchBegin: + case ET_TouchMotion: + case ET_TouchEnd: return eventToDeviceEvent(&ev->device_event, xi); case ET_ProximityIn: case ET_ProximityOut: @@ -575,6 +584,7 @@ eventToDeviceEvent(DeviceEvent *ev, xEvent **xi) xde->sourceid = ev->sourceid; 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; @@ -727,6 +737,9 @@ GetXI2Type(InternalEvent *event) 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_TouchMotion; break; default: break; } diff --git a/dix/events.c b/dix/events.c index 77e76ac..106e024 100644 --- a/dix/events.c +++ b/dix/events.c @@ -435,7 +435,7 @@ GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev) (inputMasks->xi2mask[XIAllMasterDevices][evtype/8] && IsMaster(dev))); } -static Mask +Mask GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients* other) { /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */ @@ -1277,6 +1277,7 @@ ComputeFreezes(void) if (replayDev) { DeviceEvent* event = replayDev->deviceGrab.sync.event; + SpritePtr pSprite = replayDev->spriteInfo->sprite; syncEvents.replayDev = (DeviceIntPtr)NULL; @@ -3415,9 +3416,9 @@ CheckPassiveGrabsOnWindow( tempGrab.detail.exact = event->detail.key; if (!match) { - tempGrab.type = GetXIType((InternalEvent*)event); tempGrab.grabtype = GRABTYPE_XI; - if (GrabMatchesSecond(&tempGrab, grab, FALSE)) + if ((tempGrab.type = GetXIType((InternalEvent*)event)) && + (GrabMatchesSecond(&tempGrab, grab, FALSE))) match = XI_MATCH; } diff --git a/dix/getevents.c b/dix/getevents.c index 794df42..75ec34b 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -47,6 +47,7 @@ #include "eventstr.h" #include "eventconvert.h" #include "inpututils.h" +#include "windowstr.h" #include <X11/extensions/XKBproto.h> #include "xkbsrv.h" @@ -1287,6 +1288,118 @@ GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type, const Valuato } /** + * 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, unsigned int touchid, + const ValuatorMask *mask_in, Bool end) +{ + int x, y; /* in screen co-ord space */ + float x_frac = 0.0, y_frac = 0.0; /* as above */ + DeviceEvent *event; + ValuatorMask mask; + int touch, i; + TouchClassPtr t = pDev->touch; + ScreenPtr scr = pDev->spriteInfo->sprite->hotPhys.pScreen; + CARD32 ms = GetTimeInMillis(); + + if (!pDev->enabled) + return 0; + + if (!t) + return 0; + + if (t->x_axis < 0 || t->y_axis < 0) + return 0; + + event = (DeviceEvent *)events->event; + init_event(pDev, event, ms); + + touch = FindTouchPoint(pDev, touchid); + if (touch < 0) { + /* We obviously can't finish a non-existent touch. */ + if (end) + return 0; + + /* 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)) + return 0; + + /* Touch IDs must increase monotonically. + * XXX: Deal with this so the drivers don't have to. */ + if (touchid - t->last_touchid > INT_MAX) { + LogMessage(X_WARNING, "[dix] %s: New touch ID %d going backwards, " + "dropping touch.\n", pDev->name, touchid); + return 0; + } + + touch = CreateTouchPoint(pDev, touchid); + if (touch < 0) + return 0; + + event->type = ET_TouchBegin; + t->last_touchid = touchid; + } + else if (end) { + event->type = ET_TouchEnd; + } + else { + event->type = ET_TouchMotion; + } + + 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 = t->touches[touch].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 = t->touches[touch].valuators[t->y_axis]; + y = rescaleValuatorAxis(y, 0.0, &y_frac, + (AxisInfoPtr)(t->axes + t->y_axis), + NULL, scr->height); + } + else { + x = pDev->spriteInfo->sprite->hotPhys.x; + y = pDev->spriteInfo->sprite->hotPhys.y; + } + + event->root = scr->root->drawable.id; + event->root_x = x; + event->root_y = y; + event->root_x_frac = x_frac; + event->root_y_frac = y_frac; + event->detail.touch = touchid; + + set_valuators(pDev, event, &mask); + for (i = 0; i < t->num_axes; i++) + { + if (valuator_mask_isset(&mask, i)) + t->touches[touch].valuators[i] = valuator_mask_get(&mask, i); + } + + return 1; +} + +/** * Synthesize a single motion event for the core pointer. * * Used in cursor functions, e.g. when cursor confinement changes, and we need diff --git a/dix/grabs.c b/dix/grabs.c index 69c58df..49e51f0 100644 --- a/dix/grabs.c +++ b/dix/grabs.c @@ -60,6 +60,7 @@ SOFTWARE. #include "dixgrabs.h" #include "xace.h" #include "exevents.h" +#include "mi.h" #define BITMASK(i) (((Mask)1) << ((i) & 31)) #define MASKIDX(i) ((i) >> 5) @@ -114,9 +115,63 @@ CreateGrab( } +/* As touch grabs don't turn into active grabs with their own resources, we + * need to walk all the touches and remove this grab from any delivery + * lists. */ +static void +FreeTouchGrab(GrabPtr pGrab) +{ + TouchPointInfoPtr ti; + DeviceIntPtr dev; + InternalEvent *ev; + ValuatorMask *mask = valuator_mask_new(0); /* XXX use a static */ + EventList *events = InitEventList(GetMaximumEventsNum()); + int i, j, nev; + + if (!mask || !events) + FatalError("FreeTouchGrab: couldn't allocate valuator_mask/events\n"); + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!dev->touch) + continue; + + for (i = 0; i < dev->touch->num_touches; i++) + { + ti = &dev->touch->touches[i]; + for (j = 0; j < ti->num_listeners; j++) + { + if (ti->listeners[j] != pGrab->resource) + continue; + + while (j < ti->num_listeners - 1) + { + ti->listeners[j] = ti->listeners[j + 1]; + break; + } + ti->num_listeners--; + ti->num_grabs--; + + ProcessInputEvents(); + nev = GetTouchEvents(events, dev, ti->id, mask, 0); + for (j = 0; j < nev; j++) + { + ev = (InternalEvent *)((events + j)->event); + mieqProcessDeviceEvent(dev, ev, NULL); + } + + break; + } + } + } +} + static void FreeGrab(GrabPtr pGrab) { + if (pGrab->grabtype == GRABTYPE_XI2 && pGrab->type == XI_TouchBegin) + FreeTouchGrab(pGrab); + free(pGrab->modifiersDetail.pMask); free(pGrab->detail.pMask); diff --git a/dix/inpututils.c b/dix/inpututils.c index 2877804..13e8131 100644 --- a/dix/inpututils.c +++ b/dix/inpututils.c @@ -548,3 +548,61 @@ CountBits(const uint8_t *mask, int len) return ret; } + +int +FindTouchPoint(DeviceIntPtr dev, unsigned int touchid) +{ + int i; + TouchClassPtr t = dev->touch; + + if (!t) + return -1; + + for (i = 0; i < t->num_touches; i++) + if (t->touches[i].active && t->touches[i].id == touchid) + return i; + + return -1; +} + +int +CreateTouchPoint(DeviceIntPtr dev, unsigned int touchid) +{ + int i; + TouchClassPtr t = dev->touch; + + if (!t) + return -1; + + if (FindTouchPoint(dev, touchid) >= 0) + return -1; + + for (i = 0; i < t->num_touches; i++) + if (!t->touches[i].active) { + t->touches[i].active = TRUE; + t->touches[i].id = touchid; + return i; + } + + return -1; +} + +void +FinishTouchPoint(DeviceIntPtr dev, unsigned int touchid) +{ + int touch = FindTouchPoint(dev, touchid); + TouchPointInfoPtr ti; + + if (touch < 0) + return; + + ti = &dev->touch->touches[touch]; + + ti->active = FALSE; + ti->pending_finish = FALSE; + ti->num_grabs = 0; + ti->sprite.spriteTraceGood = 0; + free(ti->listeners); + ti->listeners = NULL; + ti->num_listeners = 0; +} diff --git a/dix/window.c b/dix/window.c index d140dda..ede9858 100644 --- a/dix/window.c +++ b/dix/window.c @@ -110,6 +110,7 @@ Equipment Corporation. #include "windowstr.h" #include "input.h" #include "inputstr.h" +#include "exevents.h" #include "resource.h" #include "colormapst.h" #include "cursorstr.h" @@ -2869,8 +2870,10 @@ UnmapWindow(WindowPtr pWin, Bool fromConfigure) if (!fromConfigure && pScreen->PostValidateTree) (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap); } - if (wasRealized && !fromConfigure) + if (wasRealized && !fromConfigure) { WindowsRestructured (); + WindowGone(pWin); + } return Success; } @@ -2953,8 +2956,10 @@ UnmapSubwindows(WindowPtr pWin) if (anyMarked && pScreen->PostValidateTree) (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap); } - if (wasRealized) + if (wasRealized) { WindowsRestructured (); + WindowGone(pWin); + } } diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index b9006ab..29166ad 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -1345,6 +1345,16 @@ xf86InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, 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(). @@ -1396,4 +1406,15 @@ xf86EnableDevice(DeviceIntPtr dev) EnableDevice(dev, TRUE); } +void +xf86PostTouchEvent(DeviceIntPtr dev, unsigned int touchid, + const ValuatorMask *mask, int end) +{ + int i, nevents; + + nevents = GetTouchEvents(xf86Events, dev, touchid, mask, end); + for (i = 0; i < nevents; i++) + mieqEnqueue(dev, (InternalEvent *)((xf86Events + i)->event)); +} + /* end of xf86Xinput.c */ diff --git a/hw/xfree86/common/xf86Xinput.h b/hw/xfree86/common/xf86Xinput.h index 1b0b16f..35dcfdf 100644 --- a/hw/xfree86/common/xf86Xinput.h +++ b/hw/xfree86/common/xf86Xinput.h @@ -141,6 +141,8 @@ extern _X_EXPORT void xf86PostKeyEventP(DeviceIntPtr device, unsigned int key_co const int *valuators); extern _X_EXPORT void xf86PostKeyboardEvent(DeviceIntPtr device, unsigned int key_code, int is_down); +extern _X_EXPORT void xf86PostTouchEvent(DeviceIntPtr dev, unsigned int touchid, + const ValuatorMask *mask, int end); 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 +150,8 @@ extern _X_EXPORT void xf86ProcessCommonOptions(InputInfoPtr pInfo, pointer optio 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); diff --git a/include/eventstr.h b/include/eventstr.h index 377cceb..1766c1b 100644 --- a/include/eventstr.h +++ b/include/eventstr.h @@ -65,6 +65,9 @@ enum EventType { ET_RawButtonRelease, ET_RawMotion, ET_XQuartz, + ET_TouchBegin, + ET_TouchEnd, + ET_TouchMotion, ET_Internal = 0xFF /* First byte */ }; @@ -90,6 +93,7 @@ struct _DeviceEvent union { uint32_t button; /**< Button number */ uint32_t key; /**< Key code */ + uint32_t touch; /**< Touch 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,6 +121,7 @@ struct _DeviceEvent 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 pass into the generated event */ }; diff --git a/include/exevents.h b/include/exevents.h index bfee385..ae45054 100644 --- a/include/exevents.h +++ b/include/exevents.h @@ -51,6 +51,14 @@ extern _X_EXPORT void InitValuatorAxisStruct( 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 @@ GrabWindow( 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 @@ InputClientGone( WindowPtr /* pWin */, XID /* id */); +extern void +WindowGone( + WindowPtr /* win */); + extern int SendEvent ( ClientPtr /* client */, diff --git a/include/input.h b/include/input.h index c1db544..cddef91 100644 --- a/include/input.h +++ b/include/input.h @@ -314,6 +314,12 @@ extern _X_EXPORT Bool InitAbsoluteClassDeviceStruct( 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*/, @@ -463,6 +469,13 @@ extern int GetKeyboardValuatorEvents( int key_code, const ValuatorMask *mask); +extern int GetTouchEvents( + EventListPtr events, + DeviceIntPtr pDev, + unsigned int touchid, + const ValuatorMask *mask, + int end); + extern int GetProximityEvents( EventListPtr events, DeviceIntPtr pDev, @@ -524,8 +537,12 @@ extern DeviceIntPtr GetXTestDevice(DeviceIntPtr master); extern void SendDevicePresenceEvent(int deviceid, int type); extern _X_EXPORT InputAttributes *DuplicateInputAttributes(InputAttributes *attrs); extern _X_EXPORT void FreeInputAttributes(InputAttributes *attrs); +extern int CreateTouchPoint(DeviceIntPtr dev, unsigned int touchid); +extern int FindTouchPoint(DeviceIntPtr dev, unsigned int touchid); +extern void FinishTouchPoint(DeviceIntPtr dev, unsigned int touchid); /* misc event helpers */ +extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients); extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event); extern Mask GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev); void FixUpEventFromWindow(SpritePtr pSprite, diff --git a/include/inputstr.h b/include/inputstr.h index 264d715..8931598 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -49,6 +49,8 @@ SOFTWARE. #ifndef INPUTSTRUCT_H #define INPUTSTRUCT_H +#include <X11/extensions/XI2proto.h> + #include <pixman.h> #include "input.h" #include "window.h" @@ -71,7 +73,7 @@ extern _X_EXPORT int CountBits(const uint8_t *mask, int len); * 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_TouchMotion #define XI2MASKSIZE ((XI2LASTEVENT + 7)/8) /* no of bits for masks */ /** @@ -203,6 +205,47 @@ typedef struct _GrabRec { unsigned char xi2mask[EMASKSIZE][XI2MASKSIZE]; } GrabRec; +/** + * Sprite information for a device. + */ +typedef struct _SpriteRec { + CursorPtr current; + BoxRec hotLimits; /* logical constraints of hot spot */ + Bool confined; /* confined to screen */ + RegionPtr hotShape; /* additional logical shape constraint */ + BoxRec physLimits; /* physical constraints of hot spot */ + WindowPtr win; /* window of logical position */ + HotSpot hot; /* logical pointer position */ + HotSpot hotPhys; /* physical pointer position */ +#ifdef PANORAMIX + ScreenPtr screen; /* all others are in Screen 0 coordinates */ + RegionRec Reg1; /* Region 1 for confining motion */ + RegionRec Reg2; /* Region 2 for confining virtual motion */ + WindowPtr windows[MAXSCREENS]; + WindowPtr confineWin; /* confine window */ +#endif + /* The window trace information is used at dix/events.c to avoid having + * to compute all the windows between the root and the current pointer + * window each time a button or key goes down. The grabs on each of those + * windows must be checked. + * spriteTraces should only be used at dix/events.c! */ + WindowPtr *spriteTrace; + int spriteTraceSize; + int spriteTraceGood; + + /* Due to delays between event generation and event processing, it is + * possible that the pointer has crossed screen boundaries between the + * time in which it begins generating events and the time when + * those events are processed. + * + * pEnqueueScreen: screen the pointer was on when the event was generated + * pDequeueScreen: screen the pointer was on when the event is processed + */ + ScreenPtr pEnqueueScreen; + ScreenPtr pDequeueScreen; + +} SpriteRec; + typedef struct _KeyClassRec { int sourceid; CARD8 down[DOWN_LENGTH]; @@ -243,6 +286,36 @@ typedef struct _ValuatorClassRec { ValuatorAccelerationRec accelScheme; } ValuatorClassRec, *ValuatorClassPtr; +typedef struct _TouchPointInfo { + Bool active; + Bool pending_finish; + uint32_t id; + SpriteRec sprite; + int *valuators; + XID *listeners; + int num_listeners; + int num_grabs; + Bool emulate_pointer; +} TouchPointInfoRec, *TouchPointInfoPtr; + +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; + CARD8 mode; + unsigned int last_touchid; + int x_axis; + int y_axis; +} TouchClassRec, *TouchClassPtr; + typedef struct _ButtonClassRec { int sourceid; CARD8 numButtons; @@ -347,6 +420,7 @@ typedef struct _LedFeedbackClassRec { typedef struct _ClassesRec { KeyClassPtr key; ValuatorClassPtr valuator; + TouchClassPtr touch; ButtonClassPtr button; FocusClassPtr focus; ProximityClassPtr proximity; @@ -360,47 +434,6 @@ typedef struct _ClassesRec { } ClassesRec; -/** - * Sprite information for a device. - */ -typedef struct _SpriteRec { - CursorPtr current; - BoxRec hotLimits; /* logical constraints of hot spot */ - Bool confined; /* confined to screen */ - RegionPtr hotShape; /* additional logical shape constraint */ - BoxRec physLimits; /* physical constraints of hot spot */ - WindowPtr win; /* window of logical position */ - HotSpot hot; /* logical pointer position */ - HotSpot hotPhys; /* physical pointer position */ -#ifdef PANORAMIX - ScreenPtr screen; /* all others are in Screen 0 coordinates */ - RegionRec Reg1; /* Region 1 for confining motion */ - RegionRec Reg2; /* Region 2 for confining virtual motion */ - WindowPtr windows[MAXSCREENS]; - WindowPtr confineWin; /* confine window */ -#endif - /* The window trace information is used at dix/events.c to avoid having - * to compute all the windows between the root and the current pointer - * window each time a button or key goes down. The grabs on each of those - * windows must be checked. - * spriteTraces should only be used at dix/events.c! */ - WindowPtr *spriteTrace; - int spriteTraceSize; - int spriteTraceGood; - - /* Due to delays between event generation and event processing, it is - * possible that the pointer has crossed screen boundaries between the - * time in which it begins generating events and the time when - * those events are processed. - * - * pEnqueueScreen: screen the pointer was on when the event was generated - * pDequeueScreen: screen the pointer was on when the event is processed - */ - ScreenPtr pEnqueueScreen; - ScreenPtr pDequeueScreen; - -} SpriteRec; - /* Device properties */ typedef struct _XIPropertyValue { @@ -512,6 +545,7 @@ typedef struct _DeviceIntRec { int id; KeyClassPtr key; ValuatorClassPtr valuator; + TouchClassPtr touch; ButtonClassPtr button; FocusClassPtr focus; ProximityClassPtr proximity; diff --git a/include/protocol-versions.h b/include/protocol-versions.h index c8c7f5f..42b7d0e 100644 --- a/include/protocol-versions.h +++ b/include/protocol-versions.h @@ -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 diff --git a/mi/mieq.c b/mi/mieq.c index 01da52a..42aec2c 100644 --- a/mi/mieq.c +++ b/mi/mieq.c @@ -269,6 +269,9 @@ ChangeDeviceID(DeviceIntPtr dev, InternalEvent* event) case ET_ProximityOut: case ET_Hierarchy: case ET_DeviceChanged: + case ET_TouchBegin: + case ET_TouchEnd: + case ET_TouchMotion: event->device_event.deviceid = dev->id; break; #if XFreeXDGA -- 1.7.2.3 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
