summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2012-12-19 12:09:31 -0800
committerKeith Packard <keithp@keithp.com>2012-12-19 12:09:31 -0800
commit014a5c8a9d86f2f992183bff9106354fac2c3b0e (patch)
treee848fd6eb03079d6e3e8b69ba1b4237066e23749
parentf793b5fd3eb16a2ada130367c2ffebeede69a322 (diff)
parent2eefa5d6e870c57ac6a5930883d8cfe3a3882a43 (diff)
Merge remote-tracking branch 'whot/barriers'
Conflicts: Xi/xichangehierarchy.c Small conflict with the patch from Xi: don't use devices after removing them Was easily resolved by hand. Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--Xi/Makefile.am2
-rw-r--r--Xi/exevents.c47
-rw-r--r--Xi/extinit.c41
-rw-r--r--Xi/xibarriers.c916
-rw-r--r--Xi/xibarriers.h48
-rw-r--r--Xi/xichangehierarchy.c5
-rw-r--r--configure.ac2
-rw-r--r--dix/eventconvert.c43
-rw-r--r--dix/events.c24
-rw-r--r--dix/getevents.c15
-rw-r--r--include/events.h1
-rw-r--r--include/eventstr.h24
-rw-r--r--include/input.h6
-rw-r--r--include/inputstr.h2
-rw-r--r--mi/mieq.c4
-rw-r--r--mi/mipointer.c54
-rw-r--r--mi/mipointer.h3
-rw-r--r--test/fixes.c26
-rw-r--r--test/xi2/protocol-eventconvert.c216
-rw-r--r--xfixes/cursor.c432
-rw-r--r--xfixes/xfixes.h17
21 files changed, 1464 insertions, 464 deletions
diff --git a/Xi/Makefile.am b/Xi/Makefile.am
index 69c7886b9..af85bd049 100644
--- a/Xi/Makefile.am
+++ b/Xi/Makefile.am
@@ -78,6 +78,8 @@ libXi_la_SOURCES = \
ungrdevk.h \
xiallowev.c \
xiallowev.h \
+ xibarriers.c \
+ xibarriers.h \
xichangecursor.c \
xichangecursor.h \
xichangehierarchy.c \
diff --git a/Xi/exevents.c b/Xi/exevents.c
index 4c1aeb4da..58fe49363 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -1648,6 +1648,49 @@ 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;
+ GrabPtr grab = dev->deviceGrab.grab;
+
+ if (!IsMaster(dev))
+ return;
+
+ if (dixLookupWindow(&pWin, be->window, serverClient, DixReadAccess) != Success)
+ return;
+
+ if (grab)
+ be->flags |= XIBarrierDeviceIsGrabbed;
+
+ rc = EventToXI2(e, &ev);
+ if (rc != Success) {
+ ErrorF("[Xi] event conversion from %s failed with code %d\n", __func__, rc);
+ return;
+ }
+
+ /* A client has a grab, deliver to this client if the grab_window is the
+ barrier window.
+
+ Otherwise, deliver normally to the client.
+ */
+ if (grab &&
+ CLIENT_ID(be->barrierid) == CLIENT_ID(grab->resource) &&
+ grab->window->drawable.id == be->window) {
+ DeliverGrabbedEvent(e, dev, FALSE);
+ } else {
+ filter = GetEventFilter(dev, ev);
+
+ DeliverEventsToWindow(dev, pWin, ev, 1,
+ filter, NullGrab);
+ }
+ free(ev);
+}
+
/**
* Process DeviceEvents and DeviceChangedEvents.
*/
@@ -1797,6 +1840,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 7e3075551..73b084cd9 100644
--- a/Xi/extinit.c
+++ b/Xi/extinit.c
@@ -122,6 +122,7 @@ SOFTWARE.
#include "xiqueryversion.h"
#include "xisetclientpointer.h"
#include "xiwarppointer.h"
+#include "xibarriers.h"
/* Masks for XI events have to be aligned with core event (partially anyway).
* If DeviceButtonMotionMask is != ButtonMotionMask, event delivery
@@ -251,7 +252,8 @@ static int (*ProcIVector[]) (ClientPtr) = {
ProcXIChangeProperty, /* 57 */
ProcXIDeleteProperty, /* 58 */
ProcXIGetProperty, /* 59 */
- ProcXIGetSelectedEvents /* 60 */
+ ProcXIGetSelectedEvents, /* 60 */
+ ProcXIBarrierReleasePointer /* 61 */
};
/* For swapped clients */
@@ -316,7 +318,8 @@ static int (*SProcIVector[]) (ClientPtr) = {
SProcXIChangeProperty, /* 57 */
SProcXIDeleteProperty, /* 58 */
SProcXIGetProperty, /* 59 */
- SProcXIGetSelectedEvents /* 60 */
+ SProcXIGetSelectedEvents, /* 60 */
+ SProcXIBarrierReleasePointer /* 61 */
};
/*****************************************************************
@@ -839,6 +842,32 @@ STouchOwnershipEvent(xXITouchOwnershipEvent * from, xXITouchOwnershipEvent * to)
swapl(&to->child);
}
+static void
+SBarrierEvent(xXIBarrierEvent * from,
+ xXIBarrierEvent * to) {
+
+ *to = *from;
+
+ swaps(&from->sequenceNumber);
+ swapl(&from->length);
+ swaps(&from->evtype);
+ swapl(&from->time);
+ swaps(&from->deviceid);
+ swaps(&from->sourceid);
+ swapl(&from->event);
+ swapl(&from->root);
+ swapl(&from->root_x);
+ swapl(&from->root_y);
+
+ swapl(&from->dx.integral);
+ swapl(&from->dx.frac);
+ swapl(&from->dy.integral);
+ swapl(&from->dy.frac);
+ swapl(&from->dtime);
+ swapl(&from->barrier);
+ swapl(&from->eventid);
+}
+
/** Event swapping function for XI2 events. */
void
XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
@@ -885,6 +914,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;
@@ -1263,6 +1297,9 @@ XInputExtensionInit(void)
if (!AddCallback(&ClientStateCallback, XIClientCallback, 0))
FatalError("Failed to add callback to XI.\n");
+ if (!XIBarrierInit())
+ FatalError("Could not initialize barriers.\n");
+
extEntry = AddExtension(INAME, IEVENTS, IERRORS, ProcIDispatch,
SProcIDispatch, IResetProc, StandardMinorOpcode);
if (extEntry) {
diff --git a/Xi/xibarriers.c b/Xi/xibarriers.c
new file mode 100644
index 000000000..7b7b83f1c
--- /dev/null
+++ b/Xi/xibarriers.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright © 2002 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "xibarriers.h"
+#include "scrnintstr.h"
+#include "cursorstr.h"
+#include "dixevents.h"
+#include "servermd.h"
+#include "mipointer.h"
+#include "inputstr.h"
+#include "windowstr.h"
+#include "xace.h"
+#include "list.h"
+#include "exglobals.h"
+#include "eventstr.h"
+#include "mi.h"
+
+RESTYPE PointerBarrierType;
+
+static DevPrivateKeyRec BarrierScreenPrivateKeyRec;
+
+#define BarrierScreenPrivateKey (&BarrierScreenPrivateKeyRec)
+
+typedef struct PointerBarrierClient *PointerBarrierClientPtr;
+
+struct PointerBarrierDevice {
+ struct xorg_list entry;
+ int deviceid;
+ Time last_timestamp;
+ int barrier_event_id;
+ int release_event_id;
+ Bool hit;
+ Bool seen;
+};
+
+struct PointerBarrierClient {
+ XID id;
+ ScreenPtr screen;
+ Window window;
+ struct PointerBarrier barrier;
+ struct xorg_list entry;
+ /* num_devices/device_ids are devices the barrier applies to */
+ int num_devices;
+ int *device_ids; /* num_devices */
+
+ /* per_device keeps track of devices actually blocked by barriers */
+ struct xorg_list per_device;
+};
+
+typedef struct _BarrierScreen {
+ struct xorg_list barriers;
+} BarrierScreenRec, *BarrierScreenPtr;
+
+#define GetBarrierScreen(s) ((BarrierScreenPtr)dixLookupPrivate(&(s)->devPrivates, BarrierScreenPrivateKey))
+#define GetBarrierScreenIfSet(s) GetBarrierScreen(s)
+#define SetBarrierScreen(s,p) dixSetPrivate(&(s)->devPrivates, BarrierScreenPrivateKey, p)
+
+static struct PointerBarrierDevice *AllocBarrierDevice(void)
+{
+ struct PointerBarrierDevice *pbd = NULL;
+
+ pbd = malloc(sizeof(struct PointerBarrierDevice));
+ if (!pbd)
+ return NULL;
+
+ pbd->deviceid = -1; /* must be set by caller */
+ pbd->barrier_event_id = 1;
+ pbd->release_event_id = 0;
+ pbd->hit = FALSE;
+ pbd->seen = FALSE;
+ xorg_list_init(&pbd->entry);
+
+ return pbd;
+}
+
+static void FreePointerBarrierClient(struct PointerBarrierClient *c)
+{
+ struct PointerBarrierDevice *pbd = NULL, *tmp = NULL;
+
+ xorg_list_for_each_entry_safe(pbd, tmp, &c->per_device, entry) {
+ free(pbd);
+ }
+ free(c);
+}
+
+static struct PointerBarrierDevice *GetBarrierDevice(struct PointerBarrierClient *c, int deviceid)
+{
+ struct PointerBarrierDevice *pbd = NULL;
+
+ xorg_list_for_each_entry(pbd, &c->per_device, entry) {
+ if (pbd->deviceid == deviceid)
+ break;
+ }
+
+ BUG_WARN(!pbd);
+ return pbd;
+}
+
+static BOOL
+barrier_is_horizontal(const struct PointerBarrier *barrier)
+{
+ return barrier->y1 == barrier->y2;
+}
+
+static BOOL
+barrier_is_vertical(const struct PointerBarrier *barrier)
+{
+ return barrier->x1 == barrier->x2;
+}
+
+/**
+ * @return The set of barrier movement directions the movement vector
+ * x1/y1 → x2/y2 represents.
+ */
+int
+barrier_get_direction(int x1, int y1, int x2, int y2)
+{
+ int direction = 0;
+
+ /* which way are we trying to go */
+ if (x2 > x1)
+ direction |= BarrierPositiveX;
+ if (x2 < x1)
+ direction |= BarrierNegativeX;
+ if (y2 > y1)
+ direction |= BarrierPositiveY;
+ if (y2 < y1)
+ direction |= BarrierNegativeY;
+
+ return direction;
+}
+
+/**
+ * Test if the barrier may block movement in the direction defined by
+ * x1/y1 → x2/y2. This function only tests whether the directions could be
+ * blocked, it does not test if the barrier actually blocks the movement.
+ *
+ * @return TRUE if the barrier blocks the direction of movement or FALSE
+ * otherwise.
+ */
+BOOL
+barrier_is_blocking_direction(const struct PointerBarrier * barrier,
+ int direction)
+{
+ /* Barriers define which way is ok, not which way is blocking */
+ return (barrier->directions & direction) != direction;
+}
+
+static BOOL
+inside_segment(int v, int v1, int v2)
+{
+ if (v1 < 0 && v2 < 0) /* line */
+ return TRUE;
+ else if (v1 < 0) /* ray */
+ return v <= v2;
+ else if (v2 < 0) /* ray */
+ return v >= v1;
+ else /* line segment */
+ return v >= v1 && v <= v2;
+}
+
+#define T(v, a, b) (((float)v) - (a)) / ((b) - (a))
+#define F(t, a, b) ((t) * ((a) - (b)) + (a))
+
+/**
+ * Test if the movement vector x1/y1 → x2/y2 is intersecting with the
+ * barrier. A movement vector with the startpoint or endpoint adjacent to
+ * the barrier itself counts as intersecting.
+ *
+ * @param x1 X start coordinate of movement vector
+ * @param y1 Y start coordinate of movement vector
+ * @param x2 X end coordinate of movement vector
+ * @param y2 Y end coordinate of movement vector
+ * @param[out] distance The distance between the start point and the
+ * intersection with the barrier (if applicable).
+ * @return TRUE if the barrier intersects with the given vector
+ */
+BOOL
+barrier_is_blocking(const struct PointerBarrier * barrier,
+ int x1, int y1, int x2, int y2, double *distance)
+{
+ if (barrier_is_vertical(barrier)) {
+ float t, y;
+ t = T(barrier->x1, x1, x2);
+ if (t < 0 || t > 1)
+ return FALSE;
+
+ /* Edge case: moving away from barrier. */
+ if (x2 > x1 && t == 0)
+ return FALSE;
+
+ y = F(t, y1, y2);
+ if (!inside_segment(y, barrier->y1, barrier->y2))
+ return FALSE;
+
+ *distance = sqrt((pow(y - y1, 2) + pow(barrier->x1 - x1, 2)));
+ return TRUE;
+ }
+ else {
+ float t, x;
+ t = T(barrier->y1, y1, y2);
+ if (t < 0 || t > 1)
+ return FALSE;
+
+ /* Edge case: moving away from barrier. */
+ if (y2 > y1 && t == 0)
+ return FALSE;
+
+ x = F(t, x1, x2);
+ if (!inside_segment(x, barrier->x1, barrier->x2))
+ return FALSE;
+
+ *distance = sqrt((pow(x - x1, 2) + pow(barrier->y1 - y1, 2)));
+ return TRUE;
+ }
+}
+
+#define HIT_EDGE_EXTENTS 2
+static BOOL
+barrier_inside_hit_box(struct PointerBarrier *barrier, int x, int y)
+{
+ int x1, x2, y1, y2;
+ int dir;
+
+ x1 = barrier->x1;
+ x2 = barrier->x2;
+ y1 = barrier->y1;
+ y2 = barrier->y2;
+ dir = ~(barrier->directions);
+
+ if (barrier_is_vertical(barrier)) {
+ if (dir & BarrierPositiveX)
+ x1 -= HIT_EDGE_EXTENTS;
+ if (dir & BarrierNegativeX)
+ x2 += HIT_EDGE_EXTENTS;
+ }
+ if (barrier_is_horizontal(barrier)) {
+ if (dir & BarrierPositiveY)
+ y1 -= HIT_EDGE_EXTENTS;
+ if (dir & BarrierNegativeY)
+ y2 += HIT_EDGE_EXTENTS;
+ }
+
+ return x >= x1 && x <= x2 && y >= y1 && y <= y2;
+}
+
+static BOOL
+barrier_blocks_device(struct PointerBarrierClient *client,
+ DeviceIntPtr dev)
+{
+ int i;
+ int master_id;
+
+ /* Clients with no devices are treated as
+ * if they specified XIAllDevices. */
+ if (client->num_devices == 0)
+ return TRUE;
+
+ master_id = GetMaster(dev, POINTER_OR_FLOAT)->id;
+
+ for (i = 0; i < client->num_devices; i++) {
+ int device_id = client->device_ids[i];
+ if (device_id == XIAllDevices ||
+ device_id == XIAllMasterDevices ||
+ device_id == master_id)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * 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
+ * @param y1 Y start coordinate of movement vector
+ * @param x2 X end coordinate of movement vector
+ * @param y2 Y end coordinate of movement vector
+ * @return The barrier nearest to the movement origin that blocks this movement.
+ */
+static struct PointerBarrierClient *
+barrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev,
+ int dir,
+ int x1, int y1, int x2, int y2)
+{
+ 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) {
+ struct PointerBarrier *b = &c->barrier;
+ struct PointerBarrierDevice *pbd;
+ double distance;
+
+ pbd = GetBarrierDevice(c, dev->id);
+ if (pbd->seen)
+ continue;
+
+ if (!barrier_is_blocking_direction(b, dir))
+ continue;
+
+ if (!barrier_blocks_device(c, dev))
+ continue;
+
+ if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) {
+ if (min_distance > distance) {
+ min_distance = distance;
+ nearest = c;
+ }
+ }
+ }
+
+ return nearest;
+}
+
+/**
+ * Clamp to the given barrier given the movement direction specified in dir.
+ *
+ * @param barrier The barrier to clamp to
+ * @param dir The movement direction
+ * @param[out] x The clamped x coordinate.
+ * @param[out] y The clamped x coordinate.
+ */
+void
+barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x,
+ int *y)
+{
+ if (barrier_is_vertical(barrier)) {
+ if ((dir & BarrierNegativeX) & ~barrier->directions)
+ *x = barrier->x1;
+ if ((dir & BarrierPositiveX) & ~barrier->directions)
+ *x = barrier->x1 - 1;
+ }
+ if (barrier_is_horizontal(barrier)) {
+ if ((dir & BarrierNegativeY) & ~barrier->directions)
+ *y = barrier->y1;
+ if ((dir & BarrierPositiveY) & ~barrier->directions)
+ *y = barrier->y1 - 1;
+ }
+}
+
+void
+input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
+ int current_x, int current_y,
+ int dest_x, int dest_y,
+ int *out_x, int *out_y,
+ int *nevents, InternalEvent* events)
+{
+ /* Clamped coordinates here refer to screen edge clamping. */
+ BarrierScreenPtr cs = GetBarrierScreen(screen);
+ int x = dest_x,
+ y = dest_y;
+ int dir;
+ 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,
+ };
+ InternalEvent *barrier_events = events;
+ DeviceIntPtr master;
+
+ if (nevents)
+ *nevents = 0;
+
+ if (xorg_list_is_empty(&cs->barriers) || IsFloating(dev))
+ goto out;
+
+ /**
+ * This function is only called for slave devices, but pointer-barriers
+ * are for master-devices only. Flip the device to the master here,
+ * continue with that.
+ */
+ master = GetMaster(dev, MASTER_POINTER);
+
+ /* How this works:
+ * Given the origin and the movement vector, get the nearest barrier
+ * to the origin that is blocking the movement.
+ * Clamp to that barrier.
+ * Then, check from the clamped intersection to the original
+ * destination, again finding the nearest barrier and clamping.
+ */
+ dir = barrier_get_direction(current_x, current_y, x, y);
+
+ while (dir != 0) {
+ struct PointerBarrierDevice *pbd;
+
+ c = barrier_find_nearest(cs, master, dir, current_x, current_y, x, y);
+ if (!c)
+ break;
+
+ nearest = &c->barrier;
+
+ pbd = GetBarrierDevice(c, master->id);
+ pbd->seen = TRUE;
+ pbd->hit = TRUE;
+
+ if (pbd->barrier_event_id == pbd->release_event_id)
+ continue;
+
+ ev.type = ET_BarrierHit;
+ barrier_clamp_to_barrier(nearest, dir, &x, &y);
+
+ if (barrier_is_vertical(nearest)) {
+ dir &= ~(BarrierNegativeX | BarrierPositiveX);
+ current_x = x;
+ }
+ else if (barrier_is_horizontal(nearest)) {
+ dir &= ~(BarrierNegativeY | BarrierPositiveY);
+ current_y = y;
+ }
+
+ ev.flags = 0;
+ ev.event_id = pbd->barrier_event_id;
+ ev.barrierid = c->id;
+
+ ev.dt = ms - pbd->last_timestamp;
+ ev.window = c->window;
+ pbd->last_timestamp = ms;
+
+ /* root x/y is filled in later */
+
+ barrier_events->barrier_event = ev;
+ barrier_events++;
+ *nevents += 1;
+ }
+
+ xorg_list_for_each_entry(c, &cs->barriers, entry) {
+ struct PointerBarrierDevice *pbd;
+ int flags = 0;
+
+ pbd = GetBarrierDevice(c, master->id);
+ pbd->seen = FALSE;
+ if (!pbd->hit)
+ continue;
+
+ if (barrier_inside_hit_box(&c->barrier, x, y))
+ continue;
+
+ pbd->hit = FALSE;
+
+ ev.type = ET_BarrierLeave;
+
+ if (pbd->barrier_event_id == pbd->release_event_id)
+ flags |= XIBarrierPointerReleased;
+
+ ev.flags = flags;
+ ev.event_id = pbd->barrier_event_id;
+ ev.barrierid = c->id;
+
+ ev.dt = ms - pbd->last_timestamp;
+ ev.window = c->window;
+ pbd->last_timestamp = ms;
+
+ /* root x/y is filled in later */
+
+ barrier_events->barrier_event = ev;
+ barrier_events++;
+ *nevents += 1;
+
+ /* If we've left the hit box, this is the
+ * start of a new event ID. */
+ pbd->barrier_event_id++;
+ }
+
+ out:
+ *out_x = x;
+ *out_y = y;
+}
+
+static void
+sort_min_max(INT16 *a, INT16 *b)
+{
+ INT16 A, B;
+ if (*a < 0 || *b < 0)
+ return;
+ A = *a;
+ B = *b;
+ *a = min(A, B);
+ *b = max(A, B);
+}
+
+static int
+CreatePointerBarrierClient(ClientPtr client,
+ xXFixesCreatePointerBarrierReq * stuff,
+ PointerBarrierClientPtr *client_out)
+{
+ WindowPtr pWin;
+ ScreenPtr screen;
+ BarrierScreenPtr cs;
+ int err;
+ int size;
+ int i;
+ struct PointerBarrierClient *ret;
+ CARD16 *in_devices;
+ DeviceIntPtr dev;
+
+ size = sizeof(*ret) + sizeof(DeviceIntPtr) * stuff->num_devices;
+ ret = malloc(size);
+
+ if (!ret) {
+ return BadAlloc;
+ }
+
+ xorg_list_init(&ret->per_device);
+
+ err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
+ if (err != Success) {
+ client->errorValue = stuff->window;
+ goto error;
+ }
+
+ screen = pWin->drawable.pScreen;
+ cs = GetBarrierScreen(screen);
+
+ ret->screen = screen;
+ ret->window = stuff->window;
+ ret->num_devices = stuff->num_devices;
+ if (ret->num_devices > 0)
+ ret->device_ids = (int*)&ret[1];
+ else
+ ret->device_ids = NULL;
+
+ in_devices = (CARD16 *) &stuff[1];
+ for (i = 0; i < stuff->num_devices; i++) {
+ int device_id = in_devices[i];
+ DeviceIntPtr device;
+
+ if ((err = dixLookupDevice (&device, device_id,
+ client, DixReadAccess))) {
+ client->errorValue = device_id;
+ goto error;
+ }
+
+ if (!IsMaster (device)) {
+ client->errorValue = device_id;
+ err = BadDevice;
+ goto error;
+ }
+
+ ret->device_ids[i] = device_id;
+ }
+
+ /* Alloc one per master pointer, they're the ones that can be blocked */
+ xorg_list_init(&ret->per_device);
+ nt_list_for_each_entry(dev, inputInfo.devices, next) {
+ struct PointerBarrierDevice *pbd;
+
+ if (dev->type != MASTER_POINTER)
+ continue;
+
+ pbd = AllocBarrierDevice();
+ if (!pbd) {
+ err = BadAlloc;
+ goto error;
+ }
+ pbd->deviceid = dev->id;
+
+ xorg_list_add(&pbd->entry, &ret->per_device);
+ }
+
+ ret->id = stuff->barrier;
+ ret->barrier.x1 = stuff->x1;
+ ret->barrier.x2 = stuff->x2;
+ ret->barrier.y1 = stuff->y1;
+ ret->barrier.y2 = stuff->y2;
+ sort_min_max(&ret->barrier.x1, &ret->barrier.x2);
+ sort_min_max(&ret->barrier.y1, &ret->barrier.y2);
+ ret->barrier.directions = stuff->directions & 0x0f;
+ if (barrier_is_horizontal(&ret->barrier))
+ ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
+ if (barrier_is_vertical(&ret->barrier))
+ ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY);
+ xorg_list_add(&ret->entry, &cs->barriers);
+
+ *client_out = ret;
+ return Success;
+
+ error:
+ *client_out = NULL;
+ FreePointerBarrierClient(ret);
+ return err;
+}
+
+static int
+BarrierFreeBarrier(void *data, XID id)
+{
+ struct PointerBarrierClient *c;
+ Time ms = GetTimeInMillis();
+ DeviceIntPtr dev = NULL;
+ ScreenPtr screen;
+
+ c = container_of(data, struct PointerBarrierClient, barrier);
+ screen = c->screen;
+
+ for (dev = inputInfo.devices; dev; dev = dev->next) {
+ struct PointerBarrierDevice *pbd;
+ int root_x, root_y;
+ BarrierEvent ev = {
+ .header = ET_Internal,
+ .type = ET_BarrierLeave,
+ .length = sizeof (BarrierEvent),
+ .time = ms,
+ /* .deviceid */
+ .sourceid = 0,
+ .barrierid = c->id,
+ .window = c->window,
+ .root = screen->root->drawable.id,
+ .dx = 0,
+ .dy = 0,
+ /* .root_x */
+ /* .root_y */
+ /* .dt */
+ /* .event_id */
+ .flags = XIBarrierPointerReleased,
+ };
+
+
+ if (dev->type != MASTER_POINTER)
+ continue;
+
+ pbd = GetBarrierDevice(c, dev->id);
+ if (!pbd->hit)
+ continue;
+
+ ev.deviceid = dev->id;
+ ev.event_id = pbd->barrier_event_id,
+ ev.dt = ms - pbd->last_timestamp,
+
+ GetSpritePosition(dev, &root_x, &root_y);
+ ev.root_x = root_x;
+ ev.root_y = root_y;
+
+ mieqEnqueue(dev, (InternalEvent *) &ev);
+ }
+
+ xorg_list_del(&c->entry);
+
+ FreePointerBarrierClient(c);
+ return Success;
+}
+
+static void add_master_func(pointer res, XID id, pointer devid)
+{
+ struct PointerBarrier *b;
+ struct PointerBarrierClient *barrier;
+ struct PointerBarrierDevice *pbd;
+ int *deviceid = devid;
+
+ b = res;
+ barrier = container_of(b, struct PointerBarrierClient, barrier);
+
+
+ pbd = AllocBarrierDevice();
+ pbd->deviceid = *deviceid;
+
+ xorg_list_add(&pbd->entry, &barrier->per_device);
+}
+
+static void remove_master_func(pointer res, XID id, pointer devid)
+{
+ struct PointerBarrierDevice *pbd;
+ struct PointerBarrierClient *barrier;
+ struct PointerBarrier *b;
+ DeviceIntPtr dev;
+ int *deviceid = devid;
+ int rc;
+ Time ms = GetTimeInMillis();
+
+ rc = dixLookupDevice(&dev, *deviceid, serverClient, DixSendAccess);
+ if (rc != Success)
+ return;
+
+ b = res;
+ barrier = container_of(b, struct PointerBarrierClient, barrier);
+
+ pbd = GetBarrierDevice(barrier, *deviceid);
+
+ if (pbd->hit) {
+ BarrierEvent ev = {
+ .header = ET_Internal,
+ .type =ET_BarrierLeave,
+ .length = sizeof (BarrierEvent),
+ .time = ms,
+ .deviceid = *deviceid,
+ .sourceid = 0,
+ .dx = 0,
+ .dy = 0,
+ .root = barrier->screen->root->drawable.id,
+ .window = barrier->window,
+ .dt = ms - pbd->last_timestamp,
+ .flags = XIBarrierPointerReleased,
+ .event_id = pbd->barrier_event_id,
+ .barrierid = barrier->id,
+ };
+
+ mieqEnqueue(dev, (InternalEvent *) &ev);
+ }
+
+ xorg_list_del(&pbd->entry);
+ free(pbd);
+}
+
+void XIBarrierNewMasterDevice(ClientPtr client, int deviceid)
+{
+ FindClientResourcesByType(client, PointerBarrierType, add_master_func, &deviceid);
+}
+
+void XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid)
+{
+ FindClientResourcesByType(client, PointerBarrierType, remove_master_func, &deviceid);
+}
+
+int
+XICreatePointerBarrier(ClientPtr client,
+ xXFixesCreatePointerBarrierReq * stuff)
+{
+ int err;
+ struct PointerBarrierClient *barrier;
+ struct PointerBarrier b;
+
+ b.x1 = stuff->x1;
+ b.x2 = stuff->x2;
+ b.y1 = stuff->y1;
+ b.y2 = stuff->y2;
+
+ if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b))
+ return BadValue;
+
+ /* no 0-sized barriers */
+ if (barrier_is_horizontal(&b) && barrier_is_vertical(&b))
+ return BadValue;
+
+ /* no infinite barriers on the wrong axis */
+ if (barrier_is_horizontal(&b) && (b.y1 < 0 || b.y2 < 0))
+ return BadValue;
+
+ if (barrier_is_vertical(&b) && (b.x1 < 0 || b.x2 < 0))
+ return BadValue;
+
+ if ((err = CreatePointerBarrierClient(client, stuff, &barrier)))
+ return err;
+
+ if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
+ return BadAlloc;
+
+ return Success;
+}
+
+int
+XIDestroyPointerBarrier(ClientPtr client,
+ xXFixesDestroyPointerBarrierReq * stuff)
+{
+ int err;
+ void *barrier;
+
+ err = dixLookupResourceByType((void **) &barrier, stuff->barrier,
+ PointerBarrierType, client, DixDestroyAccess);
+ if (err != Success) {
+ client->errorValue = stuff->barrier;
+ return err;
+ }
+
+ if (CLIENT_ID(stuff->barrier) != client->index)
+ return BadAccess;
+
+ FreeResource(stuff->barrier, RT_NONE);
+ 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++) {
+ struct PointerBarrierDevice *pbd;
+ DeviceIntPtr dev;
+ CARD32 barrier_id, event_id;
+ _X_UNUSED CARD32 device_id;
+
+ barrier_id = info->barrier;
+ event_id = info->eventid;
+
+ err = dixLookupDevice(&dev, info->deviceid, client, DixReadAccess);
+ if (err != Success) {
+ client->errorValue = BadDevice;
+ return err;
+ }
+
+ err = dixLookupResourceByType((void **) &b, barrier_id,
+ PointerBarrierType, client, DixReadAccess);
+ if (err != Success) {
+ client->errorValue = barrier_id;
+ return err;
+ }
+
+ if (CLIENT_ID(barrier_id) != client->index)
+ return BadAccess;
+
+
+ barrier = container_of(b, struct PointerBarrierClient, barrier);
+
+ pbd = GetBarrierDevice(barrier, dev->id);
+
+ if (pbd->barrier_event_id == event_id)
+ pbd->release_event_id = event_id;
+ }
+
+ return Success;
+}
+
+Bool
+XIBarrierInit(void)
+{
+ int i;
+
+ if (!dixRegisterPrivateKey(&BarrierScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
+ return FALSE;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ ScreenPtr pScreen = screenInfo.screens[i];
+ BarrierScreenPtr cs;
+
+ cs = (BarrierScreenPtr) calloc(1, sizeof(BarrierScreenRec));
+ if (!cs)
+ return FALSE;
+ xorg_list_init(&cs->barriers);
+ SetBarrierScreen(pScreen, cs);
+ }
+
+ PointerBarrierType = CreateNewResourceType(BarrierFreeBarrier,
+ "XIPointerBarrier");
+
+ return PointerBarrierType;
+}
diff --git a/Xi/xibarriers.h b/Xi/xibarriers.h
new file mode 100644
index 000000000..11e84ec9f
--- /dev/null
+++ b/Xi/xibarriers.h
@@ -0,0 +1,48 @@
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#ifndef _XIBARRIERS_H_
+#define _XIBARRIERS_H_
+
+#include "resource.h"
+
+extern _X_EXPORT RESTYPE PointerBarrierType;
+
+struct PointerBarrier {
+ INT16 x1, x2, y1, y2;
+ CARD32 directions;
+};
+
+int
+barrier_get_direction(int, int, int, int);
+BOOL
+barrier_is_blocking(const struct PointerBarrier *, int, int, int, int,
+ double *);
+BOOL
+barrier_is_blocking_direction(const struct PointerBarrier *, int);
+void
+barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x,
+ int *y);
+
+#include <xfixesint.h>
+
+int
+XICreatePointerBarrier(ClientPtr client,
+ xXFixesCreatePointerBarrierReq * stuff);
+
+int
+XIDestroyPointerBarrier(ClientPtr client,
+ xXFixesDestroyPointerBarrierReq * stuff);
+
+Bool
+XIBarrierInit(void);
+
+int SProcXIBarrierReleasePointer(ClientPtr client);
+int ProcXIBarrierReleasePointer(ClientPtr client);
+
+void XIBarrierNewMasterDevice(ClientPtr client, int deviceid);
+void XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid);
+
+#endif /* _XIBARRIERS_H_ */
diff --git a/Xi/xichangehierarchy.c b/Xi/xichangehierarchy.c
index 4dc3d76e9..0184eb29a 100644
--- a/Xi/xichangehierarchy.c
+++ b/Xi/xichangehierarchy.c
@@ -52,6 +52,7 @@
#include "xkbsrv.h"
#include "xichangehierarchy.h"
+#include "xibarriers.h"
/**
* Send the current state of the device hierarchy to all clients.
@@ -189,6 +190,8 @@ add_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES])
flags[XTestptr->id] |= XISlaveAttached;
flags[XTestkeybd->id] |= XISlaveAttached;
+ XIBarrierNewMasterDevice(client, ptr->id);
+
unwind:
free(name);
return rc;
@@ -293,6 +296,8 @@ remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
}
}
+ XIBarrierRemoveMasterDevice(client, ptr->id);
+
/* disable the remove the devices, XTest devices must be done first
else the sprites they rely on will be destroyed */
DisableDevice(XTestptr, FALSE);
diff --git a/configure.ac b/configure.ac
index 38ac240df..ee0fa7818 100644
--- a/configure.ac
+++ b/configure.ac
@@ -788,7 +788,7 @@ XPROTO="xproto >= 7.0.22"
RANDRPROTO="randrproto >= 1.4.0"
RENDERPROTO="renderproto >= 0.11"
XEXTPROTO="xextproto >= 7.1.99"
-INPUTPROTO="inputproto >= 2.1.99.6"
+INPUTPROTO="inputproto >= 2.2.99.1"
KBPROTO="kbproto >= 1.0.3"
FONTSPROTO="fontsproto"
FIXESPROTO="fixesproto >= 5.0"
diff --git a/dix/eventconvert.c b/dix/eventconvert.c
index 2e422d7a1..47dcf8b41 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 */
@@ -160,6 +161,8 @@ EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
case ET_TouchUpdate:
case ET_TouchEnd:
case ET_TouchOwnership:
+ case ET_BarrierHit:
+ case ET_BarrierLeave:
ret = BadMatch;
break;
default:
@@ -216,6 +219,8 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count)
case ET_TouchUpdate:
case ET_TouchEnd:
case ET_TouchOwnership:
+ case ET_BarrierHit:
+ case ET_BarrierLeave:
*count = 0;
*xi = NULL;
return BadMatch;
@@ -277,6 +282,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 +790,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 +966,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/dix/events.c b/dix/events.c
index 3836d2f17..73593626e 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -219,6 +219,9 @@ static void CheckVirtualMotion(DeviceIntPtr pDev, QdEventPtr qe,
static void CheckPhysLimits(DeviceIntPtr pDev, CursorPtr cursor,
Bool generateEvents, Bool confineToScreen,
ScreenPtr pScreen);
+static Bool IsWrongPointerBarrierClient(ClientPtr client,
+ DeviceIntPtr dev,
+ xEvent *event);
/** Key repeat hack. Do not use but in TryClientEvents */
extern BOOL EventIsKeyRepeat(xEvent *event);
@@ -2092,6 +2095,9 @@ DeliverEventToInputClients(DeviceIntPtr dev, InputClients * inputclients,
if (IsInterferingGrab(client, dev, events))
continue;
+ if (IsWrongPointerBarrierClient(client, dev, events))
+ continue;
+
mask = GetEventMask(dev, events, inputclients);
if (XaceHook(XACE_RECEIVE_ACCESS, client, win, events, count))
@@ -2446,6 +2452,8 @@ FixUpEventFromWindow(SpritePtr pSprite,
case XI_DeviceChanged:
case XI_HierarchyChanged:
case XI_PropertyEvent:
+ case XI_BarrierHit:
+ case XI_BarrierLeave:
return;
default:
break;
@@ -6080,3 +6088,19 @@ IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent *event)
return FALSE;
}
+
+/* PointerBarrier events are only delivered to the client that created that
+ * barrier */
+static Bool
+IsWrongPointerBarrierClient(ClientPtr client, DeviceIntPtr dev, xEvent *event)
+{
+ xXIBarrierEvent *ev = (xXIBarrierEvent*)event;
+
+ if (ev->type != GenericEvent || ev->extension != IReqCode)
+ return FALSE;
+
+ if (ev->evtype != XI_BarrierHit && ev->evtype != XI_BarrierLeave)
+ return FALSE;
+
+ return client->index != CLIENT_ID(ev->barrier);
+}
diff --git a/dix/getevents.c b/dix/getevents.c
index fa538d9f4..3d41e1e5a 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -916,10 +916,13 @@ scale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask,
* @param[in,out] devy y desktop-wide coordinate in device coordinate system
* @param[in,out] screenx x coordinate in desktop coordinate system
* @param[in,out] screeny y coordinate in desktop coordinate system
+ * @param[out] nevents Number of barrier events added to events
+ * @param[in,out] events List of events barrier events are added to
*/
static ScreenPtr
positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
- double *devx, double *devy, double *screenx, double *screeny)
+ double *devx, double *devy, double *screenx, double *screeny,
+ int *nevents, InternalEvent* events)
{
ScreenPtr scr = miPointerGetScreen(dev);
double tmpx, tmpy;
@@ -933,7 +936,7 @@ 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, nevents, events);
/* If we were constrained, rescale x/y from the screen coordinates so
* the device valuators reflect the correct position. For screen
@@ -1319,6 +1322,7 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
int sx, sy; /* for POINTER_SCREEN */
ValuatorMask mask;
ScreenPtr scr;
+ int num_barrier_events = 0;
switch (type) {
case MotionNotify:
@@ -1395,7 +1399,10 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
}
scr = positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative,
- &mask, &devx, &devy, &screenx, &screeny);
+ &mask, &devx, &devy, &screenx, &screeny,
+ &num_barrier_events, events);
+ num_events += num_barrier_events;
+ events += num_barrier_events;
/* screenx, screeny are in desktop coordinates,
mask is in device coordinates per-screen (the event data)
@@ -1945,7 +1952,7 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid,
scr = scale_to_desktop(dev, &mask, &devx, &devy, &screenx, &screeny);
if (emulate_pointer)
scr = positionSprite(dev, Absolute, &mask,
- &devx, &devy, &screenx, &screeny);
+ &devx, &devy, &screenx, &screeny, NULL, NULL);
/* see fill_pointer_events for coordinate systems */
if (emulate_pointer)
diff --git a/include/events.h b/include/events.h
index 222bf328b..c0ef45d5f 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 dd6fbeffb..38fab4f3c 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 */
};
@@ -130,7 +132,7 @@ struct _DeviceEvent {
*/
struct _TouchOwnershipEvent {
unsigned char header; /**< Always ET_Internal */
- enum EventType type; /**< One of EventType */
+ enum EventType type; /**< ET_TouchOwnership */
int length; /**< Length in bytes */
Time time; /**< Time in ms */
int deviceid; /**< Device to post this event for */
@@ -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/input.h b/include/input.h
index 2387dbf4a..23a20b59d 100644
--- a/include/input.h
+++ b/include/input.h
@@ -678,4 +678,10 @@ extern _X_EXPORT void input_option_set_value(InputOption *opt,
extern _X_HIDDEN Bool point_on_screen(ScreenPtr pScreen, int x, int y);
extern _X_HIDDEN void update_desktop_dimensions(void);
+extern _X_HIDDEN void input_constrain_cursor(DeviceIntPtr pDev, ScreenPtr screen,
+ int current_x, int current_y,
+ int dest_x, int dest_y,
+ int *out_x, int *out_y,
+ int *nevents, InternalEvent* events);
+
#endif /* INPUT_H */
diff --git a/include/inputstr.h b/include/inputstr.h
index bb0a77963..17cee9854 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 b2c7769ec..22f8c91bb 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);
diff --git a/mi/mipointer.c b/mi/mipointer.c
index f34506326..b8503f450 100644
--- a/mi/mipointer.c
+++ b/mi/mipointer.c
@@ -98,7 +98,7 @@ static void miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen);
static void miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x,
int y);
-static InternalEvent *events; /* for WarpPointer MotionNotifies */
+static InternalEvent *mipointermove_events; /* for WarpPointer MotionNotifies */
Bool
miPointerInitialize(ScreenPtr pScreen,
@@ -143,7 +143,7 @@ miPointerInitialize(ScreenPtr pScreen,
pScreen->DeviceCursorInitialize = miPointerDeviceInitialize;
pScreen->DeviceCursorCleanup = miPointerDeviceCleanup;
- events = NULL;
+ mipointermove_events = NULL;
return TRUE;
}
@@ -160,8 +160,8 @@ miPointerCloseScreen(ScreenPtr pScreen)
pScreen->CloseScreen = pScreenPriv->CloseScreen;
free((pointer) pScreenPriv);
- FreeEventList(events, GetMaximumEventsNum());
- events = NULL;
+ FreeEventList(mipointermove_events, GetMaximumEventsNum());
+ mipointermove_events = NULL;
return (*pScreen->CloseScreen) (pScreen);
}
@@ -565,13 +565,16 @@ miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
*/
ScreenPtr
miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx,
- double *screeny)
+ double *screeny,
+ int *nevents, InternalEvent* events)
{
miPointerScreenPtr pScreenPriv;
ScreenPtr pScreen;
ScreenPtr newScreen;
int x, y;
Bool switch_screen = FALSE;
+ Bool should_constrain_barriers = FALSE;
+ int i;
miPointerPtr pPointer;
@@ -588,6 +591,25 @@ miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx,
x -= pScreen->x;
y -= pScreen->y;
+ should_constrain_barriers = (mode == Relative);
+
+ if (should_constrain_barriers) {
+ /* coordinates after clamped to a barrier */
+ int constrained_x, constrained_y;
+ int current_x, current_y; /* current position in per-screen coord */
+
+ current_x = MIPOINTER(pDev)->x - pScreen->y;
+ current_y = MIPOINTER(pDev)->y - pScreen->x;
+
+ input_constrain_cursor(pDev, pScreen,
+ current_x, current_y, x, y,
+ &constrained_x, &constrained_y,
+ nevents, events);
+
+ x = constrained_x;
+ y = constrained_y;
+ }
+
if (switch_screen) {
pScreenPriv = GetScreenPrivate(pScreen);
if (!pPointer->confined) {
@@ -619,6 +641,18 @@ miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx,
if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen)
miPointerMoveNoEvent(pDev, pScreen, x, y);
+ /* check if we generated any barrier events and if so, update root x/y
+ * to the fully constrained coords */
+ if (should_constrain_barriers) {
+ for (i = 0; i < *nevents; i++) {
+ if (events[i].any.type == ET_BarrierHit ||
+ events[i].any.type == ET_BarrierLeave) {
+ events[i].barrier_event.root_x = x;
+ events[i].barrier_event.root_y = y;
+ }
+ }
+ }
+
/* Convert to desktop coordinates again */
x += pScreen->x;
y += pScreen->y;
@@ -676,17 +710,17 @@ miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
valuators[0] = x;
valuators[1] = y;
- if (!events) {
- events = InitEventList(GetMaximumEventsNum());
+ if (!mipointermove_events) {
+ mipointermove_events = InitEventList(GetMaximumEventsNum());
- if (!events) {
+ if (!mipointermove_events) {
FatalError("Could not allocate event store.\n");
return;
}
}
valuator_mask_set_range(&mask, 0, 2, valuators);
- nevents = GetPointerEvents(events, pDev, MotionNotify, 0,
+ nevents = GetPointerEvents(mipointermove_events, pDev, MotionNotify, 0,
POINTER_SCREEN | POINTER_ABSOLUTE |
POINTER_NORAW, &mask);
@@ -695,7 +729,7 @@ miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
darwinEvents_lock();
#endif
for (i = 0; i < nevents; i++)
- mieqEnqueue(pDev, &events[i]);
+ mieqEnqueue(pDev, &mipointermove_events[i]);
#ifdef XQUARTZ
darwinEvents_unlock();
#endif
diff --git a/mi/mipointer.h b/mi/mipointer.h
index 1500e216a..f89dff31e 100644
--- a/mi/mipointer.h
+++ b/mi/mipointer.h
@@ -115,7 +115,8 @@ 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 *nevents, InternalEvent *events);
extern _X_EXPORT void
miPointerUpdateSprite(DeviceIntPtr pDev);
diff --git a/test/fixes.c b/test/fixes.c
index 7807c73ce..4ac6750e4 100644
--- a/test/fixes.c
+++ b/test/fixes.c
@@ -265,6 +265,32 @@ fixes_pointer_barriers_test(void)
x2 = x + 100;
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
+ /* ray vert barrier */
+ barrier.x1 = x;
+ barrier.x2 = x;
+ barrier.y1 = -1;
+ barrier.y2 = y + 100;
+
+ /* ray barrier simple case */
+ y1 = y;
+ y2 = y;
+ x1 = x + 50;
+ x2 = x - 50;
+ assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
+
+ /* endpoint outside y range; should be blocked */
+ y1 = y - 1000;
+ y2 = y - 1000;
+ x1 = x + 50;
+ x2 = x - 50;
+ assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
+
+ /* endpoint outside y range */
+ y1 = y + 150;
+ y2 = y + 150;
+ x1 = x + 50;
+ x2 = x - 50;
+ assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
}
static void
diff --git a/test/xi2/protocol-eventconvert.c b/test/xi2/protocol-eventconvert.c
index bb3177cc1..395774774 100644
--- a/test/xi2/protocol-eventconvert.c
+++ b/test/xi2/protocol-eventconvert.c
@@ -984,6 +984,221 @@ test_convert_XITouchOwnershipEvent(void)
}
}
+static void
+test_XIBarrierEvent(BarrierEvent *in)
+{
+ xXIBarrierEvent *out, *swapped;
+ int count;
+ int rc;
+ int eventlen;
+ FP3232 value;
+
+ rc = EventToXI((InternalEvent*)in, (xEvent**)&out, &count);
+ assert(rc == BadMatch);
+
+ rc = EventToCore((InternalEvent*)in, (xEvent**)&out, &count);
+ assert(rc == BadMatch);
+
+ rc = EventToXI2((InternalEvent*)in, (xEvent**)&out);
+
+ assert(out->type == GenericEvent);
+ assert(out->extension == 0); /* IReqCode defaults to 0 */
+ assert(out->evtype == GetXI2Type(in->type));
+ assert(out->time == in->time);
+ assert(out->deviceid == in->deviceid);
+ assert(out->sourceid == in->sourceid);
+ assert(out->barrier == in->barrierid);
+ assert(out->flags == in->flags);
+ assert(out->event == in->window);
+ assert(out->root == in->root);
+ assert(out->dtime == in->dt);
+ assert(out->eventid == in->event_id);
+ assert(out->root_x == double_to_fp1616(in->root_x));
+ assert(out->root_y == double_to_fp1616(in->root_y));
+
+ value = double_to_fp3232(in->dx);
+ assert(out->dx.integral == value.integral);
+ assert(out->dx.frac == value.frac);
+ value = double_to_fp3232(in->dy);
+ assert(out->dy.integral == value.integral);
+ assert(out->dy.frac == value.frac);
+
+ eventlen = sizeof(xEvent) + out->length * 4;
+ swapped = calloc(1, eventlen);
+ XI2EventSwap((xGenericEvent *) out, (xGenericEvent *) swapped);
+
+ swaps(&swapped->sequenceNumber);
+ swapl(&swapped->length);
+ swaps(&swapped->evtype);
+ swaps(&swapped->deviceid);
+ swapl(&swapped->time);
+ swapl(&swapped->eventid);
+ swapl(&swapped->root);
+ swapl(&swapped->event);
+ swapl(&swapped->barrier);
+ swapl(&swapped->dtime);
+ swaps(&swapped->sourceid);
+ swapl(&swapped->root_x);
+ swapl(&swapped->root_y);
+ swapl(&swapped->dx.integral);
+ swapl(&swapped->dx.frac);
+ swapl(&swapped->dy.integral);
+ swapl(&swapped->dy.frac);
+
+ assert(memcmp(swapped, out, eventlen) == 0);
+
+ free(swapped);
+ free(out);
+}
+
+static void
+test_convert_XIBarrierEvent(void)
+{
+ BarrierEvent in;
+
+ memset(&in, 0, sizeof(in));
+ in.header = ET_Internal;
+ in.type = ET_BarrierHit;
+ in.length = sizeof(in);
+ in.time = 0;
+ in.deviceid = 1;
+ in.sourceid = 2;
+
+ test_XIBarrierEvent(&in);
+
+ in.deviceid = 1;
+ while(in.deviceid & 0xFFFF) {
+ test_XIBarrierEvent(&in);
+ in.deviceid <<= 1;
+ }
+ in.deviceid = 0;
+
+ in.sourceid = 1;
+ while(in.sourceid & 0xFFFF) {
+ test_XIBarrierEvent(&in);
+ in.sourceid <<= 1;
+ }
+ in.sourceid = 0;
+
+ in.flags = 1;
+ while(in.flags) {
+ test_XIBarrierEvent(&in);
+ in.flags <<= 1;
+ }
+
+ in.barrierid = 1;
+ while(in.barrierid) {
+ test_XIBarrierEvent(&in);
+ in.barrierid <<= 1;
+ }
+
+ in.dt = 1;
+ while(in.dt) {
+ test_XIBarrierEvent(&in);
+ in.dt <<= 1;
+ }
+
+ in.event_id = 1;
+ while(in.event_id) {
+ test_XIBarrierEvent(&in);
+ in.event_id <<= 1;
+ }
+
+ in.window = 1;
+ while(in.window) {
+ test_XIBarrierEvent(&in);
+ in.window <<= 1;
+ }
+
+ in.root = 1;
+ while(in.root) {
+ test_XIBarrierEvent(&in);
+ in.root <<= 1;
+ }
+
+ /* pseudo-random 16 bit numbers */
+ in.root_x = 1;
+ test_XIBarrierEvent(&in);
+ in.root_x = 1.3;
+ test_XIBarrierEvent(&in);
+ in.root_x = 264.908;
+ test_XIBarrierEvent(&in);
+ in.root_x = 35638.292;
+ test_XIBarrierEvent(&in);
+
+ in.root_x = -1;
+ test_XIBarrierEvent(&in);
+ in.root_x = -1.3;
+ test_XIBarrierEvent(&in);
+ in.root_x = -264.908;
+ test_XIBarrierEvent(&in);
+ in.root_x = -35638.292;
+ test_XIBarrierEvent(&in);
+
+ in.root_y = 1;
+ test_XIBarrierEvent(&in);
+ in.root_y = 1.3;
+ test_XIBarrierEvent(&in);
+ in.root_y = 264.908;
+ test_XIBarrierEvent(&in);
+ in.root_y = 35638.292;
+ test_XIBarrierEvent(&in);
+
+ in.root_y = -1;
+ test_XIBarrierEvent(&in);
+ in.root_y = -1.3;
+ test_XIBarrierEvent(&in);
+ in.root_y = -264.908;
+ test_XIBarrierEvent(&in);
+ in.root_y = -35638.292;
+ test_XIBarrierEvent(&in);
+
+ /* equally pseudo-random 32 bit numbers */
+ in.dx = 1;
+ test_XIBarrierEvent(&in);
+ in.dx = 1.3;
+ test_XIBarrierEvent(&in);
+ in.dx = 264.908;
+ test_XIBarrierEvent(&in);
+ in.dx = 35638.292;
+ test_XIBarrierEvent(&in);
+ in.dx = 2947813871.2342;
+ test_XIBarrierEvent(&in);
+
+ in.dx = -1;
+ test_XIBarrierEvent(&in);
+ in.dx = -1.3;
+ test_XIBarrierEvent(&in);
+ in.dx = -264.908;
+ test_XIBarrierEvent(&in);
+ in.dx = -35638.292;
+ test_XIBarrierEvent(&in);
+ in.dx = -2947813871.2342;
+ test_XIBarrierEvent(&in);
+
+ in.dy = 1;
+ test_XIBarrierEvent(&in);
+ in.dy = 1.3;
+ test_XIBarrierEvent(&in);
+ in.dy = 264.908;
+ test_XIBarrierEvent(&in);
+ in.dy = 35638.292;
+ test_XIBarrierEvent(&in);
+ in.dy = 2947813871.2342;
+ test_XIBarrierEvent(&in);
+
+ in.dy = -1;
+ test_XIBarrierEvent(&in);
+ in.dy = -1.3;
+ test_XIBarrierEvent(&in);
+ in.dy = -264.908;
+ test_XIBarrierEvent(&in);
+ in.dy = -35638.292;
+ test_XIBarrierEvent(&in);
+ in.dy = -2947813871.2342;
+ test_XIBarrierEvent(&in);
+}
+
int
main(int argc, char **argv)
{
@@ -992,6 +1207,7 @@ main(int argc, char **argv)
test_convert_XIDeviceEvent();
test_convert_XIDeviceChangedEvent();
test_convert_XITouchOwnershipEvent();
+ test_convert_XIBarrierEvent();
return 0;
}
diff --git a/xfixes/cursor.c b/xfixes/cursor.c
index ffee4d6ab..568e717fa 100644
--- a/xfixes/cursor.c
+++ b/xfixes/cursor.c
@@ -56,12 +56,11 @@
#include "windowstr.h"
#include "xace.h"
#include "list.h"
-#include "exglobals.h"
+#include "xibarriers.h"
static RESTYPE CursorClientType;
static RESTYPE CursorHideCountType;
static RESTYPE CursorWindowType;
-RESTYPE PointerBarrierType;
static CursorPtr CursorCurrent[MAXDEVICES];
static DevPrivateKeyRec CursorScreenPrivateKeyRec;
@@ -113,16 +112,6 @@ typedef struct _CursorHideCountRec {
XID resource;
} CursorHideCountRec;
-typedef struct PointerBarrierClient *PointerBarrierClientPtr;
-
-struct PointerBarrierClient {
- ScreenPtr screen;
- struct PointerBarrier barrier;
- struct xorg_list entry;
- int num_devices;
- int *device_ids; /* num_devices */
-};
-
/*
* Wrap DisplayCursor to catch cursor change events
*/
@@ -130,9 +119,7 @@ struct PointerBarrierClient {
typedef struct _CursorScreen {
DisplayCursorProcPtr DisplayCursor;
CloseScreenProcPtr CloseScreen;
- ConstrainCursorHarderProcPtr ConstrainCursorHarder;
CursorHideCountPtr pCursorHideCounts;
- struct xorg_list barriers;
} CursorScreenRec, *CursorScreenPtr;
#define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey))
@@ -199,11 +186,9 @@ CursorCloseScreen(ScreenPtr pScreen)
Bool ret;
_X_UNUSED CloseScreenProcPtr close_proc;
_X_UNUSED DisplayCursorProcPtr display_proc;
- _X_UNUSED ConstrainCursorHarderProcPtr constrain_proc;
Unwrap(cs, pScreen, CloseScreen, close_proc);
Unwrap(cs, pScreen, DisplayCursor, display_proc);
- Unwrap(cs, pScreen, ConstrainCursorHarder, constrain_proc);
deleteCursorHideCountsForScreen(pScreen);
ret = (*pScreen->CloseScreen) (pScreen);
free(cs);
@@ -1013,384 +998,15 @@ CursorFreeWindow(pointer data, XID id)
return 1;
}
-static BOOL
-barrier_is_horizontal(const struct PointerBarrier *barrier)
-{
- return barrier->y1 == barrier->y2;
-}
-
-static BOOL
-barrier_is_vertical(const struct PointerBarrier *barrier)
-{
- return barrier->x1 == barrier->x2;
-}
-
-/**
- * @return The set of barrier movement directions the movement vector
- * x1/y1 → x2/y2 represents.
- */
-int
-barrier_get_direction(int x1, int y1, int x2, int y2)
-{
- int direction = 0;
-
- /* which way are we trying to go */
- if (x2 > x1)
- direction |= BarrierPositiveX;
- if (x2 < x1)
- direction |= BarrierNegativeX;
- if (y2 > y1)
- direction |= BarrierPositiveY;
- if (y2 < y1)
- direction |= BarrierNegativeY;
-
- return direction;
-}
-
-/**
- * Test if the barrier may block movement in the direction defined by
- * x1/y1 → x2/y2. This function only tests whether the directions could be
- * blocked, it does not test if the barrier actually blocks the movement.
- *
- * @return TRUE if the barrier blocks the direction of movement or FALSE
- * otherwise.
- */
-BOOL
-barrier_is_blocking_direction(const struct PointerBarrier * barrier,
- int direction)
-{
- /* Barriers define which way is ok, not which way is blocking */
- return (barrier->directions & direction) != direction;
-}
-
-/**
- * Test if the movement vector x1/y1 → x2/y2 is intersecting with the
- * barrier. A movement vector with the startpoint or endpoint adjacent to
- * the barrier itself counts as intersecting.
- *
- * @param x1 X start coordinate of movement vector
- * @param y1 Y start coordinate of movement vector
- * @param x2 X end coordinate of movement vector
- * @param y2 Y end coordinate of movement vector
- * @param[out] distance The distance between the start point and the
- * intersection with the barrier (if applicable).
- * @return TRUE if the barrier intersects with the given vector
- */
-BOOL
-barrier_is_blocking(const struct PointerBarrier * barrier,
- int x1, int y1, int x2, int y2, double *distance)
-{
- BOOL rc = FALSE;
- float ua, ub, ud;
- int dir = barrier_get_direction(x1, y1, x2, y2);
-
- /* Algorithm below doesn't handle edge cases well, hence the extra
- * checks. */
- if (barrier_is_vertical(barrier)) {
- /* handle immediate barrier adjacency, moving away */
- if (dir & BarrierPositiveX && x1 == barrier->x1)
- return FALSE;
- if (dir & BarrierNegativeX && x1 == (barrier->x1 - 1))
- return FALSE;
- /* startpoint adjacent to barrier, moving towards -> block */
- if (dir & BarrierPositiveX && x1 == (barrier->x1 - 1) && y1 >= barrier->y1 && y1 <= barrier->y2) {
- *distance = 0;
- return TRUE;
- }
- if (dir & BarrierNegativeX && x1 == barrier->x1 && y1 >= barrier->y1 && y1 <= barrier->y2) {
- *distance = 0;
- return TRUE;
- }
- }
- else {
- /* handle immediate barrier adjacency, moving away */
- if (dir & BarrierPositiveY && y1 == barrier->y1)
- return FALSE;
- if (dir & BarrierNegativeY && y1 == (barrier->y1 - 1))
- return FALSE;
- /* startpoint adjacent to barrier, moving towards -> block */
- if (dir & BarrierPositiveY && y1 == (barrier->y1 - 1) && x1 >= barrier->x1 && x1 <= barrier->x2) {
- *distance = 0;
- return TRUE;
- }
- if (dir & BarrierNegativeY && y1 == barrier->y1 && x1 >= barrier->x1 && x1 <= barrier->x2) {
- *distance = 0;
- return TRUE;
- }
- }
-
- /* not an edge case, compute distance */
- ua = 0;
- ud = (barrier->y2 - barrier->y1) * (x2 - x1) - (barrier->x2 -
- barrier->x1) * (y2 - y1);
- if (ud != 0) {
- ua = ((barrier->x2 - barrier->x1) * (y1 - barrier->y1) -
- (barrier->y2 - barrier->y1) * (x1 - barrier->x1)) / ud;
- ub = ((x2 - x1) * (y1 - barrier->y1) -
- (y2 - y1) * (x1 - barrier->x1)) / ud;
- if (ua < 0 || ua > 1 || ub < 0 || ub > 1)
- ua = 0;
- }
-
- if (ua > 0 && ua <= 1) {
- double ix = barrier->x1 + ua * (barrier->x2 - barrier->x1);
- double iy = barrier->y1 + ua * (barrier->y2 - barrier->y1);
-
- *distance = sqrt(pow(x1 - ix, 2) + pow(y1 - iy, 2));
- rc = TRUE;
- }
-
- return rc;
-}
-
-static BOOL
-barrier_blocks_device(struct PointerBarrierClient *client,
- DeviceIntPtr dev)
-{
- int i;
- int master_id;
-
- /* Clients with no devices are treated as
- * if they specified XIAllDevices. */
- if (client->num_devices == 0)
- return TRUE;
-
- master_id = GetMaster(dev, POINTER_OR_FLOAT)->id;
-
- for (i = 0; i < client->num_devices; i++) {
- int device_id = client->device_ids[i];
- if (device_id == XIAllDevices ||
- device_id == XIAllMasterDevices ||
- device_id == master_id)
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * Find the nearest barrier 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
- * @param y1 Y start coordinate of movement vector
- * @param x2 X end coordinate of movement vector
- * @param y2 Y end coordinate of movement vector
- * @return The barrier nearest to the movement origin that blocks this movement.
- */
-static struct PointerBarrier *
-barrier_find_nearest(CursorScreenPtr cs, DeviceIntPtr dev,
- int dir,
- int x1, int y1, int x2, int y2)
-{
- struct PointerBarrierClient *c;
- struct PointerBarrier *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) {
- struct PointerBarrier *b = &c->barrier;
- double distance;
-
- if (!barrier_is_blocking_direction(b, dir))
- continue;
-
- if (!barrier_blocks_device(c, dev))
- continue;
-
- if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) {
- if (min_distance > distance) {
- min_distance = distance;
- nearest = b;
- }
- }
- }
-
- return nearest;
-}
-
-/**
- * Clamp to the given barrier given the movement direction specified in dir.
- *
- * @param barrier The barrier to clamp to
- * @param dir The movement direction
- * @param[out] x The clamped x coordinate.
- * @param[out] y The clamped x coordinate.
- */
-void
-barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x,
- int *y)
-{
- if (barrier_is_vertical(barrier)) {
- if ((dir & BarrierNegativeX) & ~barrier->directions)
- *x = barrier->x1;
- if ((dir & BarrierPositiveX) & ~barrier->directions)
- *x = barrier->x1 - 1;
- }
- if (barrier_is_horizontal(barrier)) {
- if ((dir & BarrierNegativeY) & ~barrier->directions)
- *y = barrier->y1;
- if ((dir & BarrierPositiveY) & ~barrier->directions)
- *y = barrier->y1 - 1;
- }
-}
-
-static void
-CursorConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode,
- int *x, int *y)
-{
- CursorScreenPtr cs = GetCursorScreen(screen);
-
- if (!xorg_list_is_empty(&cs->barriers) && !IsFloating(dev) &&
- mode == Relative) {
- int ox, oy;
- int dir;
- int i;
- struct PointerBarrier *nearest = NULL;
-
- /* where are we coming from */
- miPointerGetPosition(dev, &ox, &oy);
-
- /* How this works:
- * Given the origin and the movement vector, get the nearest barrier
- * to the origin that is blocking the movement.
- * Clamp to that barrier.
- * Then, check from the clamped intersection to the original
- * destination, again finding the nearest barrier and clamping.
- */
- dir = barrier_get_direction(ox, oy, *x, *y);
-
-#define MAX_BARRIERS 2
- for (i = 0; i < MAX_BARRIERS; i++) {
- nearest = barrier_find_nearest(cs, dev, dir, ox, oy, *x, *y);
- if (!nearest)
- break;
-
- barrier_clamp_to_barrier(nearest, dir, x, y);
-
- if (barrier_is_vertical(nearest)) {
- dir &= ~(BarrierNegativeX | BarrierPositiveX);
- ox = *x;
- }
- else if (barrier_is_horizontal(nearest)) {
- dir &= ~(BarrierNegativeY | BarrierPositiveY);
- oy = *y;
- }
- }
- }
-
- if (cs->ConstrainCursorHarder) {
- screen->ConstrainCursorHarder = cs->ConstrainCursorHarder;
- screen->ConstrainCursorHarder(dev, screen, mode, x, y);
- screen->ConstrainCursorHarder = CursorConstrainCursorHarder;
- }
-}
-
-static int
-CreatePointerBarrierClient(ScreenPtr screen, ClientPtr client,
- xXFixesCreatePointerBarrierReq * stuff,
- PointerBarrierClientPtr *client_out)
-{
- CursorScreenPtr cs = GetCursorScreen(screen);
- int err;
- int size;
- int i;
- CARD16 *in_devices;
- struct PointerBarrierClient *ret;
-
- size = sizeof(*ret) + sizeof(int) * stuff->num_devices;
- ret = malloc(size);
-
- *client_out = NULL;
-
- if (!ret) {
- return BadAlloc;
- }
-
- ret->screen = screen;
- ret->num_devices = stuff->num_devices;
- if (ret->num_devices > 0)
- ret->device_ids = (int*)&ret[1];
- else
- ret->device_ids = NULL;
-
- in_devices = (CARD16 *) &stuff[1];
- for (i = 0; i < stuff->num_devices; i++) {
- int device_id = in_devices[i];
- DeviceIntPtr device;
-
- if ((err = dixLookupDevice (&device, device_id,
- client, DixReadAccess))) {
- client->errorValue = device_id;
- goto error;
- }
-
- if (!IsMaster (device)) {
- client->errorValue = device_id;
- err = BadDevice;
- goto error;
- }
-
- ret->device_ids[i] = device_id;
- }
-
- ret->barrier.x1 = min(stuff->x1, stuff->x2);
- ret->barrier.x2 = max(stuff->x1, stuff->x2);
- ret->barrier.y1 = min(stuff->y1, stuff->y2);
- ret->barrier.y2 = max(stuff->y1, stuff->y2);
- ret->barrier.directions = stuff->directions & 0x0f;
- if (barrier_is_horizontal(&ret->barrier))
- ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
- if (barrier_is_vertical(&ret->barrier))
- ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY);
- xorg_list_add(&ret->entry, &cs->barriers);
-
- *client_out = ret;
- return Success;
-
- error:
- free(ret);
- return err;
-}
-
int
ProcXFixesCreatePointerBarrier(ClientPtr client)
{
- int err;
- WindowPtr pWin;
- struct PointerBarrierClient *barrier;
- struct PointerBarrier b;
-
REQUEST(xXFixesCreatePointerBarrierReq);
REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq, pad_to_int32(stuff->num_devices));
LEGAL_NEW_RESOURCE(stuff->barrier, client);
- err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
- if (err != Success) {
- client->errorValue = stuff->window;
- return err;
- }
-
- b.x1 = stuff->x1;
- b.x2 = stuff->x2;
- b.y1 = stuff->y1;
- b.y2 = stuff->y2;
-
- if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b))
- return BadValue;
-
- /* no 0-sized barriers */
- if (barrier_is_horizontal(&b) && barrier_is_vertical(&b))
- return BadValue;
-
- if ((err = CreatePointerBarrierClient(pWin->drawable.pScreen,
- client, stuff, &barrier)))
- return err;
-
- if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
- return BadAlloc;
-
- return Success;
+ return XICreatePointerBarrier(client, stuff);
}
int
@@ -1418,49 +1034,14 @@ SProcXFixesCreatePointerBarrier(ClientPtr client)
return ProcXFixesVector[stuff->xfixesReqType] (client);
}
-static int
-CursorFreeBarrier(void *data, XID id)
-{
- struct PointerBarrierClient *b = NULL, *barrier;
- ScreenPtr screen;
- CursorScreenPtr cs;
-
- barrier = container_of(data, struct PointerBarrierClient, barrier);
-
- screen = barrier->screen;
- cs = GetCursorScreen(screen);
-
- /* find and unlink from the screen private */
- xorg_list_for_each_entry(b, &cs->barriers, entry) {
- if (b == barrier) {
- xorg_list_del(&b->entry);
- break;
- }
- }
-
- free(barrier);
- return Success;
-}
-
int
ProcXFixesDestroyPointerBarrier(ClientPtr client)
{
- int err;
- void *barrier;
-
REQUEST(xXFixesDestroyPointerBarrierReq);
REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
- err = dixLookupResourceByType((void **) &barrier, stuff->barrier,
- PointerBarrierType, client, DixDestroyAccess);
- if (err != Success) {
- client->errorValue = stuff->barrier;
- return err;
- }
-
- FreeResource(stuff->barrier, RT_NONE);
- return Success;
+ return XIDestroyPointerBarrier(client, stuff);
}
int
@@ -1492,10 +1073,8 @@ XFixesCursorInit(void)
cs = (CursorScreenPtr) calloc(1, sizeof(CursorScreenRec));
if (!cs)
return FALSE;
- xorg_list_init(&cs->barriers);
Wrap(cs, pScreen, CloseScreen, CursorCloseScreen);
Wrap(cs, pScreen, DisplayCursor, CursorDisplayCursor);
- Wrap(cs, pScreen, ConstrainCursorHarder, CursorConstrainCursorHarder);
cs->pCursorHideCounts = NULL;
SetCursorScreen(pScreen, cs);
}
@@ -1505,9 +1084,6 @@ XFixesCursorInit(void)
"XFixesCursorHideCount");
CursorWindowType = CreateNewResourceType(CursorFreeWindow,
"XFixesCursorWindow");
- PointerBarrierType = CreateNewResourceType(CursorFreeBarrier,
- "XFixesPointerBarrier");
- return CursorClientType && CursorHideCountType && CursorWindowType &&
- PointerBarrierType;
+ return CursorClientType && CursorHideCountType && CursorWindowType;
}
diff --git a/xfixes/xfixes.h b/xfixes/xfixes.h
index 19af09f7d..98828710f 100644
--- a/xfixes/xfixes.h
+++ b/xfixes/xfixes.h
@@ -30,7 +30,6 @@
#include "resource.h"
extern _X_EXPORT RESTYPE RegionResType;
-extern _X_EXPORT RESTYPE PointerBarrierType;
extern _X_EXPORT int XFixesErrorBase;
#define VERIFY_REGION(pRegion, rid, client, mode) \
@@ -52,20 +51,6 @@ extern _X_EXPORT int XFixesErrorBase;
extern _X_EXPORT RegionPtr
XFixesRegionCopy(RegionPtr pRegion);
-struct PointerBarrier {
- CARD16 x1, x2, y1, y2;
- CARD32 directions;
-};
-
-extern int
- barrier_get_direction(int, int, int, int);
-extern BOOL
-barrier_is_blocking(const struct PointerBarrier *, int, int, int, int,
- double *);
-extern BOOL barrier_is_blocking_direction(const struct PointerBarrier *, int);
-extern void
-
-barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x,
- int *y);
+#include "xibarriers.h"
#endif /* _XFIXES_H_ */