summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2011-12-20 16:34:43 -0800
committerChase Douglas <chase.douglas@canonical.com>2011-12-21 10:34:12 -0800
commitfaf720ea9e18fd239df677a2a57f7f5f61a07c45 (patch)
treebd4d96f840a265ee7bdbe4fe8e1c89fc78adab3e
parent9cca6418012ef81fc58c95e41f78c12d2a9e32ca (diff)
Xi: hook up touch ownership handling
Ownership changes don't get processed directly when they happen, instead the DIX submits an ownership event which goes through ProcessTouchEvents and ProcessTouchOwnershipEvents. Then on the required events are generated and sent to clients. Co-authored-by: Daniel Stone <daniel@fooishbar.org> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Chase Douglas <chase.douglas@canonical.com> Reviewed-by: Chase Douglas <chase.douglas@canonical.com>
-rw-r--r--Xi/exevents.c155
1 files changed, 154 insertions, 1 deletions
diff --git a/Xi/exevents.c b/Xi/exevents.c
index bbca8926d..f1598f750 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1089,6 +1089,159 @@ DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
}
/**
+ * If the current owner has rejected the event, deliver the
+ * TouchOwnership/TouchBegin to the next item in the sprite stack.
+ */
+static void
+TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti,
+ TouchOwnershipEvent *ev)
+{
+ InternalEvent *tel = InitEventList(GetMaximumEventsNum());
+ ValuatorMask *mask = valuator_mask_new(2);
+ int i, nev;
+
+ /* Deliver the ownership */
+ if (ti->listeners[0].state == LISTENER_AWAITING_OWNER)
+ DeliverTouchEvents(dev, ti, (InternalEvent*)ev, ti->listeners[0].listener);
+ else if (ti->listeners[0].state == LISTENER_AWAITING_BEGIN)
+ TouchEventHistoryReplay(ti, dev, ti->listeners[0].listener);
+
+ /* If we've just removed the last grab and the touch has physically
+ * ended, send a TouchEnd event too and finalise the touch. */
+ if (ti->num_listeners == 1 && ti->num_grabs == 0 &&
+ ti->pending_finish)
+ {
+ int flags;
+ valuator_mask_set_double(mask, 0,
+ valuator_mask_get_double(ti->valuators, 0));
+ valuator_mask_set_double(mask, 1,
+ valuator_mask_get_double(ti->valuators, 1));
+
+ flags = TOUCH_CLIENT_ID;
+ if (ti->emulate_pointer)
+ flags |= TOUCH_POINTER_EMULATED;
+ nev = GetTouchEvents(tel, dev, ti->client_id, XI_TouchEnd, flags, mask);
+ for (i = 0; i < nev; i++)
+ DeliverTouchEvents(dev, ti, tel + i, 0);
+ TouchEndTouch(dev, ti);
+ }
+
+ valuator_mask_free(&mask);
+ FreeEventList(tel, GetMaximumEventsNum());
+}
+
+static void
+TouchEventRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
+ TouchOwnershipEvent *ev)
+{
+ InternalEvent *tel = InitEventList(GetMaximumEventsNum());
+ ValuatorMask *mask = valuator_mask_new(2);
+ Bool was_owner = (ev->resource == ti->listeners[0].listener);
+ void *grab;
+ int nev, i;
+
+
+ /* Send a TouchEnd event to the resource being removed, but only if they
+ * haven't received one yet already */
+ if (ti->listeners[0].state != LISTENER_HAS_END)
+ {
+ int flags;
+ valuator_mask_set_double(mask, 0,
+ valuator_mask_get_double(ti->valuators, 0));
+ valuator_mask_set_double(mask, 1,
+ valuator_mask_get_double(ti->valuators, 1));
+
+ flags = TOUCH_CLIENT_ID|TOUCH_REJECT;
+ if (ti->emulate_pointer)
+ flags |= TOUCH_POINTER_EMULATED;
+ nev = GetTouchEvents(tel, sourcedev, ti->client_id, XI_TouchEnd, flags, mask);
+ for (i = 0; i < nev; i++)
+ DeliverTouchEvents(sourcedev, ti, tel + i, ev->resource);
+ }
+
+ /* If there are no other listeners left, then don't bother sending an
+ * ownership change event to no-one; if the touchpoint is pending
+ * finish, then we can just kill it now. */
+ if (ti->num_listeners == 1)
+ {
+ if (ti->pending_finish)
+ TouchEndTouch(sourcedev, ti);
+ goto out;
+ }
+
+ /* Remove the resource from the listener list, updating
+ * ti->num_listeners, as well as ti->num_grabs if it was a grab. */
+ if (TouchRemoveListener(ti, ev->resource))
+ {
+ if (dixLookupResourceByType(&grab, ev->resource, RT_PASSIVEGRAB,
+ serverClient, DixGetAttrAccess) == Success)
+ ti->num_grabs--;
+ }
+
+ /* If the current owner was removed, deliver the TouchOwnership or TouchBegin
+ event to the new owner. */
+ if (was_owner)
+ TouchPuntToNextOwner(sourcedev, ti, ev);
+
+out:
+ FreeEventList(tel, GetMaximumEventsNum());
+ valuator_mask_free(&mask);
+}
+
+/**
+ * Processes a TouchOwnership event, indicating a grab has accepted the touch
+ * it currently owns, or a grab or selection has been removed. Will generate
+ * and send TouchEnd events to all clients removed from the delivery list, as
+ * well as possibly sending the new TouchOwnership event. May end the
+ * touchpoint if it is pending finish.
+ */
+static void
+ProcessTouchOwnershipEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
+ TouchOwnershipEvent *ev)
+{
+
+ if (ev->reason == XIRejectTouch)
+ TouchEventRejected(dev, ti, ev);
+ else if (ev->reason == XIAcceptTouch) {
+ int flags;
+ int nev, i;
+ ValuatorMask *mask;
+
+ InternalEvent *tel = InitEventList(GetMaximumEventsNum());
+
+ mask = valuator_mask_new(dev->valuator->numAxes);
+ valuator_mask_set_double(mask, 0,
+ valuator_mask_get_double(ti->valuators, 0));
+ valuator_mask_set_double(mask, 1,
+ valuator_mask_get_double(ti->valuators, 1));
+
+ /* FIXME: what about early acceptance? a client may accept before it
+ * owns the touch. */
+
+ /* The touch owner has accepted the touch. Send TouchEnd events to
+ * everyone else, and truncate the list of listeners. */
+ flags = TOUCH_ACCEPT|TOUCH_CLIENT_ID;
+ if (ti->emulate_pointer)
+ flags |= TOUCH_POINTER_EMULATED;
+ nev = GetTouchEvents(tel, dev, ti->client_id, XI_TouchEnd,
+ flags, mask);
+ for (i = 0; i < nev; i++)
+ DeliverTouchEvents(dev, ti, tel + i, 0);
+
+ FreeEventList(tel, GetMaximumEventsNum());
+ valuator_mask_free(&mask);
+
+ while (ti->num_listeners > 1)
+ TouchRemoveListener(ti, ti->listeners[1].listener);
+ /* Owner accepted after receiving end */
+ if (ti->listeners[0].state == LISTENER_HAS_END)
+ TouchEndTouch(dev, ti);
+ } else { /* this is the very first ownership event for a grab */
+ DeliverTouchEvents(dev, ti, (InternalEvent*)ev, ev->resource);
+ }
+}
+
+/**
* Copy the event's valuator information into the touchpoint, we may need
* this for emulated TouchEnd events.
*/
@@ -1406,7 +1559,7 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
/* TouchOwnership events are handled separately from the rest, as they
* have more complex semantics. */
if (ev->any.type == ET_TouchOwnership)
- /* FIXME: process me! */;
+ ProcessTouchOwnershipEvent(dev, ti, &ev->touch_ownership_event);
else
{
TouchCopyValuatorData(&ev->device_event, ti);