[PATCH xserver 3/3] Input: Add initial multitouch support from Xi 2.1
Daniel Stone
daniel at fooishbar.org
Sun Sep 19 22:03:06 PDT 2010
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. This is a full implementation of the Xi 2.1 additions.
Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
Xext/geext.c | 2 -
Xext/security.c | 2 -
Xi/exevents.c | 423 ++++++++++++++++++++++++++++++++++++++++
Xi/extinit.c | 65 ++++++
Xi/xiallowev.c | 38 +++-
Xi/xipassivegrab.c | 11 +-
Xi/xiquerydevice.c | 125 ++++++++++++
Xi/xiquerydevice.h | 2 +
Xi/xiselectev.c | 21 ++
configure.ac | 2 +-
dix/devices.c | 56 ++++++
dix/eventconvert.c | 67 +++++++
dix/events.c | 42 +++--
dix/getevents.c | 154 +++++++++++++++
dix/inpututils.c | 64 ++++++
hw/xfree86/common/xf86Xinput.c | 26 +++
hw/xfree86/common/xf86Xinput.h | 14 ++
include/dix.h | 7 +
include/events.h | 2 +
include/eventstr.h | 42 ++++
include/exevents.h | 9 +
include/input.h | 40 ++++
include/inputstr.h | 39 ++++-
include/protocol-versions.h | 2 +-
mi/mieq.c | 10 +
25 files changed, 1238 insertions(+), 27 deletions(-)
diff --git a/Xext/geext.c b/Xext/geext.c
index 8319c92..b37c1a0 100644
--- a/Xext/geext.c
+++ b/Xext/geext.c
@@ -33,8 +33,6 @@
#include "geext.h"
#include "protocol-versions.h"
-#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
-
DevPrivateKeyRec GEClientPrivateKeyRec;
int RT_GECLIENT = 0;
diff --git a/Xext/security.c b/Xext/security.c
index 7eb95de..8673880 100644
--- a/Xext/security.c
+++ b/Xext/security.c
@@ -154,8 +154,6 @@ SecurityLookupRequestName(ClientPtr client)
}
-#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
-
/* SecurityDeleteAuthorization
*
* Arguments:
diff --git a/Xi/exevents.c b/Xi/exevents.c
index 1f02cb0..038b7dc 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -87,6 +87,7 @@ SOFTWARE.
Mod3Mask | Mod4Mask | Mod5Mask )
#define AllButtonsMask ( \
Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )
+#define RootWindow(dev) dev->spriteInfo->sprite->spriteTrace[0]
Bool ShouldFreeInputMasks(WindowPtr /* pWin */ ,
Bool /* ignoreSelectedEvents */
@@ -572,6 +573,49 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
to->valuator = NULL;
}
+ if (from->touch)
+ {
+ TouchClassPtr t;
+ int i;
+
+ if (!to->touch)
+ {
+ classes = to->unused_classes;
+ to->touch = classes->touch;
+ if (to->touch)
+ classes->touch = NULL;
+ }
+
+ to->touch = realloc(to->touch,
+ sizeof(*to->touch) +
+ (from->touch->num_touches *
+ sizeof(*from->touch->touches)));
+ t = to->touch;
+ if (!t)
+ FatalError("[Xi] no memory for class shift.\n");
+
+ t->min_x = from->touch->min_x;
+ t->max_x = from->touch->max_x;
+ t->min_y = from->touch->min_y;
+ t->max_y = from->touch->max_y;
+ t->min_touch_width = from->touch->min_touch_width;
+ t->max_touch_width = from->touch->max_touch_width;
+ t->max_touches = from->touch->max_touches;
+ t->num_touches = from->touch->num_touches;
+ t->touches = (TouchInfoPtr) &t[1];
+ memcpy(t->touches, from->touch->touches,
+ t->num_touches * sizeof(*t->touches));
+ for (i = 0; i < t->num_touches; i++)
+ t->touches[i].sourceid = from->id;
+ }
+ else if (to->touch && !from->touch)
+ {
+ ClassesPtr classes;
+ classes = to->unused_classes;
+ classes->touch = to->touch;
+ to->touch = NULL;
+ }
+
if (from->button)
{
if (!to->button)
@@ -931,6 +975,340 @@ ProcessRawEvent(RawDeviceEvent *ev, DeviceIntPtr device)
}
}
+static Bool
+CheckTouchQueueSize(TouchInfoPtr touch)
+{
+ InternalEvent *tmp;
+
+ if (touch->num_frozen_events < touch->size_frozen_events)
+ return TRUE;
+
+ touch->size_frozen_events += 10;
+ tmp = realloc(touch->frozen_events,
+ touch->size_frozen_events * sizeof(InternalEvent));
+ if (!tmp)
+ {
+ touch->size_frozen_events -= 10;
+ return FALSE;
+ }
+ touch->frozen_events = tmp;
+
+ return TRUE;
+}
+
+static void
+ProcessTouchMotionEvent(TouchMotionEvent *ev, DeviceIntPtr device)
+{
+ TouchInfoPtr touch = FindTouchPoint(device, ev->touchid);
+ xEvent *xi2;
+ int ret;
+ WindowPtr win;
+
+ if (!touch)
+ {
+ DebugF("[Xi] %s: Received TouchMotion event for dead touchpoint %d\n",
+ device->name, ev->touchid);
+ return;
+ }
+
+ /* If the touch is currently frozen, add it to the queue if possible or
+ * drop the event if not, then get out. */
+ if (touch->frozen)
+ {
+ if (CheckTouchQueueSize(touch))
+ touch->frozen_events[touch->num_frozen_events++] =
+ *(InternalEvent*)ev;
+ return;
+ }
+
+ if (ev->mask & XITouchXMask)
+ touch->last_x = ev->x;
+ if (ev->mask & XITouchYMask)
+ touch->last_y = ev->y;
+ if (ev->mask & XITouchTouchSizeMask)
+ {
+ touch->last_touch_major = ev->touch_width_major;
+ touch->last_touch_minor = ev->touch_width_minor;
+ }
+ if (ev->mask & XITouchToolSizeMask)
+ {
+ touch->last_tool_major = ev->tool_width_major;
+ touch->last_tool_minor = ev->tool_width_minor;
+ }
+ if (ev->mask & XITouchOrientationMask)
+ touch->last_orientation = ev->orientation;
+
+ ret = EventToXI2((InternalEvent *) ev, &xi2);
+ if (ret != Success)
+ {
+ ErrorF("[Xi] %s: XI2 conversion failed in ProcessTouchMotionEvent (%d)\n",
+ device->name, ret);
+ return;
+ }
+
+ if (dixLookupWindow(&win, touch->win, clients[touch->client_id],
+ DixReadAccess) == Success)
+ FixUpEventFromWindow(device, xi2, win, None, TRUE);
+
+ TryClientEvents(clients[touch->client_id], device, xi2, 1,
+ 0, NoEventMask, NULL);
+
+ free(xi2);
+}
+
+static void
+ProcessTouchEndEvent(TouchStateEvent *ev, DeviceIntPtr device)
+{
+ TouchInfoPtr touch = FindTouchPoint(device, ev->touchid);
+ xEvent *xi2;
+ int err;
+
+ if (!touch)
+ {
+ DebugF("[Xi] %s: Received TouchFini for dead touchpoint %d\n",
+ device->name, ev->touchid);
+ return;
+ }
+
+ /* If the touch is currently frozen, add it to the queue; if we can't
+ * enlarge the queue to fit TouchEnd, then just stomp a motion event. */
+ if (touch->frozen)
+ {
+ if (CheckTouchQueueSize(touch))
+ touch->num_frozen_events++;
+ touch->frozen_events[touch->num_frozen_events] = *(InternalEvent*)ev;
+ return;
+ }
+
+ err = EventToXI2((InternalEvent *) ev, &xi2);
+ if (err != Success)
+ {
+ ErrorF("[Xi] %s: XI2 conversion failed in ProcessTouchEnd (%d)\n",
+ device->name, err);
+ return;
+ }
+
+ TryClientEvents(clients[touch->client_id], device, xi2, 1,
+ 0, NoEventMask, NULL);
+ FinishTouchPoint(device, ev->touchid);
+}
+
+static void
+ProcessTouchQueue(TouchInfoPtr touch, DeviceIntPtr device)
+{
+ int j;
+
+ /* The first queued event is this TouchBegin, so skip it. */
+ for (j = 1; j < touch->num_frozen_events; j++)
+ {
+ if (touch->frozen_events[j].any.type == ET_TouchMotion)
+ ProcessTouchMotionEvent((TouchMotionEvent*)&touch->frozen_events[j],
+ device);
+ else if (touch->frozen_events[j].any.type == ET_TouchEnd)
+ ProcessTouchEndEvent((TouchStateEvent*)&touch->frozen_events[j],
+ device);
+ else
+ FatalError("[Xi] %s: Unknown event type %d in touch queue\n",
+ device->name, touch->frozen_events[j].any.type);
+ }
+ touch->num_frozen_events = 0;
+}
+
+static void
+ProcessTouchBeginEvent(TouchStateEvent *ev, DeviceIntPtr device)
+{
+ TouchInfoPtr touch = FindTouchPoint(device, ev->touchid);
+ WindowPtr win;
+ SpriteRec tsprite;
+ SpritePtr sprite;
+ ClientPtr client;
+ GrabRec tempGrab;
+ Window child = None;
+ xEvent *xi2;
+ int i = 0, err;
+
+ if (!touch)
+ {
+ DebugF("[Xi] %s: Received TouchBegin event for dead touchpoint %d\n",
+ device->name, ev->touchid);
+ return;
+ }
+
+ err = EventToXI2((InternalEvent *) ev, &xi2);
+ if (err != Success)
+ {
+ ErrorF("[Xi] %s: XI2 conversion failed in ProcessTouchBegin (%d)\n",
+ device->name, err);
+ return;
+ }
+
+ /* In Absolute focus_mode, we focus immediately under the touchpoint, so
+ * we need to build a window trace; in Relative, we just use the sprite. */
+ if (device->touch->focus_mode == Absolute)
+ {
+ /* Fake sprite for XYToWindow. */
+ memset(&tsprite, 0, sizeof(tsprite));
+ sprite = &tsprite;
+ tsprite.spriteTraceSize = 10;
+ tsprite.spriteTrace = calloc(tsprite.spriteTraceSize,sizeof(WindowPtr));
+ if (!tsprite.spriteTrace)
+ goto out;
+ tsprite.spriteTrace[0] = RootWindow(device);
+ XYToWindow(sprite, ev->root_x, ev->root_y);
+ } else
+ {
+ sprite = device->spriteInfo->sprite;
+ }
+
+ tempGrab.type = GetXI2Type((InternalEvent *) ev);
+ tempGrab.grabtype = GRABTYPE_XI2;
+ tempGrab.device = device;
+ tempGrab.detail.exact = ev->tool;
+ tempGrab.detail.pMask = NULL;
+ tempGrab.modifiersDetail.pMask = NULL;
+ tempGrab.next = NULL;
+
+ /* If we've already got win, then it means we're replaying the touch
+ * stream, so find it in the trace and then restart delivery from the next
+ * child. */
+ if (touch->win != None)
+ {
+ for (; i < sprite->spriteTraceGood; i++)
+ {
+ if (sprite->spriteTrace[i]->drawable.id == touch->win)
+ {
+ i++;
+ break;
+ }
+ }
+ }
+ /* Now walk the window tree downwards looking for (more) grabs. */
+ for (; i < sprite->spriteTraceGood; i++)
+ {
+ GrabPtr grab;
+
+ win = sprite->spriteTrace[i];
+ for (grab = wPassiveGrabs(win); grab; grab = grab->next)
+ {
+ DeviceIntPtr gdev;
+ XkbSrvInfoPtr xkbi = NULL;
+
+ if (grab->grabtype != GRABTYPE_XI2 || grab->type != XI_TouchBegin)
+ continue;
+
+ if (!IsMaster(grab->device) && device->u.master)
+ gdev = GetMaster(device, MASTER_KEYBOARD);
+ else
+ gdev = grab->modifierDevice;
+ if (gdev && gdev->key)
+ xkbi = gdev->key->xkbInfo;
+
+ tempGrab.window = win;
+ tempGrab.modifierDevice = grab->modifierDevice;
+ tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0;
+
+ if (GrabMatchesSecond(&tempGrab, grab, FALSE))
+ {
+ client = rClient(grab);
+ FixUpEventFromWindow(device, xi2, grab->window, None, TRUE);
+ err = TryClientEvents(client, device, xi2, 1, 0, NoEventMask,
+ grab);
+ if (!err)
+ continue; /* Couldn't deliver, keep trying */
+
+ /* At this point, we've delivered our grabbed event; if it's
+ * a Sync grab, then freeze the device, else replay anything
+ * that might be left in the queue. */
+ touch->client_id = client->index;
+ touch->win = win->drawable.id;
+
+ if (grab->keyboardMode == GrabModeSync)
+ {
+ touch->frozen = 1;
+ touch->num_frozen_events = 1;
+ if (!CheckTouchQueueSize(touch))
+ FatalError("[Xi] %s: Couldn't allocate frozen touch events\n",
+ device->name);
+ touch->frozen_events[0] = *(InternalEvent*)ev;
+ } else
+ {
+ ProcessTouchQueue(touch, device);
+ }
+ goto out;
+ }
+ }
+ }
+
+ /* If we get this far, we've gone through all the grabs and are now
+ * attempting normal window delivery. */
+ win = sprite->spriteTrace[sprite->spriteTraceGood - 1];
+ while (win)
+ {
+ OtherInputMasks *masks = wOtherInputMasks(win);
+
+ if (masks && GetWindowXI2Mask(device, win, xi2)) {
+ InputClients *iclients = masks->inputClients;
+ Mask mask = GetEventMask(device, xi2, iclients);
+ Mask filter = GetEventFilter(device, xi2);
+
+ client = rClient(iclients);
+ FixUpEventFromWindow(device, xi2, win, child, FALSE);
+ if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) == Success)
+ {
+ err = TryClientEvents(client, device, xi2, 1, mask, filter,
+ NULL);
+ if (err)
+ {
+ touch->client_id = client->index;
+ touch->win = win->drawable.id;
+ goto out;
+ }
+ }
+
+ }
+
+ child = win->drawable.id;
+ win = win->parent;
+ }
+
+out:
+ free(xi2);
+}
+
+void
+AllowTouches(ClientPtr client, TimeStamp time, DeviceIntPtr device,
+ int mode, uint32_t touchid)
+{
+ TouchInfoPtr touch = FindTouchPoint(device, touchid);
+
+ if (!touch)
+ {
+ DebugF("[Xi] %s: Received AllowEvents for dead touchpoint %d\n",
+ device->name, touchid);
+ return;
+ }
+
+ if (!touch->frozen || touch->num_frozen_events == 0)
+ return;
+
+ if (touch->frozen_events[0].any.type != ET_TouchBegin)
+ {
+ ErrorF("[Xi] %s: Corrupted touchstream queue, type %d at head\n",
+ device->name, touch->frozen_events[0].any.type);
+ return;
+ }
+
+ /* Either replay the TouchBegin down towards the next window, or flush the
+ * TouchMotion/TouchEnd queue out to the grabbing client, depending on the
+ * mode. */
+ touch->frozen = 0;
+ if (mode == XIReplayTouch)
+ ProcessTouchBeginEvent((TouchStateEvent *) &touch->frozen_events[0],
+ device);
+ else
+ ProcessTouchQueue(touch, device);
+}
+
/**
* Main device event processing function.
* Called from when processing the events from the event queue.
@@ -960,6 +1338,18 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
{
ProcessRawEvent(&ev->raw_event, device);
return;
+ } else if (ev->any.type == ET_TouchBegin)
+ {
+ ProcessTouchBeginEvent(&ev->touch_state_event, device);
+ return;
+ } else if (ev->any.type == ET_TouchEnd)
+ {
+ ProcessTouchEndEvent(&ev->touch_state_event, device);
+ return;
+ } else if (ev->any.type == ET_TouchMotion)
+ {
+ ProcessTouchMotionEvent(&ev->touch_motion_event, device);
+ return;
}
if (IsPointerDevice(device))
@@ -1563,6 +1953,39 @@ GrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
return AddPassiveGrabToList(client, grab);
}
+/* TouchBegin grab */
+int
+GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev, int tool,
+ GrabParameters *param, GrabMask *mask)
+{
+ WindowPtr pWin;
+ GrabPtr grab;
+ Mask access_mode = DixGrabAccess;
+ int rc;
+
+ rc = CheckGrabValues(client, param);
+ if (rc != Success)
+ return rc;
+
+ rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess);
+ if (rc != Success)
+ return rc;
+ if (param->this_device_mode == GrabModeSync)
+ access_mode |= DixFreezeAccess;
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
+ if (rc != Success)
+ return rc;
+
+ /* FIXME: tool gets truncated to 8 bits here */
+ grab = CreateGrab(client->index, dev, mod_dev, pWin, GRABTYPE_XI2,
+ mask, param, XI_TouchBegin, tool, NULL, NULL);
+
+ if (!grab)
+ return BadAlloc;
+
+ return AddPassiveGrabToList(client, grab);
+}
+
int
SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client,
Mask mask, Mask exclusivemasks)
diff --git a/Xi/extinit.c b/Xi/extinit.c
index 7edadea..556c060 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -812,6 +812,62 @@ static void SXIPropertyEvent(xXIPropertyEvent *from, xXIPropertyEvent *to)
swapl(&to->property, n);
}
+static void SXITouchStateEvent(xXITouchStateEvent *from,
+ xXITouchStateEvent *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);
+ swapl(&to->touchid, n);
+ swapl(&to->tool, n);
+ swaps(&to->sourceid, n);
+ swapl(&to->root, n);
+ swapl(&to->event, n);
+ swapl(&to->child, n);
+}
+
+static void SXITouchMotionEvent(xXITouchMotionEvent *from,
+ xXITouchMotionEvent *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);
+ swaps(&to->mask, n);
+ swapl(&to->touchid, n);
+ swapl(&to->root, n);
+ swapl(&to->event, n);
+ swapl(&to->child, n);
+ swapl(&to->root_x, n);
+ swapl(&to->root_y, n);
+ swapl(&to->event_x, n);
+ swapl(&to->event_y, n);
+ swapl(&to->x.integral, n);
+ swapl(&to->x.frac, n);
+ swapl(&to->y.integral, n);
+ swapl(&to->y.frac, n);
+ swapl(&to->touch_width_major.integral, n);
+ swapl(&to->touch_width_major.frac, n);
+ swapl(&to->touch_width_minor.integral, n);
+ swapl(&to->touch_width_minor.frac, n);
+ swapl(&to->tool_width_major.integral, n);
+ swapl(&to->tool_width_major.frac, n);
+ swapl(&to->tool_width_minor.integral, n);
+ swapl(&to->tool_width_minor.frac, n);
+ swaps(&to->orientation, n);
+ swaps(&to->flags, n);
+}
+
static void SRawEvent(xXIRawEvent *from, xXIRawEvent *to)
{
char n;
@@ -889,6 +945,15 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
case XI_RawButtonRelease:
SRawEvent((xXIRawEvent*)from, (xXIRawEvent*)to);
break;
+ case XI_TouchBegin:
+ case XI_TouchEnd:
+ SXITouchStateEvent((xXITouchStateEvent*)from,
+ (xXITouchStateEvent*)to);
+ break;
+ case XI_TouchMotion:
+ SXITouchMotionEvent((xXITouchMotionEvent*)from,
+ (xXITouchMotionEvent*)to);
+ break;
default:
ErrorF("[Xi] Unknown event type to swap. This is a bug.\n");
break;
diff --git a/Xi/xiallowev.c b/Xi/xiallowev.c
index 3077e1a..5de43ff 100644
--- a/Xi/xiallowev.c
+++ b/Xi/xiallowev.c
@@ -44,6 +44,7 @@
int
SProcXIAllowEvents(ClientPtr client)
{
+ xXIAllowEventsDetailReq *req;
char n;
REQUEST(xXIAllowEventsReq);
@@ -52,6 +53,13 @@ SProcXIAllowEvents(ClientPtr client)
swaps(&stuff->deviceid, n);
swapl(&stuff->time, n);
+ /* See comment in ProcXIAllowEvents. */
+ if ((stuff->length << 2) == sizeof(xXIAllowEventsDetailReq))
+ {
+ req = (xXIAllowEventsDetailReq *) stuff;
+ swapl(&req->detail, n);
+ }
+
return ProcXIAllowEvents(client);
}
@@ -61,17 +69,31 @@ ProcXIAllowEvents(ClientPtr client)
TimeStamp time;
DeviceIntPtr dev;
int ret = Success;
+ xXIAllowEventsDetailReq req;
- REQUEST(xXIAllowEventsReq);
- REQUEST_SIZE_MATCH(xXIAllowEventsReq);
+ /* XI 2.1 adds a detail field to the request to support touch events,
+ * so we need to cater for both versions of the request. */
+ if ((client->req_len << 2) == sizeof(xXIAllowEventsDetailReq))
+ {
+ req = *(xXIAllowEventsDetailReq*)client->requestBuffer;
+ }
+ else if ((client->req_len << 2) == sizeof(xXIAllowEventsReq))
+ {
+ memcpy(&req, client->requestBuffer, sizeof(xXIAllowEventsReq));
+ req.detail = 0;
+ }
+ else
+ {
+ return BadLength;
+ }
- ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess);
+ ret = dixLookupDevice(&dev, req.deviceid, client, DixGetAttrAccess);
if (ret != Success)
return ret;
- time = ClientTimeToServerTime(stuff->time);
+ time = ClientTimeToServerTime(req.time);
- switch (stuff->mode) {
+ switch (req.mode) {
case XIReplayDevice:
AllowSome(client, time, dev, NOT_GRABBED);
break;
@@ -93,8 +115,12 @@ ProcXIAllowEvents(ClientPtr client)
if (IsMaster(dev))
AllowSome(client, time, dev, THAWED_BOTH);
break;
+ case XIAcceptTouch:
+ case XIReplayTouch:
+ AllowTouches(client, time, dev, req.mode, req.detail);
+ break;
default:
- client->errorValue = stuff->mode;
+ client->errorValue = req.mode;
ret = BadValue;
}
diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c
index 2966145..5bafe53 100644
--- a/Xi/xipassivegrab.c
+++ b/Xi/xipassivegrab.c
@@ -105,7 +105,8 @@ 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;
@@ -185,6 +186,10 @@ ProcXIPassiveGrabDevice(ClientPtr client)
status = GrabWindow(client, dev, stuff->grab_type,
¶m, &mask);
break;
+ case XIGrabtypeTouchBegin:
+ status = GrabTouch(client, dev, mod_dev, stuff->detail,
+ ¶m, &mask);
+ break;
}
if (status != GrabSuccess)
@@ -263,7 +268,8 @@ ProcXIPassiveUngrabDevice(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;
@@ -294,6 +300,7 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
case XIGrabtypeKeycode: tempGrab.type = XI_KeyPress; break;
case XIGrabtypeEnter: tempGrab.type = XI_Enter; break;
case XIGrabtypeFocusIn: tempGrab.type = XI_FocusIn; break;
+ case XIGrabtypeTouchBegin: tempGrab.type = XI_TouchBegin; break;
}
tempGrab.grabtype = GRABTYPE_XI2;
tempGrab.modifierDevice = mod_dev;
diff --git a/Xi/xiquerydevice.c b/Xi/xiquerydevice.c
index 303c8b2..f913d2f 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(xXITouchClassInfo);
+ len += dev->touch->num_touches * sizeof(xXITouchInfo);
+ }
+
return len;
}
@@ -373,6 +379,114 @@ SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info)
swaps(&info->sourceid, n);
}
+/**
+ * List information for the given touchpoint.
+ *
+ * @return The number of bytes written into info.
+ */
+int
+ListTouchInfo(DeviceIntPtr dev, xXITouchClassInfo* info, int touchnum,
+ Bool reportState)
+{
+ TouchClassPtr t = dev->touch;
+ xXITouchInfo *tinfo;
+ int i;
+
+ info->type = XITouchClass;
+ info->length = sizeof(xXITouchClassInfo) >> 2;
+ info->length += (t->num_touches * sizeof(xXITouchInfo)) >> 2;
+ info->sourceid = dev->id;
+ info->mode = t->xy_mode;
+ info->min_x = t->min_x;
+ info->max_x = t->max_x;
+ info->min_y = t->min_y;
+ info->max_y = t->max_y;
+ info->min_touch_width = t->min_touch_width;
+ info->max_touch_width = t->max_touch_width;
+ info->max_touches = t->max_touches;
+ info->num_touches = t->num_touches;
+
+ tinfo = (xXITouchInfo *) &info[1];
+ for (i = 0; i < t->num_touches; i++)
+ {
+ tinfo->length = sizeof(xXITouchInfo) >> 2;
+ tinfo->touchid = t->touches[i].touchid;
+ tinfo->tool = t->touches[i].tool;
+
+ if (reportState)
+ {
+ tinfo->x = t->touches[i].last_x;
+ tinfo->y = t->touches[i].last_y;
+ tinfo->touch_major = t->touches[i].last_touch_major;
+ tinfo->touch_minor = t->touches[i].last_touch_minor;
+ tinfo->tool_major = t->touches[i].last_tool_major;
+ tinfo->tool_minor = t->touches[i].last_tool_minor;
+ tinfo->orientation = t->touches[i].last_orientation;
+ }
+ else {
+ tinfo->x = info->min_x;
+ tinfo->y = info->min_y;
+ tinfo->touch_major = info->min_touch_width;
+ tinfo->touch_minor = info->min_touch_width;
+ tinfo->tool_major = info->min_touch_width;
+ tinfo->tool_minor = info->min_touch_width;
+ tinfo->orientation = 0;
+ }
+
+ tinfo++;
+ }
+
+ return info->length << 2;
+}
+
+static void
+SwapTouchInfo(DeviceIntPtr dev, xXITouchClassInfo* info)
+{
+ xXITouchInfo *tinfo;
+ int num_touches = info->num_touches;
+ int i;
+ char n;
+
+ swaps(&info->type, n);
+ swaps(&info->length, n);
+ swaps(&info->sourceid, n);
+ swapl(&info->num_touches, n);
+ swapl(&info->max_touches, n);
+ swapl(&info->min_x.integral, n);
+ swapl(&info->min_x.frac, n);
+ swapl(&info->max_x.integral, n);
+ swapl(&info->max_x.frac, n);
+ swapl(&info->min_y.integral, n);
+ swapl(&info->min_y.frac, n);
+ swapl(&info->max_y.integral, n);
+ swapl(&info->max_y.frac, n);
+ swapl(&info->min_touch_width.integral, n);
+ swapl(&info->min_touch_width.frac, n);
+ swapl(&info->max_touch_width.integral, n);
+ swapl(&info->max_touch_width.frac, n);
+
+ tinfo = (xXITouchInfo *) &info[1];
+ for (i = 0; i < num_touches; i++) {
+ swaps(&tinfo->length, n);
+ swapl(&tinfo->touchid, n);
+ swapl(&tinfo->tool, n);
+ swapl(&tinfo->x.integral, n);
+ swapl(&tinfo->x.frac, n);
+ swapl(&tinfo->y.integral, n);
+ swapl(&tinfo->y.frac, n);
+ swapl(&tinfo->touch_major.integral, n);
+ swapl(&tinfo->touch_major.frac, n);
+ swapl(&tinfo->touch_minor.integral, n);
+ swapl(&tinfo->touch_minor.frac, n);
+ swapl(&tinfo->tool_major.integral, n);
+ swapl(&tinfo->tool_major.frac, n);
+ swapl(&tinfo->tool_minor.integral, n);
+ swapl(&tinfo->tool_minor.frac, n);
+ swaps(&tinfo->orientation, n);
+ tinfo++;
+ }
+}
+
int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment)
{
DeviceIntPtr master = dev->u.master;
@@ -462,6 +576,14 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
total_len += len;
}
+ if (dev->touch)
+ {
+ (*nclasses)++;
+ len = ListTouchInfo(dev, (xXITouchClassInfo*)any, i, rc == Success);
+ any += len;
+ total_len += len;
+ }
+
return total_len;
}
@@ -489,6 +611,9 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info)
case XIValuatorClass:
SwapValuatorInfo(dev, (xXIValuatorInfo*)any);
break;
+ case XITouchClass:
+ SwapTouchInfo(dev, (xXITouchClassInfo*)any);
+ break;
}
any += len * 4;
diff --git a/Xi/xiquerydevice.h b/Xi/xiquerydevice.h
index 02f0659..9700ca7 100644
--- a/Xi/xiquerydevice.h
+++ b/Xi/xiquerydevice.h
@@ -44,4 +44,6 @@ 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, xXITouchClassInfo* info,
+ int axisnumber, Bool reportState);
#endif /* QUERYDEV_H */
diff --git a/Xi/xiselectev.c b/Xi/xiselectev.c
index 7aa3f0a..e64b898 100644
--- a/Xi/xiselectev.c
+++ b/Xi/xiselectev.c
@@ -141,6 +141,27 @@ ProcXISelectEvents(ClientPtr client)
return BadValue;
}
+ /* Only one client per window may select for touch begin events;
+ * touch motion and end events may not be selected for. */
+ if (evmask->mask_len >= 1)
+ {
+ unsigned char *bits = (unsigned char*)&evmask[1];
+ if (BitIsOn(bits, XI_TouchBegin))
+ {
+ OtherInputMasks *inputMasks = wOtherInputMasks(win);
+ if (inputMasks &&
+ (BitIsOn(inputMasks->xi2mask[evmask->deviceid],
+ XI_TouchBegin) ||
+ BitIsOn(inputMasks->xi2mask[XIAllDevices],
+ XI_TouchBegin) ||
+ BitIsOn(inputMasks->xi2mask[XIAllMasterDevices],
+ XI_TouchBegin)))
+ return BadValue;
+ }
+ if (BitIsOn(bits, XI_TouchMotion) || BitIsOn(bits, XI_TouchEnd))
+ return BadValue;
+ }
+
if (XICheckInvalidMaskBits((unsigned char*)&evmask[1],
evmask->mask_len * 4) != Success)
return BadValue;
diff --git a/configure.ac b/configure.ac
index 95f7a76..188d129 100644
--- a/configure.ac
+++ b/configure.ac
@@ -794,7 +794,7 @@ WINDOWSWMPROTO="windowswmproto"
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.0.99.3] [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.0.99.3] [inputproto >= 2.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 e506f6a..1eabc6c 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -752,6 +752,12 @@ FreeDeviceClass(int type, pointer *class)
free((*v));
break;
}
+ case XITouchClass:
+ {
+ TouchClassPtr *t = (TouchClassPtr*)class;
+ free((*t));
+ break;
+ }
case FocusClass:
{
FocusClassPtr *f = (FocusClassPtr*)class;
@@ -860,6 +866,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);
@@ -1550,6 +1557,55 @@ 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.
+ * @min_x The minimum value for the x axis.
+ * @max_x The maximum value for the x axis.
+ * @min_y The minimum value for the y axis.
+ * @max_y The maximum value for the y axis.
+ * @min_touch_width The minimum value for touch/tool width.
+ * @max_touch_width The maximum value for touch/tool width.
+ */
+Bool
+InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches,
+ unsigned int xy_mode, unsigned int focus_mode,
+ double min_x, double max_x,
+ double min_y, double max_y,
+ double min_touch_width, double max_touch_width)
+{
+ if (device->touch)
+ return FALSE;
+
+ if (xy_mode != Absolute && xy_mode != Relative)
+ return FALSE;
+ if (focus_mode != Absolute && focus_mode != Relative)
+ return FALSE;
+ if (max_touches == 0)
+ return FALSE;
+ if (max_x < min_x || max_y < min_y || max_touch_width < min_touch_width)
+ return FALSE;
+
+ device->touch = calloc(1, sizeof(*device->touch) +
+ max_touches * sizeof(*device->touch->touches));
+ if (!device->touch)
+ return FALSE;
+ device->touch->touches = (TouchInfoPtr) &device->touch[1];
+ device->touch->max_touches = max_touches;
+ device->touch->xy_mode = xy_mode;
+ device->touch->focus_mode = focus_mode;
+ /* FIXME: don't throw away float */
+ device->touch->min_x.integral = min_x;
+ device->touch->max_x.integral = max_x;
+ device->touch->min_y.integral = min_y;
+ device->touch->max_y.integral = max_y;
+ device->touch->min_touch_width.integral = min_touch_width;
+ device->touch->max_touch_width.integral = max_touch_width;
+
+ 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 0f747c1..5461ad7 100644
--- a/dix/eventconvert.c
+++ b/dix/eventconvert.c
@@ -55,6 +55,8 @@ static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count);
static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce);
static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
+static int eventToTouchStateEvent(TouchStateEvent *ev, xEvent **xi);
+static int eventToTouchMotionEvent(TouchMotionEvent *ev, xEvent **xi);
/* Do not use, read comments below */
BOOL EventIsKeyRepeat(xEvent *event);
@@ -139,6 +141,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 +189,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;
@@ -238,6 +246,11 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
case ET_RawButtonRelease:
case ET_RawMotion:
return eventToRawEvent(&ev->raw_event, xi);
+ case ET_TouchBegin:
+ case ET_TouchEnd:
+ return eventToTouchStateEvent(&ev->touch_state_event, xi);
+ case ET_TouchMotion:
+ return eventToTouchMotionEvent(&ev->touch_motion_event, xi);
default:
break;
}
@@ -650,6 +663,57 @@ eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
return Success;
}
+static int
+eventToTouchStateEvent(TouchStateEvent *ev, xEvent **xi)
+{
+ xXITouchStateEvent* state;
+ int len = sizeof(xXITouchStateEvent);
+
+ *xi = calloc(1, len);
+ state = (xXITouchStateEvent*)*xi;
+ state->type = GenericEvent;
+ state->extension = IReqCode;
+ state->length = bytes_to_int32(len - sizeof(xEvent));
+ state->evtype = GetXI2Type((InternalEvent*)ev);
+ state->deviceid = ev->deviceid;
+ state->time = ev->time;
+ state->sourceid = ev->sourceid;
+ state->touchid = ev->touchid;
+ state->tool = ev->tool;
+
+ return Success;
+}
+
+static int
+eventToTouchMotionEvent(TouchMotionEvent *ev, xEvent **xi)
+{
+ xXITouchMotionEvent* motion;
+ int len = sizeof(xXITouchMotionEvent);
+
+ *xi = calloc(1, len);
+ motion = (xXITouchMotionEvent*)*xi;
+ motion->type = GenericEvent;
+ motion->extension = IReqCode;
+ motion->length = bytes_to_int32(len - sizeof(xEvent));
+ motion->evtype = GetXI2Type((InternalEvent*)ev);
+ motion->deviceid = ev->deviceid;
+ motion->time = ev->time;
+ motion->sourceid = ev->sourceid;
+ motion->touchid = ev->touchid;
+ motion->mask = ev->mask;
+ motion->root_x = ev->root_x;
+ motion->root_y = ev->root_y;
+ motion->x = ev->x;
+ motion->y = ev->y;
+ motion->touch_width_major = ev->touch_width_minor;
+ motion->touch_width_minor = ev->touch_width_minor;
+ motion->tool_width_major = ev->tool_width_major;
+ motion->tool_width_minor = ev->tool_width_minor;
+ motion->orientation = ev->orientation;
+
+ return Success;
+}
+
/**
* Return the corresponding core type for the given event or 0 if no core
* equivalent exists.
@@ -721,6 +785,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 a2c9d1b..d0323d9 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -195,8 +195,6 @@ typedef const char *string;
#define XE_KBPTR (xE->u.keyButtonPointer)
-#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
-
CallbackListPtr EventCallback;
CallbackListPtr DeviceEventCallback;
@@ -334,12 +332,6 @@ IsMaster(DeviceIntPtr dev)
return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD;
}
-static WindowPtr XYToWindow(
- SpritePtr pSprite,
- int x,
- int y
-);
-
/**
* Max event opcode.
*/
@@ -447,7 +439,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 */
@@ -2262,6 +2254,32 @@ FixUpEventFromWindow(
event->evtype == XI_PropertyEvent)
return;
+ if (event->evtype == XI_TouchBegin || event->evtype == XI_TouchEnd)
+ {
+ xXITouchStateEvent* state = (xXITouchStateEvent*)xE;
+ state->root = pSprite->spriteTrace[0]->drawable.id;
+ state->event = pWin->drawable.id;
+ state->child = child;
+ return;
+ } else if (event->evtype == XI_TouchMotion)
+ {
+ xXITouchMotionEvent* motion = (xXITouchMotionEvent*)xE;
+ motion->root = pSprite->spriteTrace[0]->drawable.id;
+ motion->event = pWin->drawable.id;
+ if (pSprite->hot.pScreen == pWin->drawable.pScreen)
+ {
+ motion->event_x = motion->root_x - FP1616(pWin->drawable.x, 0);
+ motion->event_y = motion->root_y - FP1616(pWin->drawable.y, 0);
+ motion->child = child;
+ } else
+ {
+ motion->event_x = 0;
+ motion->event_y = 0;
+ motion->child = None;
+ }
+ return;
+ }
+
event->root = pSprite->spriteTrace[0]->drawable.id;
event->event = pWin->drawable.id;
if (pSprite->hot.pScreen == pWin->drawable.pScreen)
@@ -2582,7 +2600,7 @@ PointInBorderSize(WindowPtr pWin, int x, int y)
*
* @returns the window at the given coordinates.
*/
-static WindowPtr
+WindowPtr
XYToWindow(SpritePtr pSprite, int x, int y)
{
WindowPtr pWin;
@@ -3451,9 +3469,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 e5134d3..7e3a241 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -46,6 +46,7 @@
#include "mipointer.h"
#include "eventstr.h"
#include "eventconvert.h"
+#include "windowstr.h"
#include <X11/extensions/XKBproto.h>
#include "xkbsrv.h"
@@ -1232,6 +1233,159 @@ GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type,
}
/**
+ * Get events for a touch; always generates a TouchMotion event, and may
+ * generate a TouchBegin if this is the first touch of the sequence.
+ *
+ * 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, uint32_t touchid,
+ uint32_t tool, uint16_t mask, double x, double y,
+ double touch_width_major, double touch_width_minor,
+ double tool_width_major, double tool_width_minor,
+ unsigned int orientation)
+{
+ int num_events = 0;
+ uint32_t time = GetTimeInMillis();
+ int16_t rx, ry;
+ float rx_frac = 0.0, ry_frac = 0.0;
+ TouchMotionEvent *motion;
+ TouchStateEvent *state;
+ TouchInfoPtr touch = FindTouchPoint(pDev, touchid);
+ ScreenPtr screen = pDev->spriteInfo->sprite->hotPhys.pScreen;
+ AxisInfo axis;
+
+ /* refuse events from disabled devices */
+ if (!pDev->enabled)
+ return 0;
+
+ /* Sanity checks. */
+ if (!pDev->touch)
+ return 0;
+ if ((mask & XITouchOrientationMask) && orientation >= 360)
+ return 0;
+
+ /* 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 (pDev->touch->focus_mode == Absolute) {
+ if (mask & XITouchXMask) {
+ axis.min_value = pDev->touch->min_x.integral;
+ axis.max_value = pDev->touch->max_x.integral;
+ rx = rescaleValuatorAxis(x, 0.0, &rx_frac, &axis, NULL,
+ screen->width);
+ }
+ if (mask & XITouchYMask) {
+ axis.min_value = pDev->touch->min_y.integral;
+ axis.max_value = pDev->touch->max_y.integral;
+ ry = rescaleValuatorAxis(y, 0.0, &ry_frac, &axis, NULL,
+ screen->height);
+ }
+ }
+ else {
+ if (mask & XITouchXMask)
+ rx = pDev->spriteInfo->sprite->hotPhys.x;
+ if (mask & XITouchYMask)
+ ry = pDev->spriteInfo->sprite->hotPhys.y;
+ }
+
+ if (!touch) {
+ /* We need at least x and y co-ordinates to start a touch, to know
+ * where to deliver the TouchBegin. */
+ if (!(mask & XITouchXMask) || !(mask & XITouchYMask))
+ return 0;
+
+ touch = CreateTouchPoint(pDev, touchid, tool);
+ if (!touch)
+ return 0;
+
+ state = (TouchStateEvent *) events->event;
+ events++;
+ num_events++;
+ memset(state, 0, sizeof(TouchStateEvent));
+ state->header = ET_Internal;
+ state->type = ET_TouchBegin;
+ state->length = sizeof(TouchStateEvent);
+ state->time = time;
+ state->deviceid = pDev->id;
+ state->sourceid = pDev->id;
+ state->touchid = touchid;
+ state->tool = tool;
+ state->root = screen->root->drawable.id;
+ state->root_x = rx;
+ state->root_y = ry;
+ }
+
+ motion = (TouchMotionEvent *) events->event;
+ num_events++;
+ memset(motion, 0, sizeof(TouchMotionEvent));
+ motion->header = ET_Internal;
+ motion->type = ET_TouchMotion;
+ motion->length = sizeof(TouchMotionEvent);
+ motion->time = time;
+ motion->deviceid = pDev->id;
+ motion->sourceid = pDev->id;
+ motion->root = screen->root->drawable.id;
+ motion->touchid = touchid;
+ motion->mask = mask;
+
+ /* FIXME: don't throw away float */
+ if (mask & XITouchXMask) {
+ motion->x.integral = x;
+ motion->root_x = FP1616(rx, rx_frac);
+ }
+ if (mask & XITouchYMask) {
+ motion->y.integral = y;
+ motion->root_y = FP1616(ry, ry_frac);
+ }
+ if (mask & XITouchTouchSizeMask) {
+ motion->touch_width_major.integral = touch_width_major;
+ motion->touch_width_minor.integral = touch_width_minor;
+ }
+ if (mask & XITouchToolSizeMask) {
+ motion->tool_width_major.integral = tool_width_major;
+ motion->tool_width_minor.integral = tool_width_minor;
+ }
+ if (mask & XITouchOrientationMask) {
+ motion->orientation = orientation;
+ }
+
+ return num_events;
+}
+
+int
+GetTouchFinishEvents(EventList *events, DeviceIntPtr pDev, uint32_t touchid)
+{
+ TouchStateEvent *event;
+ TouchInfoPtr touch = FindTouchPoint(pDev, touchid);
+
+ /* refuse events from disabled devices */
+ if (!pDev->enabled)
+ return 0;
+
+ if (!touch) {
+ DebugF("[Xi] %s: Got touch finish event for dead touchpoint %d\n",
+ pDev->name, touchid);
+ return 0;
+ }
+
+ event = (TouchStateEvent *) events->event;
+ memset(event, 0, sizeof(TouchStateEvent));
+ event->header = ET_Internal;
+ event->type = ET_TouchEnd;
+ event->length = sizeof(TouchStateEvent);
+ event->time = GetTimeInMillis();
+ event->deviceid = pDev->id;
+ event->sourceid = pDev->id;
+ event->touchid = touchid;
+ event->tool = touch->tool;
+
+ 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/inpututils.c b/dix/inpututils.c
index 6693c67..6b0529f 100644
--- a/dix/inpututils.c
+++ b/dix/inpututils.c
@@ -418,3 +418,67 @@ FreeInputAttributes(InputAttributes *attrs)
free(attrs);
}
+TouchInfoPtr
+FindTouchPoint(DeviceIntPtr dev, uint32_t touchid)
+{
+ int i;
+
+ if (!dev->touch)
+ return NULL;
+
+ for (i = 0; i < dev->touch->max_touches; i++)
+ if (dev->touch->touches[i].touchid == touchid)
+ return &dev->touch->touches[i];
+
+ return NULL;
+}
+
+TouchInfoPtr
+CreateTouchPoint(DeviceIntPtr dev, uint32_t touchid, uint32_t tool)
+{
+ int i;
+
+ if (!dev->touch || dev->touch->num_touches == dev->touch->max_touches)
+ return NULL;
+
+ if (FindTouchPoint(dev, touchid))
+ return NULL;
+
+ for (i = 0; i < dev->touch->max_touches; i++)
+ {
+ if (!dev->touch->touches[i].touchid)
+ {
+ dev->touch->num_touches++;
+ memset(&dev->touch->touches[i], 0, sizeof(TouchInfoRec));
+ dev->touch->touches[i].touchid = touchid;
+ dev->touch->touches[i].tool = tool;
+ return &dev->touch->touches[i];
+ }
+ }
+
+ return NULL;
+}
+
+void
+FinishTouchPoint(DeviceIntPtr dev, uint32_t touchid)
+{
+ TouchInfoPtr touch = FindTouchPoint(dev, touchid);
+
+ if (!touch)
+ return;
+
+ touch->touchid = 0;
+ touch->client_id = 0;
+ touch->frozen = 0;
+ touch->num_frozen_events = 0;
+ touch->win = None;
+ touch->tool = 0;
+ touch->last_x = dev->touch->min_x;
+ touch->last_y = dev->touch->min_y;
+ touch->last_touch_major = dev->touch->min_touch_width;
+ touch->last_touch_minor = dev->touch->min_touch_width;
+ touch->last_tool_major = dev->touch->min_touch_width;
+ touch->last_tool_minor = dev->touch->min_touch_width;
+ touch->last_orientation = 0;
+ dev->touch->num_touches--;
+}
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 877eb03..df8ac49 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -1360,4 +1360,30 @@ xf86EnableDevice(DeviceIntPtr dev)
EnableDevice(dev, TRUE);
}
+void
+xf86PostTouchMotion(DeviceIntPtr dev, uint32_t touchid, uint32_t tool,
+ uint16_t mask, double x, double y,
+ double touch_major, double touch_minor,
+ double tool_major, double tool_minor,
+ unsigned int orientation)
+{
+ int i, nevents;
+
+ nevents = GetTouchEvents(xf86Events, dev, touchid, tool, mask, x, y,
+ touch_major, touch_minor, tool_major, tool_minor,
+ orientation);
+ for (i = 0; i < nevents; i++)
+ mieqEnqueue(dev, (InternalEvent *)((xf86Events + i)->event));
+}
+
+void
+xf86FiniTouchPoint(DeviceIntPtr dev, uint32_t touchid)
+{
+ int i, nevents;
+
+ nevents = GetTouchFinishEvents(xf86Events, dev, touchid);
+ 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 20a3f1b..70f822c 100644
--- a/hw/xfree86/common/xf86Xinput.h
+++ b/hw/xfree86/common/xf86Xinput.h
@@ -199,6 +199,20 @@ extern _X_EXPORT void xf86EnableDevice(DeviceIntPtr dev);
/* not exported */
int xf86NewInputDevice(IDevPtr idev, DeviceIntPtr *pdev, BOOL is_auto);
+/* Multitouch API. */
+extern _X_EXPORT void xf86PostTouchMotion(DeviceIntPtr dev,
+ uint32_t touchid,
+ uint32_t tool,
+ uint16_t mask,
+ double x,
+ double y,
+ double touch_major,
+ double touch_minor,
+ double width_major,
+ double width_minor,
+ unsigned int orientation);
+extern _X_EXPORT void xf86FiniTouchPoint(DeviceIntPtr dev, uint32_t touchid);
+
/* xf86Helper.c */
extern _X_EXPORT void xf86AddInputDriver(InputDriverPtr driver, pointer module, int flags);
extern _X_EXPORT void xf86DeleteInputDriver(int drvIndex);
diff --git a/include/dix.h b/include/dix.h
index a282a08..4f9bbc4 100644
--- a/include/dix.h
+++ b/include/dix.h
@@ -369,6 +369,13 @@ extern void AllowSome(
DeviceIntPtr /* thisDev */,
int /* newState */);
+extern void AllowTouches(
+ ClientPtr /* client */,
+ TimeStamp /* time */,
+ DeviceIntPtr /* thisDev */,
+ int /* mode */,
+ uint32_t /* touchid */);
+
extern void ReleaseActiveGrabs(
ClientPtr client);
diff --git a/include/events.h b/include/events.h
index 375173a..9ceceda 100644
--- a/include/events.h
+++ b/include/events.h
@@ -26,6 +26,8 @@
#define EVENTS_H
typedef struct _DeviceEvent DeviceEvent;
typedef struct _DeviceChangedEvent DeviceChangedEvent;
+typedef struct _TouchStateEvent TouchStateEvent;
+typedef struct _TouchMotionEvent TouchMotionEvent;
#if XFreeXDGA
typedef struct _DGAEvent DGAEvent;
#endif
diff --git a/include/eventstr.h b/include/eventstr.h
index 433227e..da11d6a 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 */
};
@@ -209,6 +212,43 @@ struct _RawDeviceEvent
} valuators;
};
+struct _TouchStateEvent
+{
+ unsigned char header; /**< Always ET_Internal */
+ enum EventType type; /**< ET_TouchBegin or ET_TouchEnd */
+ 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; /**< Unique identifier for this touch */
+ uint32_t tool; /**< Identifier of the physical tool */
+ Window root; /**< Root window for events */
+ FP1616 root_x; /**< x in screen co-ordinates */
+ FP1616 root_y; /**< y in screen co-ordinates */
+};
+
+struct _TouchMotionEvent
+{
+ unsigned char header; /**< Always ET_Internal */
+ enum EventType type; /**< ET_TouchMotion */
+ 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; /**< Unique identifier for this touch */
+ uint16_t mask; /**< Components present in this event */
+ Window root; /**< Root window event is relative to */
+ FP1616 root_x; /**< x in screen co-ordinates */
+ FP1616 root_y; /**< y in screen co-ordinates */
+ FP3232 x;
+ FP3232 y;
+ FP3232 touch_width_major;
+ FP3232 touch_width_minor;
+ FP3232 tool_width_major;
+ FP3232 tool_width_minor;
+ uint16_t orientation;
+};
+
#ifdef XQUARTZ
#define XQUARTZ_EVENT_MAXARGS 5
struct _XQuartzEvent {
@@ -234,6 +274,8 @@ union _InternalEvent {
} any;
DeviceEvent device_event;
DeviceChangedEvent changed_event;
+ TouchStateEvent touch_state_event;
+ TouchMotionEvent touch_motion_event;
#if XFreeXDGA
DGAEvent dga_event;
#endif
diff --git a/include/exevents.h b/include/exevents.h
index 39e1c70..48212ad 100644
--- a/include/exevents.h
+++ b/include/exevents.h
@@ -202,6 +202,15 @@ GrabWindow(
GrabMask* /* eventMask */);
extern int
+GrabTouch(
+ ClientPtr /* client */,
+ DeviceIntPtr /* dev */,
+ DeviceIntPtr /* mod_dev */,
+ int /* tool */,
+ GrabParameters* /* param */,
+ GrabMask* /* eventMask */);
+
+extern int
SelectForWindow(
DeviceIntPtr /* dev */,
WindowPtr /* pWin */,
diff --git a/include/input.h b/include/input.h
index 0ae6094..5fd51a0 100644
--- a/include/input.h
+++ b/include/input.h
@@ -105,6 +105,9 @@ typedef struct _DeviceIntRec *DeviceIntPtr;
typedef struct _ClassesRec *ClassesPtr;
typedef struct _SpriteRec *SpritePtr;
typedef union _GrabMask GrabMask;
+typedef struct _TouchInfoRec *TouchInfoPtr;
+
+#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
typedef struct _EventList {
xEvent* event;
@@ -318,6 +321,18 @@ 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 /*xy_mode*/,
+ unsigned int /*focus_mode*/,
+ double /*min_x*/,
+ double /*max_x*/,
+ double /*min_y*/,
+ double /*max_y*/,
+ double /*min_touch_width*/,
+ double /*max_touch_width*/);
+
typedef void (*BellProcPtr)(
int /*percent*/,
DeviceIntPtr /*device*/,
@@ -471,6 +486,25 @@ extern int GetKeyboardValuatorEvents(
int num_valuator,
int *valuators);
+extern int GetTouchEvents(
+ EventListPtr events,
+ DeviceIntPtr pDev,
+ uint32_t touchid,
+ uint32_t tool,
+ uint16_t mask,
+ double x,
+ double y,
+ double touch_width_major,
+ double touch_width_minor,
+ double tool_width_major,
+ double tool_width_minor,
+ unsigned int orientation);
+
+extern int GetTouchFinishEvents(
+ EventListPtr events,
+ DeviceIntPtr pDev,
+ uint32_t touchid);
+
extern int GetProximityEvents(
EventListPtr events,
DeviceIntPtr pDev,
@@ -534,8 +568,13 @@ 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 TouchInfoPtr CreateTouchPoint(DeviceIntPtr dev, uint32_t touchid,
+ uint32_t tool);
+extern TouchInfoPtr FindTouchPoint(DeviceIntPtr dev, uint32_t touchid);
+extern void FinishTouchPoint(DeviceIntPtr dev, uint32_t 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,
@@ -543,6 +582,7 @@ void FixUpEventFromWindow(SpritePtr pSprite,
WindowPtr pWin,
Window child,
Bool calcChild);
+extern WindowPtr XYToWindow(SpritePtr pSprite, int x, int y);
/* Implemented by the DDX. */
extern _X_EXPORT int NewInputDeviceRequest(
diff --git a/include/inputstr.h b/include/inputstr.h
index e1cf06a..544f3cd 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"
@@ -70,7 +72,7 @@ SOFTWARE.
* 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 */
/**
@@ -242,6 +244,39 @@ typedef struct _ValuatorClassRec {
ValuatorAccelerationRec accelScheme;
} ValuatorClassRec, *ValuatorClassPtr;
+typedef struct _TouchInfoRec {
+ uint32_t touchid; /* 0 if currently unused */
+ int sourceid;
+ int client_id;
+ Window win;
+ int frozen;
+ int size_frozen_events;
+ int num_frozen_events;
+ InternalEvent *frozen_events;
+ uint32_t tool;
+ FP3232 last_x;
+ FP3232 last_y;
+ FP3232 last_touch_major;
+ FP3232 last_touch_minor;
+ FP3232 last_tool_major;
+ FP3232 last_tool_minor;
+ uint16_t last_orientation;
+} TouchInfoRec;
+
+typedef struct _TouchClassRec {
+ FP3232 min_x;
+ FP3232 max_x;
+ FP3232 min_y;
+ FP3232 max_y;
+ FP3232 min_touch_width;
+ FP3232 max_touch_width;
+ unsigned int xy_mode;
+ unsigned int focus_mode;
+ unsigned int max_touches;
+ unsigned int num_touches;
+ TouchInfoPtr touches;
+} TouchClassRec, *TouchClassPtr;
+
typedef struct _ButtonClassRec {
int sourceid;
CARD8 numButtons;
@@ -346,6 +381,7 @@ typedef struct _LedFeedbackClassRec {
typedef struct _ClassesRec {
KeyClassPtr key;
ValuatorClassPtr valuator;
+ TouchClassPtr touch;
ButtonClassPtr button;
FocusClassPtr focus;
ProximityClassPtr proximity;
@@ -511,6 +547,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 c674465..f21d632 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -127,7 +127,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 fa60b40..df4014f 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -282,6 +282,13 @@ ChangeDeviceID(DeviceIntPtr dev, InternalEvent* event)
case ET_RawMotion:
event->raw_event.deviceid = dev->id;
break;
+ case ET_TouchBegin:
+ case ET_TouchEnd:
+ event->touch_state_event.deviceid = dev->id;
+ break;
+ case ET_TouchMotion:
+ event->touch_motion_event.deviceid = dev->id;
+ break;
default:
ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
event->any.type);
@@ -388,6 +395,9 @@ mieqProcessDeviceEvent(DeviceIntPtr dev,
NewCurrentScreen (dev, DequeueScreen(dev), x, y);
}
break;
+ case ET_TouchMotion:
+ /* XXX FIXME: Add screen-crossing support here */
+ break;
default:
break;
}
--
1.7.1
More information about the xorg-devel
mailing list