[PATCH 13/42] input: add a TouchClassRec to the devices

Peter Hutterer peter.hutterer at who-t.net
Wed Dec 14 19:01:50 PST 2011


From: Daniel Stone <daniel at fooishbar.org>

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 at who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 Xi/exevents.c      |   61 +++++++++++++++++++++++++++++++++
 Xi/xiquerydevice.c |   39 +++++++++++++++++++++
 Xi/xiquerydevice.h |    1 +
 dix/Makefile.am    |    1 +
 dix/devices.c      |   87 +++++++++++++++++++++++++++++++++++++++++++++++-
 dix/touch.c        |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/input.h    |   27 +++++++++++++++
 include/inputstr.h |   53 +++++++++++++++++++++++++++++
 8 files changed, 362 insertions(+), 1 deletions(-)
 create mode 100644 dix/touch.c

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 2db6053..ffb48d1 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 at 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 5f543f6..0879080 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 9db6aa2..632c42e 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 f5af619..b7358aa 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 9ca8fe0..7478ad6 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 0000000..9fa2f3c
--- /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 at 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 a94ff94..0d31edf 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 e684798..9881c7e 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. */
-- 
1.7.7.1



More information about the xorg-devel mailing list