[PATCH 06/29] Add support for XI2.3: Pointer barrier events and releases.

Peter Hutterer peter.hutterer at who-t.net
Tue Dec 11 23:18:59 PST 2012


From: "Jasper St. Pierre" <jstpierre at mecheye.net>

This adds support for clients that would like to get a notification
every time a barrier is hit, and allows clients to temporarily release
a barrier so that pointers can go through them, without having to
destroy and recreate barriers.

Based on work by Chris Halse Rogers <chris.halse.rogers at canonical.com>

Signed-off-by: Jasper St. Pierre <jstpierre at mecheye.net>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 Xi/exevents.c      |  32 ++++++++++++++++
 Xi/extinit.c       |  38 ++++++++++++++++++-
 Xi/xibarriers.c    | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 Xi/xibarriers.h    |   8 ++--
 dix/eventconvert.c |  39 +++++++++++++++++++
 include/events.h   |   1 +
 include/eventstr.h |  22 +++++++++++
 include/inputstr.h |   2 +-
 mi/mieq.c          |   4 ++
 9 files changed, 245 insertions(+), 8 deletions(-)

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 2caf98c..e606d9e 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1639,6 +1639,34 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
         UpdateDeviceState(dev, &ev->device_event);
 }
 
+static void
+ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
+{
+    Mask filter;
+    WindowPtr pWin;
+    BarrierEvent *be = &e->barrier_event;
+    xEvent *ev;
+    int rc;
+
+    if (!IsMaster(dev))
+        return;
+
+    if (dixLookupWindow(&pWin, be->window, serverClient, DixReadAccess) != Success)
+        return;
+
+    rc = EventToXI2(e, &ev);
+    if (rc != Success) {
+        ErrorF("[Xi] event conversion from %s failed with code %d\n", __func__, rc);
+        return;
+    }
+
+    filter = GetEventFilter(dev, ev);
+
+    DeliverEventsToWindow(dev, pWin, ev, 1,
+                          filter, NullGrab);
+    free(ev);
+}
+
 /**
  * Process DeviceEvents and DeviceChangedEvents.
  */
@@ -1788,6 +1816,10 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
     case ET_TouchEnd:
         ProcessTouchEvent(ev, device);
         break;
+    case ET_BarrierHit:
+    case ET_BarrierLeave:
+        ProcessBarrierEvent(ev, device);
+        break;
     default:
         ProcessDeviceEvent(ev, device);
         break;
diff --git a/Xi/extinit.c b/Xi/extinit.c
index 1074b23..175d89b 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -252,7 +252,8 @@ static int (*ProcIVector[]) (ClientPtr) = {
         ProcXIChangeProperty,   /* 57 */
         ProcXIDeleteProperty,   /* 58 */
         ProcXIGetProperty,      /* 59 */
-        ProcXIGetSelectedEvents /* 60 */
+        ProcXIGetSelectedEvents, /* 60 */
+        ProcXIBarrierReleasePointer /* 61 */
 };
 
 /* For swapped clients */
@@ -317,7 +318,8 @@ static int (*SProcIVector[]) (ClientPtr) = {
         SProcXIChangeProperty,  /* 57 */
         SProcXIDeleteProperty,  /* 58 */
         SProcXIGetProperty,     /* 59 */
-        SProcXIGetSelectedEvents        /* 60 */
+        SProcXIGetSelectedEvents,       /* 60 */
+        SProcXIBarrierReleasePointer /* 61 */
 };
 
 /*****************************************************************
@@ -840,6 +842,33 @@ STouchOwnershipEvent(xXITouchOwnershipEvent * from, xXITouchOwnershipEvent * to)
     swapl(&to->child);
 }
 
+static void
+SBarrierEvent(xXIBarrierEvent * from,
+              xXIBarrierEvent * to) {
+    to->type = from->type;
+
+    cpswapl(from->length, to->length);
+    cpswapl(from->time, to->time);
+    cpswaps(from->deviceid, to->deviceid);
+    cpswaps(from->sourceid, to->sourceid);
+    cpswapl(from->event, to->event);
+    cpswapl(from->root, to->root);
+    cpswapl(from->root_x, to->root_x);
+    cpswapl(from->root_y, to->root_y);
+
+#define SWAP_FP3232(x, y)                       \
+    do {                                        \
+        cpswapl((x).integral, (y).integral);    \
+        cpswapl((x).frac, (y).frac);            \
+    } while(0)
+
+    SWAP_FP3232(from->dx, to->dx);
+    SWAP_FP3232(from->dy, to->dy);
+    cpswapl(from->dtime, to->dtime);
+    cpswapl(from->barrier, to->barrier);
+    cpswapl(from->eventid, to->eventid);
+}
+
 /** Event swapping function for XI2 events. */
 void
 XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
