summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stone <daniel@fooishbar.org>2011-12-14 12:46:40 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2011-12-19 09:08:36 +1000
commit3fb258ca28850c998097b55884774cb95f476f69 (patch)
tree8e620ad39a18467800e599694c9258411632988c
parent098b837440e40bbc485368ec9658e12efd6ef581 (diff)
input: add a TouchClassRec to the devices
These structs will be used to store touch-related data, events and information. Drivers must call InitTouchClassDeviceStruct to set up a multi-touch capable device. Touchpoints for the DDX and the DIX are handled separately - touchpoints submitted by the driver/DDX will be stored in the DDXTouchPointInfoRec. Once the touchpoints are processed by the DIX, new TouchPointInfoRecs are created and stored. This process is already used for pointer events with the last.valuators field. Note that this patch does not actually add the generation of touch events, only the required structs. TouchListeners are (future) recipients of touch or emulated pointer events. Each listener is in a state, depending which event they have already received. The type of listener defines how the listener got to be one. Co-authored-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Chase Douglas <chase.douglas@canonical.com>
-rw-r--r--Xi/exevents.c61
-rw-r--r--Xi/xiquerydevice.c39
-rw-r--r--Xi/xiquerydevice.h1
-rw-r--r--dix/Makefile.am1
-rw-r--r--dix/devices.c87
-rw-r--r--dix/touch.c94
-rw-r--r--include/input.h27
-rw-r--r--include/inputstr.h53
8 files changed, 362 insertions, 1 deletions
diff --git a/Xi/exevents.c b/Xi/exevents.c
index 2db605302..ffb48d1c7 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -44,6 +44,32 @@ SOFTWARE.
********************************************************/
+/*
+ * Copyright © 2010 Collabora Ltd.
+ * Copyright © 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Daniel Stone <daniel@fooishbar.org>
+ */
+
/********************************************************************
*
* Routines to register and initialize extension input devices.
@@ -641,6 +667,41 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
classes->proximity = to->proximity;
to->proximity = NULL;
}
+
+ if (from->touch)
+ {
+ TouchPointInfoPtr tmp;
+ if (!to->touch)
+ {
+ classes = to->unused_classes;
+ to->touch = classes->touch;
+ if (!to->touch)
+ {
+ int i;
+ to->touch = calloc(1, sizeof(TouchClassRec));
+ if (!to->touch)
+ FatalError("[Xi] no memory for class shift.\n");
+ to->touch->num_touches = from->touch->num_touches;
+ to->touch->touches = calloc(to->touch->num_touches,
+ sizeof(TouchPointInfoRec));
+ for (i = 0; i < to->touch->num_touches; i++)
+ TouchInitTouchPoint(to->touch, to->valuator, i);
+ if (!to->touch)
+ FatalError("[Xi] no memory for class shift.\n");
+ } else
+ classes->touch = NULL;
+ }
+ tmp = to->touch->touches;
+ memcpy(to->touch, from->touch, sizeof(TouchClassRec));
+ to->touch->touches = tmp;
+ to->touch->sourceid = from->id;
+ } else if (to->touch)
+ {
+ ClassesPtr classes;
+ classes = to->unused_classes;
+ classes->touch = to->touch;
+ to->touch = NULL;
+ }
}
/**
diff --git a/Xi/xiquerydevice.c b/Xi/xiquerydevice.c
index 5f543f620..0879080ad 100644
--- a/Xi/xiquerydevice.c
+++ b/Xi/xiquerydevice.c
@@ -240,6 +240,8 @@ SizeDeviceClasses(DeviceIntPtr dev)
}
}
+ if (dev->touch)
+ len += sizeof(xXITouchInfo);
return len;
}
@@ -427,6 +429,31 @@ SwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo* info)
swapl(&info->increment.frac);
}
+/**
+ * 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 = touch->sourceid;
+ touch->mode = dev->touch->mode;
+ touch->num_touches = dev->touch->num_touches;
+
+ return touch->length << 2;
+}
+
+static void
+SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo* touch)
+{
+ swaps(&touch->type);
+ swaps(&touch->length);
+ swaps(&touch->sourceid);
+}
+
int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment)
{
DeviceIntPtr master = GetMaster(dev, MASTER_ATTACHED);
@@ -525,6 +552,14 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
total_len += len;
}
+ if (dev->touch)
+ {
+ (*nclasses)++;
+ len = ListTouchInfo(dev, (xXITouchInfo*)any);
+ any += len;
+ total_len += len;
+ }
+
return total_len;
}
@@ -554,6 +589,10 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info)
case XIScrollClass:
SwapScrollInfo(dev, (xXIScrollInfo*)any);
break;
+ case XITouchClass:
+ SwapTouchInfo(dev, (xXITouchInfo*)any);
+ break;
+
}
any += len * 4;
diff --git a/Xi/xiquerydevice.h b/Xi/xiquerydevice.h
index 9db6aa293..632c42eeb 100644
--- a/Xi/xiquerydevice.h
+++ b/Xi/xiquerydevice.h
@@ -45,4 +45,5 @@ int ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info);
int ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info,
int axisnumber, Bool reportState);
int ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo* info, int axisnumber);
+int ListTouchInfo(DeviceIntPtr dev, xXITouchInfo* info);
#endif /* QUERYDEV_H */
diff --git a/dix/Makefile.am b/dix/Makefile.am
index f5af619e3..b7358aa72 100644
--- a/dix/Makefile.am
+++ b/dix/Makefile.am
@@ -39,6 +39,7 @@ libdix_la_SOURCES = \
swaprep.c \
swapreq.c \
tables.c \
+ touch.c \
window.c
EXTRA_DIST = buildatoms BuiltInAtoms Xserver.d Xserver-dtrace.h.in
diff --git a/dix/devices.c b/dix/devices.c
index 9ca8fe055..7478ad67a 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -263,6 +263,7 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart)
return (DeviceIntPtr)NULL;
dev->last.scroll = NULL;
+ dev->last.touches = NULL;
dev->id = devid;
dev->public.processInputProc = ProcessOtherEvent;
dev->public.realInputProc = ProcessOtherEvent;
@@ -761,6 +762,21 @@ 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)->touches[i].valuators);
+ }
+
+ free((*t));
+ break;
+ }
case FocusClass:
{
FocusClassPtr *f = (FocusClassPtr*)class;
@@ -869,6 +885,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);
@@ -948,6 +965,9 @@ CloseDevice(DeviceIntPtr dev)
free(dev->deviceGrab.sync.event);
free(dev->config_info); /* Allocated in xf86ActivateDevice. */
free(dev->last.scroll);
+ for (j = 0; j < dev->last.num_touches; j++)
+ free(dev->last.touches[j].valuators);
+ free(dev->last.touches);
dev->config_info = NULL;
dixFreeObjectWithPrivates(dev, PRIVATE_DEVICE);
}
@@ -1419,7 +1439,6 @@ InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc)
return TRUE;
}
-
static LedCtrl defaultLedControl = {
DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0};
@@ -1542,6 +1561,72 @@ 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 i;
+
+ if (device->touch || !device->valuator)
+ return FALSE;
+
+ /* Check the mode is valid, and at least X and Y axes. */
+ if (mode != XIDirectTouch && mode != XIDependentTouch)
+ return FALSE;
+ if (num_axes < 2)
+ return FALSE;
+
+ if (num_axes > MAX_VALUATORS)
+ {
+ LogMessage(X_WARNING,
+ "Device '%s' has %d touch axes, only using first %d.\n",
+ device->name, num_axes, MAX_VALUATORS);
+ num_axes = MAX_VALUATORS;
+ }
+
+ touch = calloc(1, sizeof(*touch));
+ if (!touch)
+ return FALSE;
+
+ touch->max_touches = max_touches;
+ if (max_touches == 0)
+ max_touches = 5; /* arbitrary number plucked out of the air */
+ touch->touches = calloc(max_touches, sizeof(*touch->touches));
+ if (!touch->touches)
+ goto err;
+ touch->num_touches = max_touches;
+ for (i = 0; i < max_touches; i++)
+ TouchInitTouchPoint(touch, device->valuator, i);
+
+ touch->mode = mode;
+ touch->sourceid = device->id;
+
+ device->touch = touch;
+ device->last.touches = calloc(max_touches, sizeof(*device->last.touches));
+ device->last.num_touches = touch->num_touches;
+ for (i = 0; i < touch->num_touches; i++)
+ TouchInitDDXTouchPoint(device, &device->last.touches[i]);
+
+ return TRUE;
+
+err:
+ for (i = 0; i < touch->num_touches; i++)
+ TouchFreeTouchPoint(device, i);
+
+ free(touch->touches);
+ free(touch);
+
+ return FALSE;
+}
+
/*
* Check if the given buffer contains elements between low (inclusive) and
* high (inclusive) only.
diff --git a/dix/touch.c b/dix/touch.c
new file mode 100644
index 000000000..9fa2f3c8d
--- /dev/null
+++ b/dix/touch.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2011 Collabra Ltd.
+ * Copyright © 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Daniel Stone <daniel@fooishbar.org>
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "inputstr.h"
+#include "scrnintstr.h"
+
+
+void
+TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch)
+{
+ memset(ddxtouch, 0, sizeof(*ddxtouch));
+ ddxtouch->valuators = valuator_mask_new(dev->valuator->numAxes);
+}
+
+
+Bool
+TouchInitTouchPoint(TouchClassPtr t, ValuatorClassPtr v, int index)
+{
+ TouchPointInfoPtr ti;
+
+ if (index >= t->num_touches)
+ return FALSE;
+ ti = &t->touches[index];
+
+ memset(ti, 0, sizeof(*ti));
+
+ ti->valuators = valuator_mask_new(v->numAxes);
+ if (!ti->valuators)
+ return FALSE;
+
+ ti->sprite.spriteTrace = calloc(32, sizeof(*ti->sprite.spriteTrace));
+ if (!ti->sprite.spriteTrace)
+ {
+ valuator_mask_free(&ti->valuators);
+ return FALSE;
+ }
+ ti->sprite.spriteTraceSize = 32;
+ ti->sprite.spriteTrace[0] = screenInfo.screens[0]->root;
+ ti->sprite.hot.pScreen = screenInfo.screens[0];
+ ti->sprite.hotPhys.pScreen = screenInfo.screens[0];
+
+ ti->client_id = -1;
+
+ return TRUE;
+}
+
+void
+TouchFreeTouchPoint(DeviceIntPtr device, int index)
+{
+ TouchPointInfoPtr ti;
+
+ if (!device->touch || index >= device->touch->num_touches)
+ return;
+ ti = &device->touch->touches[index];
+
+ valuator_mask_free(&ti->valuators);
+ free(ti->sprite.spriteTrace);
+ ti->sprite.spriteTrace = NULL;
+ free(ti->listeners);
+ ti->listeners = NULL;
+ free(ti->history);
+ ti->history = NULL;
+ ti->history_size = 0;
+ ti->history_elements = 0;
+}
+
+
diff --git a/include/input.h b/include/input.h
index a94ff942d..0d31edf75 100644
--- a/include/input.h
+++ b/include/input.h
@@ -124,6 +124,9 @@ typedef struct _DeviceIntRec *DeviceIntPtr;
typedef struct _ValuatorClassRec *ValuatorClassPtr;
typedef struct _ClassesRec *ClassesPtr;
typedef struct _SpriteRec *SpritePtr;
+typedef struct _TouchClassRec *TouchClassPtr;
+typedef struct _TouchPointInfo *TouchPointInfoPtr;
+typedef struct _DDXTouchPointInfo *DDXTouchPointInfoPtr;
typedef union _GrabMask GrabMask;
typedef struct _ValuatorMask ValuatorMask;
@@ -324,6 +327,12 @@ extern _X_EXPORT Bool InitPointerAccelerationScheme(
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*/,
@@ -563,6 +572,24 @@ extern void SendDevicePresenceEvent(int deviceid, int type);
extern _X_EXPORT InputAttributes *DuplicateInputAttributes(InputAttributes *attrs);
extern _X_EXPORT void FreeInputAttributes(InputAttributes *attrs);
+enum TouchListenerState{
+ LISTENER_AWAITING_BEGIN = 0, /**< Waiting for a TouchBegin event */
+ LISTENER_AWAITING_OWNER, /**< Waiting for a TouchOwnership event */
+ LISTENER_IS_OWNER, /**< Is the current owner */
+ LISTENER_HAS_END, /**< Has already received the end event */
+};
+
+enum TouchListenerType {
+ LISTENER_GRAB,
+ LISTENER_POINTER_GRAB,
+ LISTENER_REGULAR,
+ LISTENER_POINTER_REGULAR,
+};
+
+extern void TouchInitDDXTouchPoint(DeviceIntPtr dev, DDXTouchPointInfoPtr ddxtouch);
+extern Bool TouchInitTouchPoint(TouchClassPtr touch, ValuatorClassPtr v, int index);
+extern void TouchFreeTouchPoint(DeviceIntPtr dev, int index);
+
/* misc event helpers */
extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients);
extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event);
diff --git a/include/inputstr.h b/include/inputstr.h
index e6847984b..9881c7e46 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -300,6 +300,55 @@ typedef struct _ValuatorClassRec {
int v_scroll_axis; /* vert smooth-scrolling axis */
} ValuatorClassRec;
+typedef struct _TouchPointInfo {
+ /* client_id must be first element, see GetTouchEvents */
+ uint32_t client_id; /* touch ID as seen in client events */
+ int sourceid; /* Source device's ID for this touchpoint */
+ Bool active; /* whether or not the touch is active */
+ Bool pending_finish; /* true if the touch is physically inactive
+ * but still owned by a grab */
+ SpriteRec sprite; /* window trace for delivery */
+ ValuatorMask *valuators; /* last recorded axis values */
+ struct _TouchListener {
+ XID listener; /* grabs/event selection IDs receiving
+ * events for this touch */
+ enum TouchListenerType type;
+ enum TouchListenerState state;
+ enum InputLevel level; /* matters only for emulating touches */
+ } *listeners;
+ int num_listeners;
+ int num_grabs; /* number of open grabs on this touch
+ * which have not accepted or rejected */
+ Bool emulate_pointer;
+ DeviceEvent *history; /* History of events on this touchpoint */
+ size_t history_elements; /* Number of current elements in history */
+ size_t history_size; /* Size of history in elements */
+} TouchPointInfoRec;
+
+typedef struct _TouchListener TouchListener;
+
+typedef struct _DDXTouchPointInfo {
+ /* client_id must be first element, see GetTouchEvents */
+ uint32_t client_id; /* touch ID as seen in client events */
+ Bool active; /* whether or not the touch is active */
+ uint32_t ddx_id; /* touch ID given by the DDX */
+ Bool emulate_pointer;
+
+ ValuatorMask* valuators; /* last recorded axis values */
+} DDXTouchPointInfoRec;
+
+typedef struct _TouchClassRec {
+ int sourceid;
+ TouchPointInfoPtr touches;
+ unsigned short num_touches; /* number of allocated touches */
+ unsigned short max_touches; /* maximum number of touches, may be 0 */
+ CARD8 mode; /* ::XIDirectTouch, XIDependentTouch */
+ /* for pointer-emulation */
+ CARD8 buttonsDown; /* number of buttons down */
+ unsigned short state; /* logical button state */
+ Mask motionMask;
+} TouchClassRec;
+
typedef struct _ButtonClassRec {
int sourceid;
CARD8 numButtons;
@@ -383,6 +432,7 @@ typedef struct _LedFeedbackClassRec {
typedef struct _ClassesRec {
KeyClassPtr key;
ValuatorClassPtr valuator;
+ TouchClassPtr touch;
ButtonClassPtr button;
FocusClassPtr focus;
ProximityClassPtr proximity;
@@ -510,6 +560,7 @@ typedef struct _DeviceIntRec {
int id;
KeyClassPtr key;
ValuatorClassPtr valuator;
+ TouchClassPtr touch;
ButtonClassPtr button;
FocusClassPtr focus;
ProximityClassPtr proximity;
@@ -541,6 +592,8 @@ typedef struct _DeviceIntRec {
int numValuators;
DeviceIntPtr slave;
ValuatorMask *scroll;
+ int num_touches; /* size of the touches array */
+ DDXTouchPointInfoPtr touches;
} last;
/* Input device property handling. */