[PATCH xserver 08/10] Input: Add initial multitouch support from Xi 2.1
Daniel Stone
daniel at fooishbar.org
Fri Dec 17 09:13:33 PST 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.
Based on work from both myself and Chase Douglas.
Signed-off-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
---
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
More information about the xorg-devel
mailing list