summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2011-12-14 16:24:17 +1000
committerChase Douglas <chase.douglas@canonical.com>2011-12-21 10:34:12 -0800
commitc7de6457de604075582416d878b95da0ba188f89 (patch)
tree87f8b5f3cb47e0ade911ad0299e388b8469ac227
parent21609c8a18586be6e35955510f880fdc13643a5d (diff)
dix: add helper functions for adding/removing touch listeners
The DIX will call TouchSetupListeners once for a new touch. After that the listener list remains static, with listeners only dropping out when they either reject the grab or disappear. Exception: if grabs activate they are prefixed to the listeners. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Chase Douglas <chase.douglas@canonical.com>
-rw-r--r--dix/touch.c223
-rw-r--r--include/input.h5
2 files changed, 227 insertions, 1 deletions
diff --git a/dix/touch.c b/dix/touch.c
index 2647ca4be..7207fd680 100644
--- a/dix/touch.c
+++ b/dix/touch.c
@@ -34,6 +34,9 @@
#include "eventstr.h"
#include "exevents.h"
+#include "inpututils.h"
+#include "eventconvert.h"
+#include "windowstr.h"
#define TOUCH_HISTORY_SIZE 100
@@ -614,3 +617,223 @@ TouchGetPointerEventType(const InternalEvent *event)
return type;
}
+
+/**
+ * Add the resource to this touch's listeners.
+ */
+void
+TouchAddListener(TouchPointInfoPtr ti, XID resource, enum InputLevel level,
+ enum TouchListenerType type, enum TouchListenerState state)
+{
+ ti->listeners[ti->num_listeners].listener = resource;
+ ti->listeners[ti->num_listeners].level = level;
+ ti->listeners[ti->num_listeners].state = state;
+ ti->listeners[ti->num_listeners].type = type;
+ ti->num_listeners++;
+}
+
+/**
+ * Remove the resource from this touch's listeners.
+ *
+ * @return TRUE if the resource was removed, FALSE if the resource was not
+ * in the list
+ */
+Bool
+TouchRemoveListener(TouchPointInfoPtr ti, XID resource)
+{
+ int i;
+ for (i = 0; i < ti->num_listeners; i++)
+ {
+ if (ti->listeners[i].listener == resource)
+ {
+ int j;
+ for (j = i; j< ti->num_listeners - 1; j++)
+ ti->listeners[j] = ti->listeners[j + 1];
+ ti->num_listeners--;
+ ti->listeners[ti->num_listeners].listener = 0;
+ ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+TouchAddGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
+ InternalEvent *ev, GrabPtr grab)
+{
+ enum TouchListenerType type = LISTENER_GRAB;
+
+ /* FIXME: owner_events */
+
+ if (grab->grabtype == XI2)
+ {
+ if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchOwnership))
+ TouchEventHistoryAllocate(ti);
+ if (!xi2mask_isset(grab->xi2mask, dev, XI_TouchBegin))
+ type = LISTENER_POINTER_GRAB;
+ } else if (grab->grabtype == XI || grab->grabtype == CORE)
+ {
+ TouchEventHistoryAllocate(ti);
+ type = LISTENER_POINTER_GRAB;
+ }
+
+ TouchAddListener(ti, grab->resource, grab->grabtype,
+ type, LISTENER_AWAITING_BEGIN);
+ ti->num_grabs++;
+}
+
+/**
+ * Add one listener if there is a grab on the given window.
+ */
+static void
+TouchAddPassiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
+ WindowPtr win, InternalEvent *ev)
+{
+ GrabPtr grab;
+ Bool check_core = IsMaster(dev) && ti->emulate_pointer;
+
+ /* FIXME: make CheckPassiveGrabsOnWindow only trigger on TouchBegin */
+ grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core, FALSE);
+ if (!grab)
+ return;
+
+ TouchAddGrabListener(dev, ti, ev, grab);
+}
+
+static Bool
+TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
+ WindowPtr win, InternalEvent *ev)
+{
+ InputClients *iclients = NULL;
+ OtherInputMasks *inputMasks = NULL;
+ uint16_t evtype = 0; /* may be event type or emulated event type */
+ enum TouchListenerType type = LISTENER_REGULAR;
+ int mask;
+
+ evtype = GetXI2Type(ev->any.type);
+ mask = EventIsDeliverable(dev, ev->any.type, win);
+ if (!mask && !ti->emulate_pointer)
+ return FALSE;
+ else if (!mask)/* now try for pointer event */
+ {
+ mask = EventIsDeliverable(dev, TouchGetPointerEventType(ev), win);
+ if (mask)
+ {
+ evtype = GetXI2Type(TouchGetPointerEventType(ev));
+ type = LISTENER_POINTER_REGULAR;
+ }
+ }
+ if (!mask)
+ return FALSE;
+
+ inputMasks = wOtherInputMasks(win);
+
+ if (mask & EVENT_XI2_MASK)
+ {
+ nt_list_for_each_entry(iclients, inputMasks->inputClients, next)
+ {
+ if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
+ continue;
+
+ if (!xi2mask_isset(iclients->xi2mask, dev, XI_TouchOwnership))
+ TouchEventHistoryAllocate(ti);
+
+ TouchAddListener(ti, iclients->resource, XI2,
+ type, LISTENER_AWAITING_BEGIN);
+ return TRUE;
+ }
+ }
+
+ if (mask & EVENT_XI1_MASK)
+ {
+ int xitype = GetXIType(TouchGetPointerEventType(ev));
+ Mask xi_filter = event_get_filter_from_type(dev, xitype);
+ nt_list_for_each_entry(iclients, inputMasks->inputClients, next)
+ {
+ if (!(iclients->mask[dev->id] & xi_filter))
+ continue;
+
+ TouchEventHistoryAllocate(ti);
+ TouchAddListener(ti, iclients->resource, XI,
+ LISTENER_POINTER_REGULAR, LISTENER_AWAITING_BEGIN);
+ return TRUE;
+ }
+ }
+
+ if (mask & EVENT_CORE_MASK)
+ {
+ int coretype = GetCoreType(TouchGetPointerEventType(ev));
+ Mask core_filter = event_get_filter_from_type(dev, coretype);
+
+ /* window owner */
+ if (IsMaster(dev) && (win->eventMask & core_filter))
+ {
+ TouchEventHistoryAllocate(ti);
+ TouchAddListener(ti, win->drawable.id, CORE,
+ LISTENER_POINTER_REGULAR, LISTENER_AWAITING_BEGIN);
+ return TRUE;
+ }
+
+ /* all others */
+ nt_list_for_each_entry(iclients, (InputClients*)wOtherClients(win), next)
+ {
+ if (!(iclients->mask[XIAllDevices] & core_filter))
+ continue;
+
+ TouchEventHistoryAllocate(ti);
+ TouchAddListener(ti, iclients->resource, CORE,
+ type, LISTENER_AWAITING_BEGIN);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+TouchAddActiveGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
+ InternalEvent *ev, GrabPtr grab)
+{
+ if (!ti->emulate_pointer &&
+ (grab->grabtype == CORE || grab->grabtype == XI))
+ return;
+
+ if (!ti->emulate_pointer &&
+ grab->grabtype == XI2 &&
+ (grab->type != XI_TouchBegin && grab->type != XI_TouchEnd && grab->type != XI_TouchUpdate))
+ return;
+
+ TouchAddGrabListener(dev, ti, ev, grab);
+}
+
+void
+TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
+{
+ int i;
+ SpritePtr sprite = &ti->sprite;
+ WindowPtr win;
+
+ if (dev->deviceGrab.grab)
+ TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab);
+
+ /* First, find all grabbing clients from the root window down
+ * to the deepest child window. */
+ for (i = 0; i < sprite->spriteTraceGood; i++)
+ {
+ win = sprite->spriteTrace[i];
+ TouchAddPassiveGrabListener(dev, ti, win, ev);
+ }
+
+ /* Find the first client with an applicable event selection,
+ * going from deepest child window back up to the root window. */
+ for (i = sprite->spriteTraceGood - 1; i >= 0; i--)
+ {
+ Bool delivered;
+
+ win = sprite->spriteTrace[i];
+ delivered = TouchAddRegularListener(dev, ti, win, ev);
+ if (delivered)
+ return;
+ }
+}
diff --git a/include/input.h b/include/input.h
index 84d1d4352..a6de82458 100644
--- a/include/input.h
+++ b/include/input.h
@@ -611,7 +611,10 @@ 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);
-
+extern void TouchAddListener(TouchPointInfoPtr ti, XID resource, enum InputLevel level,
+ enum TouchListenerType type, enum TouchListenerState state);
+extern Bool TouchRemoveListener(TouchPointInfoPtr ti, XID resource);
+extern void TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev);
extern Bool TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
InternalEvent *ev);
extern Bool TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite);