[PATCH v2 34/42] Xi: hook up pointer emulation for emulating touches

Chase Douglas chase.douglas at canonical.com
Tue Dec 20 16:33:33 PST 2011


From: Peter Hutterer <peter.hutterer at who-t.net>

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 at who-t.net>
Reviewed-by: Chase Douglas <chase.douglas at canonical.com>
---
Sent on behalf of Peter to save time.

Changes to v1:
- Add comment to DeliverTouchEmulatedEvent for implicit grab processing

 Xi/exevents.c |  177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 176 insertions(+), 1 deletions(-)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index b5fc826..bbca892 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);
-- 
1.7.5.4



More information about the xorg-devel mailing list