summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2011-12-20 16:33:33 -0800
committerPeter Hutterer <peter.hutterer@who-t.net>2011-12-21 12:38:36 +1000
commit1894468c2b9788efa70ef4fb5fc911711402f3a7 (patch)
tree23d2eb6b18098c03ddaf6a2554095d20fe187869
parent753c4dca1e42035e29fb21458a746e484ed93ca3 (diff)
Xi: hook up pointer emulation for emulating touches
Includes a hack for implicit grab activation, because integrating this requires a larger rewrite and I'm not sleeping enough as it is. Right now, we deliver the event and check before/after if there is an implicit grab on. If one activated, then store the event in the grab and switch the listener type to a grab listener. 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.c177
1 files changed, 176 insertions, 1 deletions
diff --git a/Xi/exevents.c b/Xi/exevents.c
index b5fc82689..bbca8926d 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1203,6 +1203,153 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
return TRUE;
}
+static int
+DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
+ TouchListener *listener, ClientPtr client,
+ WindowPtr win, GrabPtr grab, XI2Mask *xi2mask)
+{
+ InternalEvent motion, button;
+ InternalEvent *ptrev = &motion;
+ int nevents;
+ DeviceIntPtr kbd;
+
+ /* We don't deliver pointer events to non-owners */
+ if (!TouchResourceIsOwner(ti, listener->listener))
+ return Success;
+
+ nevents = TouchConvertToPointerEvent(ev, &motion, &button);
+ BUG_WARN(nevents == 0);
+ if (nevents == 0)
+ return BadValue;
+
+ if (nevents > 1)
+ ptrev = &button;
+
+ kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
+ event_set_state(dev, kbd, &ptrev->device_event);
+ ptrev->device_event.corestate = event_get_corestate(dev, kbd);
+
+ if (grab)
+ {
+ /* this side-steps the usual activation mechansims, but... */
+ if (ev->any.type == ET_TouchBegin)
+ ActivatePassiveGrab(dev, grab, ptrev, ev); /* also delivers the event */
+ else {
+ int deliveries = 0;
+ /* 'grab' is the passive grab, but if the grab isn't active,
+ * don't deliver */
+ if (!dev->deviceGrab.grab)
+ return Success;
+
+ if (grab->ownerEvents)
+ {
+ WindowPtr focus = NullWindow;
+ WindowPtr win = dev->spriteInfo->sprite->win;
+ deliveries = DeliverDeviceEvents(win, ptrev, grab, focus, dev);
+ }
+
+ if (!deliveries)
+ DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype);
+
+ if (ev->any.type == ET_TouchEnd &&
+ !dev->button->buttonsDown &&
+ dev->deviceGrab.fromPassiveGrab &&
+ GrabIsPointerGrab(grab))
+ (*dev->deviceGrab.DeactivateGrab)(dev);
+ }
+ } else
+ {
+ GrabPtr devgrab = dev->deviceGrab.grab;
+
+ DeliverDeviceEvents(win, ptrev, grab, win, dev);
+ /* FIXME: bad hack
+ * Implicit passive grab activated in response to this event. Store
+ * the event.
+ */
+ if (!devgrab && dev->deviceGrab.grab && dev->deviceGrab.implicitGrab)
+ {
+ TouchListener *listener;
+
+ devgrab = dev->deviceGrab.grab;
+
+ *dev->deviceGrab.sync.event = ev->device_event;
+
+ /* The listener array has a sequence of grabs and then one event
+ * selection. Implicit grab activation occurs through delivering an
+ * event selection. Thus, we update the last listener in the array.
+ */
+ listener = &ti->listeners[ti->num_listeners - 1];
+ listener->listener = devgrab->resource;
+
+ if (devgrab->grabtype != XI2 ||
+ devgrab->type != XI_TouchBegin)
+ listener->type = LISTENER_POINTER_GRAB;
+ else
+ listener->type = LISTENER_GRAB;
+ }
+
+ }
+ if (ev->any.type == ET_TouchBegin)
+ listener->state = LISTENER_IS_OWNER;
+ else if (ev->any.type == ET_TouchEnd)
+ listener->state = LISTENER_HAS_END;
+
+ return Success;
+}
+
+
+
+
+static void
+DeliverEmulatedMotionEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
+ InternalEvent *ev)
+{
+ InternalEvent motion;
+
+ if (ti->num_listeners)
+ {
+ ClientPtr client;
+ WindowPtr win;
+ GrabPtr grab;
+ XI2Mask *mask;
+
+ if (ti->listeners[0].type != LISTENER_POINTER_REGULAR ||
+ ti->listeners[0].type != LISTENER_POINTER_GRAB)
+ return;
+
+ motion = *ev;
+ motion.any.type = ET_TouchUpdate;
+ motion.device_event.detail.button = 0;
+
+ if (!RetrieveTouchDeliveryData(dev, ti, &motion,
+ &ti->listeners[0], &client, &win, &grab,
+ &mask))
+ return;
+
+ /* There may be a pointer grab on the device */
+ if (!grab)
+ {
+ grab = dev->deviceGrab.grab;
+ if (grab)
+ {
+ win = grab->window;
+ mask = grab->xi2mask;
+ client = rClient(grab);
+ }
+ }
+
+ DeliverTouchEmulatedEvent(dev, ti, &motion, &ti->listeners[0], client, win, grab, mask);
+ } else {
+ InternalEvent button;
+ int converted;
+ converted = TouchConvertToPointerEvent(ev, &motion, &button);
+
+ BUG_WARN(converted == 0);
+ if (converted)
+ ProcessOtherEvent(&motion, dev);
+ }
+}
+
/**
* Processes and delivers a TouchBegin, TouchUpdate, or a
* TouchEnd event.
@@ -1241,6 +1388,12 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
return;
}
+
+ /* if emulate_pointer is set, emulate the motion event right
+ * here, so we can ignore it for button event emulation. TouchUpdate
+ * events which _only_ emulate motion just work normally */
+ if (emulate_pointer && ev->any.type != ET_TouchUpdate)
+ DeliverEmulatedMotionEvent(dev, ti, ev);
if (emulate_pointer && IsMaster(dev))
CheckMotion(&ev->device_event, dev);
@@ -1436,6 +1589,15 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev
int rc = Success;
Bool has_ownershipmask;
+ if (listener->type == LISTENER_POINTER_REGULAR ||
+ listener->type == LISTENER_POINTER_GRAB)
+ {
+ rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
+ grab, xi2mask);
+ goto out;
+ }
+
+
has_ownershipmask = xi2mask_isset(xi2mask, dev, XI_TouchOwnership);
if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
@@ -1454,6 +1616,7 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev
}
listener->state = state;
+out:
return rc;
}
@@ -1464,6 +1627,14 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
{
int rc = Success;
+ if (listener->type == LISTENER_POINTER_REGULAR ||
+ listener->type == LISTENER_POINTER_GRAB)
+ {
+ rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win,
+ grab, xi2mask);
+ goto out;
+ }
+
/* Event in response to reject */
if (ev->device_event.flags & TOUCH_REJECT)
{
@@ -1488,6 +1659,7 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
}
}
+out:
return rc;
}
@@ -1517,7 +1689,10 @@ DeliverTouchEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
rc = DeliverTouchBeginEvent(dev, ti, ev, listener, client, win, grab, xi2mask);
} else if (ev->any.type == ET_TouchUpdate)
{
- if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
+ if (listener->type == LISTENER_POINTER_REGULAR ||
+ listener->type == LISTENER_POINTER_GRAB)
+ DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win, grab, xi2mask);
+ else if (TouchResourceIsOwner(ti, listener->listener) || has_ownershipmask)
rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev);
} else if (ev->any.type == ET_TouchEnd)
rc = DeliverTouchEndEvent(dev, ti, ev, listener, client, win, grab, xi2mask);