[PATCH 3/5] Add support for XI2.3: Pointer barrier notify events
Jasper St. Pierre
jstpierre at mecheye.net
Tue Nov 20 11:50:43 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 released, along with a way to temporarily
release a barrier after it has been hit.
This adds two new events to XI: BarrierHitNotify and
BarrierPointerReleasedNotify.
Based on work by Chris Halse Rogers <chris.halse.rogers at canonical.com>
Signed-off-by: Jasper St. Pierre <jstpierre at mecheye.net>
---
Xi/exevents.c | 43 ++++++++++++++++++
Xi/extinit.c | 32 ++++++++++++++
Xi/xibarriers.c | 98 ++++++++++++++++++++++++++++++++++--------
Xi/xibarriers.h | 1 +
dix/getevents.c | 4 +-
hw/xfree86/modes/xf86RandR12.c | 4 +-
include/events.h | 1 +
include/eventstr.h | 22 ++++++++++
include/inputstr.h | 2 +-
include/protocol-versions.h | 2 +-
include/scrnintstr.h | 2 +-
mi/mieq.c | 3 ++
mi/mipointer.c | 12 ++++--
mi/mipointer.h | 4 +-
randr/randrstr.h | 2 +-
randr/rrcrtc.c | 4 +-
16 files changed, 204 insertions(+), 32 deletions(-)
diff --git a/Xi/exevents.c b/Xi/exevents.c
index 4248b9a..98a2cee 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1649,6 +1649,46 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
UpdateDeviceState(dev, &ev->device_event);
}
+#define INT_TO_FP3232(x) ((FP3232) { (x), 0 })
+
+static void
+ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
+{
+ Mask filter;
+ WindowPtr pWin;
+ BarrierEvent *be = &e->barrier_event;
+ xXIBarrierNotifyEvent ev = {
+ .type = GenericEvent,
+ .extension = IReqCode,
+ .sequenceNumber = 0,
+ .length = 9,
+ .evtype = be->event_type,
+ .window = be->window,
+ .deviceid = dev->id,
+ .time = be->time,
+ .x = be->x,
+ .y = be->y,
+ .dx = INT_TO_FP3232(be->dx),
+ .dy = INT_TO_FP3232(be->dy),
+ .raw_dx = INT_TO_FP3232(be->raw_dx),
+ .raw_dy = INT_TO_FP3232(be->raw_dy),
+ .dt = be->dt,
+ .event_id = be->event_id,
+ .barrier = be->barrierid,
+ };
+
+ if (!IsMaster(dev))
+ return;
+
+ if (dixLookupWindow(&pWin, be->window, serverClient, DixReadAccess) != Success)
+ return;
+
+ filter = GetEventFilter(dev, (xEvent *) &ev);
+
+ DeliverEventsToWindow(dev, pWin, (xEvent *) &ev, 1,
+ filter, NullGrab);
+}
+
/**
* Process DeviceEvents and DeviceChangedEvents.
*/
@@ -1798,6 +1838,9 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
case ET_TouchEnd:
ProcessTouchEvent(ev, device);
break;
+ case ET_BarrierNotify:
+ ProcessBarrierEvent(ev, device);
+ break;
default:
ProcessDeviceEvent(ev, device);
break;
diff --git a/Xi/extinit.c b/Xi/extinit.c
index 1074b23..6571943 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -840,6 +840,33 @@ STouchOwnershipEvent(xXITouchOwnershipEvent * from, xXITouchOwnershipEvent * to)
swapl(&to->child);
}
+static void
+SBarrierNotifyEvent(xXIBarrierNotifyEvent * from,
+ xXIBarrierNotifyEvent * to) {
+ to->type = from->type;
+
+ cpswaps(from->x, to->x);
+ cpswaps(from->y, to->y);
+ cpswaps(from->dt, to->dt);
+ cpswapl(from->length, to->length);
+ cpswapl(from->time, to->time);
+
+ cpswaps(from->event_id, to->event_id);
+ cpswapl(from->barrier, to->barrier);
+ cpswapl(from->window, to->window);
+
+#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);
+ SWAP_FP3232(from->raw_dx, to->raw_dx);
+ SWAP_FP3232(from->raw_dy, to->raw_dy);
+}
+
/** Event swapping function for XI2 events. */
void
XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
@@ -886,6 +913,11 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
case XI_RawTouchEnd:
SRawEvent((xXIRawEvent *) from, (xXIRawEvent *) to);
break;
+ case XI_BarrierHitNotify:
+ case XI_BarrierPointerReleasedNotify:
+ SBarrierNotifyEvent((xXIBarrierNotifyEvent *) from,
+ (xXIBarrierNotifyEvent *) 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 a97db56..9b5f657 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;
@@ -67,10 +69,16 @@ typedef struct PointerBarrierClient *PointerBarrierClientPtr;
struct PointerBarrierClient {
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 {
@@ -241,7 +249,7 @@ barrier_blocks_device(struct PointerBarrierClient *client,
}
/**
- * Find the nearest barrier that is blocking movement from x1/y1 to x2/y2.
+ * Find the nearest barrier client that is blocking movement from x1/y1 to x2/y2.
*
* @param dir Only barriers blocking movement in direction dir are checked
* @param x1 X start coordinate of movement vector
@@ -250,13 +258,12 @@ barrier_blocks_device(struct PointerBarrierClient *client,
* @param y2 Y end coordinate of movement vector
* @return The barrier nearest to the movement origin that blocks this movement.
*/
-static struct PointerBarrier *
+static struct PointerBarrierClient *
barrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev,
int dir,
int x1, int y1, int x2, int y2)
{
- struct PointerBarrierClient *c;
- struct PointerBarrier *nearest = NULL;
+ struct PointerBarrierClient *c, *nearest = NULL;
double min_distance = INT_MAX; /* can't get higher than that in X anyway */
xorg_list_for_each_entry(c, &cs->barriers, entry) {
@@ -272,7 +279,7 @@ barrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev,
if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) {
if (min_distance > distance) {
min_distance = distance;
- nearest = b;
+ nearest = c;
}
}
}
@@ -308,16 +315,26 @@ barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x,
static void
BarrierConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode,
- int *x, int *y)
+ int *x, int *y, int unclamped_x, int unclamped_y)
{
BarrierScreenPtr cs = GetBarrierScreen(screen);
if (!xorg_list_is_empty(&cs->barriers) && !IsFloating(dev) &&
mode == Relative) {
int ox, oy;
+ int dx, dy;
int dir;
- int i;
struct PointerBarrier *nearest = NULL;
+ PointerBarrierClientPtr c;
+ Time ms = GetTimeInMillis();
+ BarrierEvent ev = {
+ .header = ET_Internal,
+ .type = ET_BarrierNotify,
+ .length = sizeof (BarrierEvent),
+ .time = ms,
+ .deviceid = dev->id,
+ .sourceid = dev->id,
+ };
/* where are we coming from */
miPointerGetPosition(dev, &ox, &oy);
@@ -330,29 +347,68 @@ BarrierConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode,
* destination, again finding the nearest barrier and clamping.
*/
dir = barrier_get_direction(ox, oy, *x, *y);
+ dx = unclamped_x - ox;
+ dy = unclamped_y - oy;
#define MAX_BARRIERS 2
for (i = 0; i < MAX_BARRIERS; i++) {
- nearest = barrier_find_nearest(cs, dev, dir, ox, oy, *x, *y);
- if (!nearest)
+ c = barrier_find_nearest(cs, dev, dir, ox, oy, *x, *y);
+ if (!c)
break;
- barrier_clamp_to_barrier(nearest, dir, x, y);
+ nearest = &c->barrier;
- if (barrier_is_vertical(nearest)) {
- dir &= ~(BarrierNegativeX | BarrierPositiveX);
- ox = *x;
+ if (!c->last_hit) {
+ /* This is the start of a new barrier event */
+ c->barrier_event_id++;
}
- else if (barrier_is_horizontal(nearest)) {
- dir &= ~(BarrierNegativeY | BarrierPositiveY);
- oy = *y;
+
+ if (c->barrier_event_id == c->release_event_id) {
+ ev.event_type = XI_BarrierPointerReleasedNotify;
+ } else {
+ ev.event_type = XI_BarrierHitNotify;
+
+ barrier_clamp_to_barrier(nearest, dir, x, y);
+ c->hit = TRUE;
+
+ if (barrier_is_vertical(nearest)) {
+ dir &= ~(BarrierNegativeX | BarrierPositiveX);
+ ox = *x;
+ }
+ else if (barrier_is_horizontal(nearest)) {
+ dir &= ~(BarrierNegativeY | BarrierPositiveY);
+ oy = *y;
+ }
}
+
+ ev.event_id = c->barrier_event_id;
+ ev.barrierid = nearest->id;
+
+ ev.x = *x;
+ ev.y = *y;
+ ev.dx = dx;
+ ev.dy = dy;
+
+ /* FIXME: add proper raw dx/dy */
+ ev.raw_dx = dx;
+ ev.raw_dy = dy;
+
+ 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;
}
}
if (cs->ConstrainCursorHarder) {
screen->ConstrainCursorHarder = cs->ConstrainCursorHarder;
- screen->ConstrainCursorHarder(dev, screen, mode, x, y);
+ screen->ConstrainCursorHarder(dev, screen, mode, x, y, unclamped_x, unclamped_y);
screen->ConstrainCursorHarder = BarrierConstrainCursorHarder;
}
}
@@ -378,7 +434,7 @@ CreatePointerBarrierClient(ClientPtr client,
return BadAlloc;
}
- err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
+ err = dixLookupWindow(&pWin, stuff->window, client, DixSendAccess);
if (err != Success) {
client->errorValue = stuff->window;
goto error;
@@ -388,6 +444,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];
@@ -414,6 +471,11 @@ CreatePointerBarrierClient(ClientPtr client,
ret->device_ids[i] = device_id;
}
+ ret->barrier.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);
diff --git a/Xi/xibarriers.h b/Xi/xibarriers.h
index 8f2993f..91a0756 100644
--- a/Xi/xibarriers.h
+++ b/Xi/xibarriers.h
@@ -11,6 +11,7 @@
extern _X_EXPORT RESTYPE PointerBarrierType;
struct PointerBarrier {
+ XID id;
CARD16 x1, x2, y1, y2;
CARD32 directions;
};
diff --git a/dix/getevents.c b/dix/getevents.c
index 2a686e8..6f17534 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -933,7 +933,9 @@ positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
/* miPointerSetPosition takes care of crossing screens for us, as well as
* clipping to the current screen. Coordinates returned are in desktop
* coord system */
- scr = miPointerSetPosition(dev, mode, screenx, screeny);
+ scr = miPointerSetPosition(dev, mode, screenx, screeny,
+ (int)floor(*screenx) - scr->x,
+ (int)floor(*screeny) - scr->y);
/* If we were constrained, rescale x/y from the screen coordinates so
* the device valuators reflect the correct position. For screen
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index 3530abf..55cfbd9 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1871,7 +1871,7 @@ xf86CrtcSetScanoutPixmap(RRCrtcPtr randr_crtc, PixmapPtr pixmap)
}
static void
-xf86RandR13ConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, int *x, int *y)
+xf86RandR13ConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, int *x, int *y, int unclamped_x, int unclamped_y)
{
XF86RandRInfoPtr randrp = XF86RANDRINFO(screen);
@@ -1880,7 +1880,7 @@ xf86RandR13ConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, i
if (randrp->orig_ConstrainCursorHarder) {
screen->ConstrainCursorHarder = randrp->orig_ConstrainCursorHarder;
- screen->ConstrainCursorHarder(dev, screen, mode, x, y);
+ screen->ConstrainCursorHarder(dev, screen, mode, x, y, unclamped_x, unclamped_y);
screen->ConstrainCursorHarder = xf86RandR13ConstrainCursorHarder;
}
}
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 dd6fbef..176bac0 100644
--- a/include/eventstr.h
+++ b/include/eventstr.h
@@ -72,6 +72,7 @@ enum EventType {
ET_RawTouchUpdate,
ET_RawTouchEnd,
ET_XQuartz,
+ ET_BarrierNotify,
ET_Internal = 0xFF /* First byte */
};
@@ -227,6 +228,26 @@ 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_BarrierNotify */
+ 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;
+ int16_t x;
+ int16_t y;
+ int32_t dx;
+ int32_t dy;
+ int32_t raw_dx;
+ int32_t raw_dy;
+ int16_t dt;
+ int16_t event_type;
+ int32_t event_id;
+};
+
#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 5a38924..e4240c9 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_BarrierPointerReleasedNotify
#define XI2MASKSIZE ((XI2LASTEVENT >> 3) + 1) /* no of bytes for masks */
/**
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index cb8e213..10f5117 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -127,7 +127,7 @@
/* X Input */
#define SERVER_XI_MAJOR_VERSION 2
-#define SERVER_XI_MINOR_VERSION 2
+#define SERVER_XI_MINOR_VERSION 3
/* XKB */
#define SERVER_XKB_MAJOR_VERSION 1
diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index df74073..095b029 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -339,7 +339,7 @@ typedef void (*DeviceCursorCleanupProcPtr) (DeviceIntPtr /* pDev */ ,
ScreenPtr /* pScreen */ );
typedef void (*ConstrainCursorHarderProcPtr) (DeviceIntPtr, ScreenPtr, int,
- int *, int *);
+ int *, int *, int, int);
typedef Bool (*SharePixmapBackingProcPtr)(PixmapPtr, ScreenPtr, void **);
diff --git a/mi/mieq.c b/mi/mieq.c
index b2c7769..102fe95 100644
--- a/mi/mieq.c
+++ b/mi/mieq.c
@@ -407,6 +407,9 @@ ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
case ET_RawTouchUpdate:
event->raw_event.deviceid = dev->id;
break;
+ case ET_BarrierNotify:
+ event->barrier_event.deviceid = dev->id;
+ break;
default:
ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
event->any.type);
diff --git a/mi/mipointer.c b/mi/mipointer.c
index f345063..b440fd1 100644
--- a/mi/mipointer.c
+++ b/mi/mipointer.c
@@ -271,7 +271,7 @@ miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen,
pPointer->generateEvent = generateEvent;
if (pScreen->ConstrainCursorHarder)
- pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y);
+ pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y, 0, 0);
/* device dependent - must pend signal and call miPointerWarpCursor */
(*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y);
@@ -562,10 +562,13 @@ miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
* @param mode Movement mode (Absolute or Relative)
* @param[in,out] screenx The x coordinate in desktop coordinates
* @param[in,out] screeny The y coordinate in desktop coordinates
+ * @param unclamped_x The unclamped x coordinate in screen coordinates
+ * @param unclamped_x The unclamped y coordinate in screen coordinates
*/
ScreenPtr
-miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx,
- double *screeny)
+miPointerSetPosition(DeviceIntPtr pDev, int mode,
+ double *screenx, double *screeny,
+ int unclamped_x, int unclamped_y)
{
miPointerScreenPtr pScreenPriv;
ScreenPtr pScreen;
@@ -614,7 +617,8 @@ miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx,
y = pPointer->limits.y2 - 1;
if (pScreen->ConstrainCursorHarder)
- pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y);
+ pScreen->ConstrainCursorHarder(pDev, pScreen, mode, &x, &y,
+ unclamped_x, unclamped_y);
if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen)
miPointerMoveNoEvent(pDev, pScreen, x, y);
diff --git a/mi/mipointer.h b/mi/mipointer.h
index 1500e21..9d008f4 100644
--- a/mi/mipointer.h
+++ b/mi/mipointer.h
@@ -115,7 +115,9 @@ miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y);
/* Moves the cursor to the specified position. May clip the co-ordinates:
* x and y are modified in-place. */
extern _X_EXPORT ScreenPtr
-miPointerSetPosition(DeviceIntPtr pDev, int mode, double *x, double *y);
+miPointerSetPosition(DeviceIntPtr pDev, int mode,
+ double *x, double *y,
+ int unclamped_x, int unclamped_y);
extern _X_EXPORT void
miPointerUpdateSprite(DeviceIntPtr pDev);
diff --git a/randr/randrstr.h b/randr/randrstr.h
index a16302f..1cc4dfd 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -704,7 +704,7 @@ int
ProcRRSetPanning(ClientPtr client);
void
- RRConstrainCursorHarder(DeviceIntPtr, ScreenPtr, int, int *, int *);
+ RRConstrainCursorHarder(DeviceIntPtr, ScreenPtr, int, int *, int *, int, int);
/* rrdispatch.c */
extern _X_EXPORT Bool
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index e82d050..d0eb8dd 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -1613,8 +1613,8 @@ static Bool constrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int
}
void
-RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
- int *y)
+RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode,
+ int *x, int *y, int unclamped_x, int unclamped_y)
{
rrScrPriv(pScreen);
Bool ret;
--
1.8.0
More information about the xorg-devel
mailing list