summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);