Add support for XI2.3: Pointer barrier events and releases.

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@canonical.com>

Signed-off-by: Jasper St. Pierre <jstpierre@mecheye.net>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Jasper St. Pierre 2012-11-01 16:06:40 -04:00 committed by Peter Hutterer
parent 85a37ddcc2
commit e130a46ab4
9 changed files with 245 additions and 8 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)
{

View File

@ -39,9 +39,7 @@ XIDestroyPointerBarrier(ClientPtr client,
Bool
XIBarrierInit(void);
int SProcXIBarrierReleasePointer(ClientPtr client);
int ProcXIBarrierReleasePointer(ClientPtr client);
#endif /* _XIBARRIERS_H_ */

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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 */
/**

View File

@ -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);