@@ -886,6 +915,11 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
     case XI_RawTouchEnd:
         SRawEvent((xXIRawEvent *) from, (xXIRawEvent *) to);
         break;
+    case XI_BarrierHit:
+    case XI_BarrierLeave:
+        SBarrierEvent((xXIBarrierEvent *) from,
+                      (xXIBarrierEvent *) to);
+        break;
     default:
         ErrorF("[Xi] Unknown event type to swap. This is a bug.\n");
         break;
diff --git a/Xi/xibarriers.c b/Xi/xibarriers.c
index 0affde6..f16094d 100644
--- a/Xi/xibarriers.c
+++ b/Xi/xibarriers.c
@@ -56,6 +56,8 @@
 #include "xace.h"
 #include "list.h"
 #include "exglobals.h"
+#include "eventstr.h"
+#include "mi.h"
 
 RESTYPE PointerBarrierType;
 
@@ -66,11 +68,18 @@ static DevPrivateKeyRec BarrierScreenPrivateKeyRec;
 typedef struct PointerBarrierClient *PointerBarrierClientPtr;
 
 struct PointerBarrierClient {
+    XID id;
     ScreenPtr screen;
+    WindowPtr window;
     struct PointerBarrier barrier;
     struct xorg_list entry;
     int num_devices;
     int *device_ids; /* num_devices */
+    Time last_timestamp;
+    int barrier_event_id;
+    int release_event_id;
+    Bool hit;
+    Bool last_hit;
 };
 
 typedef struct _BarrierScreen {
@@ -315,6 +324,18 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
     int i;
     struct PointerBarrier *nearest = NULL;
     PointerBarrierClientPtr c;
+    Time ms = GetTimeInMillis();
+    BarrierEvent ev = {
+        .header = ET_Internal,
+        .type = 0,
+        .length = sizeof (BarrierEvent),
+        .time = ms,
+        .deviceid = dev->id,
+        .sourceid = dev->id,
+        .dx = dest_x - current_x,
+        .dy = dest_y - current_y,
+        .root = screen->root->drawable.id,
+    };
 
     if (xorg_list_is_empty(&cs->barriers) || IsFloating(dev))
         goto out;
@@ -336,6 +357,13 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
 
         nearest = &c->barrier;
 
+        c->seen = TRUE;
+        c->hit = TRUE;
+
+        if (c->barrier_event_id == c->release_event_id)
+            continue;
+
+        ev.type = ET_BarrierHit;
         barrier_clamp_to_barrier(nearest, dir, &x, &y);
 
         if (barrier_is_vertical(nearest)) {
@@ -346,6 +374,21 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
             dir &= ~(BarrierNegativeY | BarrierPositiveY);
             current_y = y;
         }
+
+        ev.flags = 0;
+        ev.event_id = c->barrier_event_id;
+        ev.barrierid = c->id;
+
+        ev.dt = ms - c->last_timestamp;
+        ev.window = c->window->drawable.id;
+        c->last_timestamp = ms;
+
+        mieqEnqueue(dev, (InternalEvent *) &ev);
+    }
+
+    xorg_list_for_each_entry(c, &cs->barriers, entry) {
+        c->last_hit = c->hit;
+        c->hit = FALSE;
     }
 
  out:
