barriers: Support line and ray barriers
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@mecheye.net> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
0a5a0d7c24
commit
707b4dc61f
|
@ -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;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
extern _X_EXPORT RESTYPE PointerBarrierType;
|
||||
|
||||
struct PointerBarrier {
|
||||
CARD16 x1, x2, y1, y2;
|
||||
INT16 x1, x2, y1, y2;
|
||||
CARD32 directions;
|
||||
};
|
||||
|
||||
|
|
26
test/fixes.c
26
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
|
||||
|
|
Loading…
Reference in New Issue
Block a user