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