[PATCH 23/42] dix: add touch event history helper functions

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


If touch client has not registered for ownership events and a grab above
that client is rejected, the client needs to receive the complete event
history.

The history currently doesn't really do fancy overflow handling. We assume
that the first TOUCH_HISTORY_SIZE events are the important ones and anything
after that is dropped. If that is a problem, fix the client that takes > 100
event to decide whether to accept or reject.

Events marked with TOUCH_CLIENT_ID or TOUCH_REPLAYING must not be stored in
the history, they are events created by the DIX to comply with the protocol.
Any such event should already be in the history anyway.

A fixme in this patch: we don't have a function to actually deliver the
event yet.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 dix/touch.c     |  104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/input.h |    4 ++
 2 files changed, 108 insertions(+), 0 deletions(-)

diff --git a/dix/touch.c b/dix/touch.c
index 5f895a0..78c50cf 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -35,6 +35,9 @@
 #include "eventstr.h"
 #include "exevents.h"
 
+#define TOUCH_HISTORY_SIZE 100
+
+
 /* If a touch queue resize is needed, the device id's bit is set. */
 static unsigned char resize_waiting[(MAXDEVICES + 7)/8];
 
@@ -393,6 +396,107 @@ TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
     ti->num_grabs = 0;
     ti->client_id = 0;
 
+    TouchEventHistoryFree(ti);
+
     valuator_mask_zero(ti->valuators);
 }
 
+/**
+ * Allocate the event history for this touch pointer. Calling this on a
+ * touchpoint that already has an event history does nothing but counts as
+ * as success.
+ *
+ * @return TRUE on success, FALSE on allocation errors
+ */
+Bool
+TouchEventHistoryAllocate(TouchPointInfoPtr ti)
+{
+    if (ti->history)
+        return TRUE;
+
+    ti->history = calloc(TOUCH_HISTORY_SIZE, sizeof(*ti->history));
+    ti->history_elements = 0;
+    if (ti->history)
+        ti->history_size = TOUCH_HISTORY_SIZE;
+    return ti->history != NULL;
+}
+
+void
+TouchEventHistoryFree(TouchPointInfoPtr ti)
+{
+    free(ti->history);
+    ti->history = NULL;
+    ti->history_size = 0;
+    ti->history_elements = 0;
+}
+
+/**
+ * Store the given event on the event history (if one exists)
+ * A touch event history consists of one TouchBegin and several TouchUpdate
+ * events (if applicable) but no TouchEnd event.
+ * If more than one TouchBegin is pushed onto the stack, the push is
+ * ignored, calling this function multiple times for the TouchBegin is
+ * valid.
+ */
+void
+TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev)
+{
+    if (!ti->history)
+        return;
+
+    switch(ev->type)
+    {
+        case ET_TouchBegin:
+            /* don't store the same touchbegin twice */
+            if (ti->history_elements > 0)
+                return;
+            break;
+        case ET_TouchUpdate:
+            break;
+        case ET_TouchEnd:
+            return; /* no TouchEnd events in the history */
+        default:
+            return;
+    }
+
+    /* We only store real events in the history */
+    if (ev->flags & (TOUCH_CLIENT_ID|TOUCH_REPLAYING))
+        return;
+
+    ti->history[ti->history_elements++] = *ev;
+    /* FIXME: proper overflow fixes */
+    ti->history_elements = min(ti->history_elements, ti->history_size - 1);
+}
+
+void
+TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
+{
+    InternalEvent *tel = InitEventList(GetMaximumEventsNum());
+    ValuatorMask *mask = valuator_mask_new(0);
+    int i, nev;
+    int flags;
+
+    if (!ti->history)
+        return;
+
+    valuator_mask_set_double(mask, 0, ti->history[0].valuators.data[0]);
+    valuator_mask_set_double(mask, 1, ti->history[0].valuators.data[1]);
+
+    flags = TOUCH_CLIENT_ID|TOUCH_REPLAYING;
+    if (ti->emulate_pointer)
+        flags |= TOUCH_POINTER_EMULATED;
+    /* send fake begin event to next owner */
+    nev = GetTouchEvents(tel, dev, ti->client_id, XI_TouchBegin, flags, mask);
+    /* FIXME: deliver the event */
+
+    valuator_mask_free(&mask);
+    FreeEventList(tel, GetMaximumEventsNum());
+
+    /* First event was TouchBegin, already replayed that one */
+    for (i = 1; i < ti->history_elements; i++)
+    {
+        DeviceEvent *ev = &ti->history[i];
+        ev->flags |= TOUCH_REPLAYING;
+        /* FIXME: deliver the event */
+    }
+}
diff --git a/include/input.h b/include/input.h
index 4d60792..8ce5f2b 100644
--- a/include/input.h
+++ b/include/input.h
@@ -607,6 +607,10 @@ extern TouchPointInfoPtr TouchBeginTouch(DeviceIntPtr dev, int sourceid,
 extern TouchPointInfoPtr TouchFindByClientID(DeviceIntPtr dev,
                                              uint32_t client_id);
 extern void TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti);
+extern Bool TouchEventHistoryAllocate(TouchPointInfoPtr ti);
+extern void TouchEventHistoryFree(TouchPointInfoPtr ti);
+extern void TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev);
+extern void TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource);
 
 /* misc event helpers */
 extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients);
-- 
1.7.7.1



More information about the xorg-devel mailing list