[PATCH 16/29] barriers: Support line and ray barriers

Peter Hutterer peter.hutterer at who-t.net
Tue Dec 11 23:19:09 PST 2012


From: "Jasper St. Pierre" <jstpierre at mecheye.net>

This allows clients to add barriers that extend to the edge of the
screen. Clients are encouraged to use these instead of precise coordinates
in these cases to help prevent pointer leaks.

Signed-off-by: Jasper St. Pierre <jstpierre at mecheye.net>
---
 Xi/xibarriers.c | 46 ++++++++++++++++++++++++++++++++++++++++------
 Xi/xibarriers.h |  2 +-
 test/fixes.c    | 26 ++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/Xi/xibarriers.c b/Xi/xibarriers.c
index a65d208..27b21ee 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 f29bb6c..bdcb0b2 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 7807c73..4ac6750 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
-- 
1.8.0.1



More information about the xorg-devel mailing list