@@ -384,6 +427,7 @@ CreatePointerBarrierClient(ClientPtr client,
     cs = GetBarrierScreen(screen);
 
     ret->screen = screen;
+    ret->window = pWin;
     ret->num_devices = stuff->num_devices;
     if (ret->num_devices > 0)
         ret->device_ids = (int*)&ret[1];
@@ -410,6 +454,11 @@ CreatePointerBarrierClient(ClientPtr client,
         ret->device_ids[i] = device_id;
     }
 
+    ret->id = stuff->barrier;
+    ret->barrier_event_id = 0;
+    ret->release_event_id = 0;
+    ret->hit = FALSE;
+    ret->last_hit = FALSE;
     ret->barrier.x1 = min(stuff->x1, stuff->x2);
     ret->barrier.x2 = max(stuff->x1, stuff->x2);
     ret->barrier.y1 = min(stuff->y1, stuff->y2);
@@ -489,6 +538,64 @@ XIDestroyPointerBarrier(ClientPtr client,
     return Success;
 }
 
+int
+SProcXIBarrierReleasePointer(ClientPtr client)
+{
+    xXIBarrierReleasePointerInfo *info;
+    REQUEST(xXIBarrierReleasePointerReq);
+    int i;
+
+    info = (xXIBarrierReleasePointerInfo*) &stuff[1];
+
+    swaps(&stuff->length);
+    swapl(&stuff->num_barriers);
+    for (i = 0; i < stuff->num_barriers; i++, info++) {
+        swaps(&info->deviceid);
+        swapl(&info->barrier);
+        swapl(&info->eventid);
+    }
+
+    return (ProcXIBarrierReleasePointer(client));
+}
+
+int
+ProcXIBarrierReleasePointer(ClientPtr client)
+{
+    int i;
+    int err;
+    struct PointerBarrierClient *barrier;
+    struct PointerBarrier *b;
+    xXIBarrierReleasePointerInfo *info;
+
+    REQUEST(xXIBarrierReleasePointerReq);
+    REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq);
+
+    info = (xXIBarrierReleasePointerInfo*) &stuff[1];
+    for (i = 0; i < stuff->num_barriers; i++, info++) {
+        CARD32 barrier_id, event_id;
+        _X_UNUSED CARD32 device_id;
+
+        barrier_id = info->barrier;
+        event_id = info->eventid;
+
+        /* FIXME: per-device releases */
+        device_id = info->deviceid;
+
+        err = dixLookupResourceByType((void **) &b, barrier_id,
+                                      PointerBarrierType, client, DixReadAccess);
+        if (err != Success) {
+            client->errorValue = barrier_id;
+            return err;
+        }
+
+        barrier = container_of(b, struct PointerBarrierClient, barrier);
+        if (barrier->barrier_event_id == event_id)
+            barrier->release_event_id = event_id;
+    }
+
+    return Success;
+}
+
 Bool
 XIBarrierInit(void)
 {
diff --git a/Xi/xibarriers.h b/Xi/xibarriers.h
index 8f2993f..f29bb6c 100644
--- a/Xi/xibarriers.h
+++ b/Xi/xibarriers.h
@@ -39,9 +39,7 @@ XIDestroyPointerBarrier(ClientPtr client,
 Bool
 XIBarrierInit(void);
 
-#endif /* _XIBARRIERS_H_ */
-
-
-
-
+int SProcXIBarrierReleasePointer(ClientPtr client);
+int ProcXIBarrierReleasePointer(ClientPtr client);
 
+#endif /* _XIBARRIERS_H_ */
diff --git a/dix/eventconvert.c b/dix/eventconvert.c
index 2e422d7..bb5c8d3 100644
--- a/dix/eventconvert.c
+++ b/dix/eventconvert.c
@@ -57,6 +57,7 @@ static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count);
 static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce);
 static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
 static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
+static int eventToBarrierEvent(BarrierEvent *ev, xEvent **xi);
 static int eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi);
 
 /* Do not use, read comments below */
@@ -277,6 +278,9 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
     case ET_RawTouchUpdate:
     case ET_RawTouchEnd:
         return eventToRawEvent(&ev->raw_event, xi);
+    case ET_BarrierHit:
+    case ET_BarrierLeave:
+        return eventToBarrierEvent(&ev->barrier_event, xi);
     default:
         break;
     }
@@ -782,6 +786,35 @@ eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
     return Success;
 }
 
