summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Xi/xibarriers.c46
-rw-r--r--Xi/xibarriers.h2
-rw-r--r--test/fixes.c26
3 files changed, 67 insertions, 7 deletions
diff --git a/Xi/xibarriers.c b/Xi/xibarriers.c
index a65d2080b..27b21eedb 100644
--- a/Xi/xibarriers.c
+++ b/Xi/xibarriers.c
@@ -140,6 +140,19 @@ barrier_is_blocking_direction(const struct PointerBarrier * barrier,
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))
@@ -171,7 +184,7 @@ barrier_is_blocking(const struct PointerBarrier * barrier,
return FALSE;
y = F(t, y1, y2);
- if (y < barrier->y1 || y > barrier->y2)
+ if (!inside_segment(y, barrier->y1, barrier->y2))
return FALSE;
*distance = sqrt((pow(y - y1, 2) + pow(barrier->x1 - x1, 2)));
@@ -188,7 +201,7 @@ barrier_is_blocking(const struct PointerBarrier * barrier,
return FALSE;
x = F(t, x1, x2);
- if (x < barrier->x1 || x > barrier->x2)
+ if (!inside_segment(x, barrier->x1, barrier->x2))
return FALSE;
*distance = sqrt((pow(x - x1, 2) + pow(barrier->y1 - y1, 2)));
@@ -428,6 +441,18 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
*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,
@@ -491,10 +516,12 @@ CreatePointerBarrierClient(ClientPtr client,
ret->release_event_id = 0;
ret->hit = FALSE;
ret->seen = 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);
- ret->barrier.y2 = max(stuff->y1, stuff->y2);
+ 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);
@@ -587,6 +614,13 @@ XICreatePointerBarrier(ClientPtr client,
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;
diff --git a/Xi/xibarriers.h b/Xi/xibarriers.h
index f29bb6c8f..bdcb0b289 100644
--- a/Xi/xibarriers.h
+++ b/Xi/xibarriers.h
@@ -11,7 +11,7 @@
extern _X_EXPORT RESTYPE PointerBarrierType;
struct PointerBarrier {
- CARD16 x1, x2, y1, y2;
+ INT16 x1, x2, y1, y2;
CARD32 directions;
};
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