[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