+static int
+eventToBarrierEvent(BarrierEvent *ev, xEvent **xi)
+{
+    xXIBarrierEvent *barrier;
+    int len = sizeof(xXIBarrierEvent);
+
+    *xi = calloc(1, len);
+    barrier = (xXIBarrierEvent*) *xi;
+    barrier->type = GenericEvent;
+    barrier->extension = IReqCode;
+    barrier->evtype = GetXI2Type(ev->type);
+    barrier->length = bytes_to_int32(len - sizeof(xEvent));
+    barrier->deviceid = ev->deviceid;
+    barrier->sourceid = ev->sourceid;
+    barrier->time = ev->time;
+    barrier->event = ev->window;
+    barrier->root = ev->root;
+    barrier->dx = double_to_fp3232(ev->dx);
+    barrier->dy = double_to_fp3232(ev->dy);
+    barrier->dtime = ev->dt;
+    barrier->flags = ev->flags;
+    barrier->eventid = ev->event_id;
+    barrier->barrier = ev->barrierid;
+    barrier->root_x = double_to_fp1616(ev->root_x);
+    barrier->root_y = double_to_fp1616(ev->root_y);
+
+    return Success;
+}
+
 /**
  * Return the corresponding core type for the given event or 0 if no core
  * equivalent exists.
@@ -929,6 +962,12 @@ GetXI2Type(enum EventType type)
     case ET_TouchOwnership:
         xi2type = XI_TouchOwnership;
         break;
+    case ET_BarrierHit:
+        xi2type = XI_BarrierHit;
+        break;
+    case ET_BarrierLeave:
+        xi2type = XI_BarrierLeave;
+        break;
     default:
         break;
     }
diff --git a/include/events.h b/include/events.h
index 222bf32..c0ef45d 100644
--- a/include/events.h
+++ b/include/events.h
@@ -27,6 +27,7 @@
 typedef struct _DeviceEvent DeviceEvent;
 typedef struct _DeviceChangedEvent DeviceChangedEvent;
 typedef struct _TouchOwnershipEvent TouchOwnershipEvent;
+typedef struct _BarrierEvent BarrierEvent;
 
 #if XFreeXDGA
 typedef struct _DGAEvent DGAEvent;
diff --git a/include/eventstr.h b/include/eventstr.h
index eddba87..38fab4f 100644
--- a/include/eventstr.h
+++ b/include/eventstr.h
@@ -72,6 +72,8 @@ enum EventType {
     ET_RawTouchUpdate,
     ET_RawTouchEnd,
     ET_XQuartz,
+    ET_BarrierHit,
+    ET_BarrierLeave,
     ET_Internal = 0xFF          /* First byte */
 };
 
@@ -227,6 +229,25 @@ struct _RawDeviceEvent {
     uint32_t flags;       /**< Flags to be copied into the generated event */
 };
 
+struct _BarrierEvent {
+    unsigned char header; /**<  Always ET_Internal */
+    enum EventType type;  /**<  ET_BarrierHit, ET_BarrierLeave */
+    int length;           /**<  Length in bytes */
+    Time time;            /**<  Time in ms */
+    int deviceid;         /**< Device to post this event for */
+    int sourceid;         /**< The physical source device */
+    int barrierid;
+    Window window;
+    Window root;
+    double dx;
+    double dy;
+    double root_x;
+    double root_y;
+    int16_t dt;
+    int32_t event_id;
+    uint32_t flags;
+};
+
 #ifdef XQUARTZ
 #define XQUARTZ_EVENT_MAXARGS 5
 struct _XQuartzEvent {
@@ -253,6 +274,7 @@ union _InternalEvent {
     DeviceEvent device_event;
     DeviceChangedEvent changed_event;
     TouchOwnershipEvent touch_ownership_event;
+    BarrierEvent barrier_event;
 #if XFreeXDGA
     DGAEvent dga_event;
 #endif
diff --git a/include/inputstr.h b/include/inputstr.h
index bb0a779..17cee98 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -71,7 +71,7 @@ extern _X_EXPORT int CountBits(const uint8_t * mask, int len);
  * events to the protocol, the server will not support these events until
  * this number here is bumped.
  */
-#define XI2LASTEVENT    XI_RawTouchEnd
+#define XI2LASTEVENT    XI_BarrierLeave
 #define XI2MASKSIZE     ((XI2LASTEVENT >> 3) + 1)       /* no of bytes for masks */
 
 /**
diff --git a/mi/mieq.c b/mi/mieq.c
index b2c7769..22f8c91 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -407,6 +407,10 @@ ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
     case ET_RawTouchUpdate:
         event->raw_event.deviceid = dev->id;
         break;
+    case ET_BarrierHit:
+    case ET_BarrierLeave:
+        event->barrier_event.deviceid = dev->id;
+        break;
     default:
         ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
                event->any.type);
-- 
1.8.0.1



More information about the xorg-devel mailing list