fixes: Add support for pointer barriers
Implements pointer barriers as specified by version 5 of the XFIXES protocol. Barriers are axis-aligned, zero-width lines that block pointer movement for relative input devices. Barriers may block motion in either the positive or negative direction, or both. v3: - Fix off-by-one in version_requests array - Port to non-glib test harness - Fix review notes from Søren Sandmann Pedersen, add tests to match Co-authored-by: Peter Hutterer <peter.hutterer@who-t.net> Tested-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
4621bb270a
commit
d45f5b2493
|
@ -810,7 +810,7 @@ dnl specific modules against it
|
|||
PKG_CHECK_MODULES(PIXMAN, $LIBPIXMAN)
|
||||
REQUIRED_LIBS="$REQUIRED_LIBS $LIBPIXMAN $LIBXFONT xau"
|
||||
|
||||
REQUIRED_MODULES="[fixesproto >= 4.1] [damageproto >= 1.1] [xcmiscproto >= 1.2.0] [xtrans >= 1.2.2] [bigreqsproto >= 1.1.0] $SDK_REQUIRED_MODULES"
|
||||
REQUIRED_MODULES="[fixesproto >= 5.0] [damageproto >= 1.1] [xcmiscproto >= 1.2.0] [xtrans >= 1.2.2] [bigreqsproto >= 1.1.0] $SDK_REQUIRED_MODULES"
|
||||
|
||||
if test "x$CONFIG_UDEV" = xyes &&
|
||||
{ test "x$CONFIG_DBUS_API" = xyes || test "x$CONFIG_HAL" = xyes; }; then
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
#define SERVER_XF86VIDMODE_MINOR_VERSION 2
|
||||
|
||||
/* Fixes */
|
||||
#define SERVER_XFIXES_MAJOR_VERSION 4
|
||||
#define SERVER_XFIXES_MAJOR_VERSION 5
|
||||
#define SERVER_XFIXES_MINOR_VERSION 0
|
||||
|
||||
/* X Input */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
if ENABLE_UNIT_TESTS
|
||||
if HAVE_LD_WRAP
|
||||
SUBDIRS= . xi2
|
||||
noinst_PROGRAMS = xkb input xtest list misc
|
||||
noinst_PROGRAMS = xkb input xtest list misc fixes
|
||||
check_LTLIBRARIES = libxservertest.la
|
||||
|
||||
TESTS=$(noinst_PROGRAMS)
|
||||
|
@ -19,6 +19,7 @@ input_LDADD=$(TEST_LDADD)
|
|||
xtest_LDADD=$(TEST_LDADD)
|
||||
list_LDADD=$(TEST_LDADD)
|
||||
misc_LDADD=$(TEST_LDADD)
|
||||
fixes_LDADD=$(TEST_LDADD)
|
||||
|
||||
libxservertest_la_LIBADD = \
|
||||
$(XSERVER_LIBS) \
|
||||
|
|
327
test/fixes.c
Normal file
327
test/fixes.c
Normal file
|
@ -0,0 +1,327 @@
|
|||
/**
|
||||
* Copyright © 2011 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <X11/X.h>
|
||||
#include <xfixesint.h>
|
||||
#include <X11/extensions/xfixeswire.h>
|
||||
|
||||
static void
|
||||
_fixes_test_direction(struct PointerBarrier *barrier, int d[4], int permitted)
|
||||
{
|
||||
BOOL blocking;
|
||||
int i, j;
|
||||
int dir = barrier_get_direction(d[0], d[1], d[2], d[3]);
|
||||
|
||||
barrier->directions = 0;
|
||||
blocking = barrier_is_blocking_direction(barrier, dir);
|
||||
assert(blocking);
|
||||
|
||||
for (j = 0; j <= BarrierNegativeY; j++)
|
||||
{
|
||||
for (i = 0; i <= BarrierNegativeY; i++)
|
||||
{
|
||||
barrier->directions |= 1 << i;
|
||||
blocking = barrier_is_blocking_direction(barrier, dir);
|
||||
assert((barrier->directions & permitted) == permitted ? !blocking : blocking);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
fixes_pointer_barrier_direction_test(void)
|
||||
{
|
||||
struct PointerBarrier barrier;
|
||||
|
||||
int x = 100;
|
||||
int y = 100;
|
||||
|
||||
int directions[8][4] = {
|
||||
{ x, y, x, y + 100}, /* S */
|
||||
{ x + 50, y, x - 50, y + 100}, /* SW */
|
||||
{ x + 100, y, x, y}, /* W */
|
||||
{ x + 100, y + 50, x, y - 50}, /* NW */
|
||||
{ x, y + 100, x, y}, /* N */
|
||||
{ x - 50, y + 100, x + 50, y}, /* NE */
|
||||
{ x, y, x + 100, y}, /* E */
|
||||
{ x, y - 50, x + 100, y + 50}, /* SE */
|
||||
};
|
||||
|
||||
barrier.x1 = x;
|
||||
barrier.x2 = x;
|
||||
barrier.y1 = y - 50;
|
||||
barrier.y2 = y + 49;
|
||||
|
||||
|
||||
_fixes_test_direction(&barrier, directions[0], BarrierPositiveY);
|
||||
_fixes_test_direction(&barrier, directions[1], BarrierPositiveY | BarrierNegativeX);
|
||||
_fixes_test_direction(&barrier, directions[2], BarrierNegativeX);
|
||||
_fixes_test_direction(&barrier, directions[3], BarrierNegativeY | BarrierNegativeX);
|
||||
_fixes_test_direction(&barrier, directions[4], BarrierNegativeY);
|
||||
_fixes_test_direction(&barrier, directions[5], BarrierPositiveX | BarrierNegativeY);
|
||||
_fixes_test_direction(&barrier, directions[6], BarrierPositiveX);
|
||||
_fixes_test_direction(&barrier, directions[7], BarrierPositiveY | BarrierPositiveX);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fixes_pointer_barriers_test(void)
|
||||
{
|
||||
struct PointerBarrier barrier;
|
||||
int x1, y1, x2, y2;
|
||||
double distance;
|
||||
|
||||
int x = 100;
|
||||
int y = 100;
|
||||
|
||||
/* vert barrier */
|
||||
barrier.x1 = x;
|
||||
barrier.x2 = x;
|
||||
barrier.y1 = y - 50;
|
||||
barrier.y2 = y + 50;
|
||||
|
||||
/* across at half-way */
|
||||
x1 = x + 1;
|
||||
x2 = x - 1;
|
||||
y1 = y;
|
||||
y2 = y;
|
||||
assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
assert(distance == 1);
|
||||
|
||||
/* definitely not across */
|
||||
x1 = x + 10;
|
||||
x2 = x + 5;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* across, but outside of y range */
|
||||
x1 = x + 1;
|
||||
x2 = x -1;
|
||||
y1 = y + 100;
|
||||
y2 = y + 100;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* across, diagonally */
|
||||
x1 = x + 5;
|
||||
x2 = x - 5;
|
||||
y1 = y + 5;
|
||||
y2 = y - 5;
|
||||
assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* across but outside boundary, diagonally */
|
||||
x1 = x + 5;
|
||||
x2 = x - 5;
|
||||
y1 = y + 100;
|
||||
y2 = y + 50;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* edge case: startpoint of movement on barrier → blocking */
|
||||
x1 = x;
|
||||
x2 = x - 1;
|
||||
y1 = y;
|
||||
y2 = y;
|
||||
assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* edge case: startpoint of movement on barrier → not blocking, positive */
|
||||
x1 = x;
|
||||
x2 = x + 1;
|
||||
y1 = y;
|
||||
y2 = y;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* edge case: startpoint of movement on barrier → not blocking, negative */
|
||||
x1 = x - 1;
|
||||
x2 = x - 2;
|
||||
y1 = y;
|
||||
y2 = y;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* edge case: endpoint of movement on barrier → blocking */
|
||||
x1 = x + 1;
|
||||
x2 = x;
|
||||
y1 = y;
|
||||
y2 = y;
|
||||
assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* startpoint on barrier but outside y range */
|
||||
x1 = x;
|
||||
x2 = x - 1;
|
||||
y1 = y + 100;
|
||||
y2 = y + 100;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* endpoint on barrier but outside y range */
|
||||
x1 = x + 1;
|
||||
x2 = x;
|
||||
y1 = y + 100;
|
||||
y2 = y + 100;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
|
||||
/* horizontal barrier */
|
||||
barrier.x1 = x - 50;
|
||||
barrier.x2 = x + 50;
|
||||
barrier.y1 = y;
|
||||
barrier.y2 = y;
|
||||
|
||||
/* across at half-way */
|
||||
x1 = x;
|
||||
x2 = x;
|
||||
y1 = y - 1;
|
||||
y2 = y + 1;
|
||||
assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* definitely not across */
|
||||
y1 = y + 10;
|
||||
y2 = y + 5;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* across, but outside of y range */
|
||||
x1 = x + 100;
|
||||
x2 = x + 100;
|
||||
y1 = y + 1;
|
||||
y2 = y -1;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* across, diagonally */
|
||||
y1 = y + 5;
|
||||
y2 = y - 5;
|
||||
x1 = x + 5;
|
||||
x2 = x - 5;
|
||||
assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* across but outside boundary, diagonally */
|
||||
y1 = y + 5;
|
||||
y2 = y - 5;
|
||||
x1 = x + 100;
|
||||
x2 = x + 50;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* edge case: startpoint of movement on barrier → blocking */
|
||||
y1 = y;
|
||||
y2 = y - 1;
|
||||
x1 = x;
|
||||
x2 = x;
|
||||
assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* edge case: startpoint of movement on barrier → not blocking, positive */
|
||||
y1 = y;
|
||||
y2 = y + 1;
|
||||
x1 = x;
|
||||
x2 = x;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* edge case: startpoint of movement on barrier → not blocking, negative */
|
||||
y1 = y - 1;
|
||||
y2 = y - 2;
|
||||
x1 = x;
|
||||
x2 = x;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* edge case: endpoint of movement on barrier → blocking */
|
||||
y1 = y + 1;
|
||||
y2 = y;
|
||||
x1 = x;
|
||||
x2 = x;
|
||||
assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* startpoint on barrier but outside y range */
|
||||
y1 = y;
|
||||
y2 = y - 1;
|
||||
x1 = x + 100;
|
||||
x2 = x + 100;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
/* endpoint on barrier but outside y range */
|
||||
y1 = y + 1;
|
||||
y2 = y;
|
||||
x1 = x + 100;
|
||||
x2 = x + 100;
|
||||
assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
|
||||
|
||||
}
|
||||
|
||||
static void fixes_pointer_barrier_clamp_test(void)
|
||||
{
|
||||
struct PointerBarrier barrier;
|
||||
|
||||
int x = 100;
|
||||
int y = 100;
|
||||
|
||||
int cx, cy; /* clamped */
|
||||
|
||||
/* vert barrier */
|
||||
barrier.x1 = x;
|
||||
barrier.x2 = x;
|
||||
barrier.y1 = y - 50;
|
||||
barrier.y2 = y + 49;
|
||||
barrier.directions = 0;
|
||||
|
||||
cx = INT_MAX;
|
||||
cy = INT_MAX;
|
||||
barrier_clamp_to_barrier(&barrier, BarrierPositiveX, &cx, &cy);
|
||||
assert(cx == barrier.x1 - 1);
|
||||
assert(cy == INT_MAX);
|
||||
|
||||
cx = 0;
|
||||
cy = INT_MAX;
|
||||
barrier_clamp_to_barrier(&barrier, BarrierNegativeX, &cx, &cy);
|
||||
assert(cx == barrier.x1);
|
||||
assert(cy == INT_MAX);
|
||||
|
||||
/* horiz barrier */
|
||||
barrier.x1 = x - 50;
|
||||
barrier.x2 = x + 49;
|
||||
barrier.y1 = y;
|
||||
barrier.y2 = y;
|
||||
barrier.directions = 0;
|
||||
|
||||
cx = INT_MAX;
|
||||
cy = INT_MAX;
|
||||
barrier_clamp_to_barrier(&barrier, BarrierPositiveY, &cx, &cy);
|
||||
assert(cx == INT_MAX);
|
||||
assert(cy == barrier.y1 - 1);
|
||||
|
||||
cx = INT_MAX;
|
||||
cy = 0;
|
||||
barrier_clamp_to_barrier(&barrier, BarrierNegativeY, &cx, &cy);
|
||||
assert(cx == INT_MAX);
|
||||
assert(cy == barrier.y1);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
||||
fixes_pointer_barriers_test();
|
||||
fixes_pointer_barrier_direction_test();
|
||||
fixes_pointer_barrier_clamp_test();
|
||||
|
||||
return 0;
|
||||
}
|
399
xfixes/cursor.c
399
xfixes/cursor.c
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2010 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"),
|
||||
|
@ -50,13 +51,16 @@
|
|||
#include "cursorstr.h"
|
||||
#include "dixevents.h"
|
||||
#include "servermd.h"
|
||||
#include "mipointer.h"
|
||||
#include "inputstr.h"
|
||||
#include "windowstr.h"
|
||||
#include "xace.h"
|
||||
#include "list.h"
|
||||
|
||||
static RESTYPE CursorClientType;
|
||||
static RESTYPE CursorHideCountType;
|
||||
static RESTYPE CursorWindowType;
|
||||
RESTYPE PointerBarrierType;
|
||||
static CursorPtr CursorCurrent[MAXDEVICES];
|
||||
|
||||
static DevPrivateKeyRec CursorScreenPrivateKeyRec;
|
||||
|
@ -107,6 +111,14 @@ typedef struct _CursorHideCountRec {
|
|||
XID resource;
|
||||
} CursorHideCountRec;
|
||||
|
||||
typedef struct PointerBarrierClient *PointerBarrierClientPtr;
|
||||
|
||||
struct PointerBarrierClient {
|
||||
ScreenPtr screen;
|
||||
struct PointerBarrier barrier;
|
||||
struct list entry;
|
||||
};
|
||||
|
||||
/*
|
||||
* Wrap DisplayCursor to catch cursor change events
|
||||
*/
|
||||
|
@ -114,7 +126,9 @@ typedef struct _CursorHideCountRec {
|
|||
typedef struct _CursorScreen {
|
||||
DisplayCursorProcPtr DisplayCursor;
|
||||
CloseScreenProcPtr CloseScreen;
|
||||
ConstrainCursorHarderProcPtr ConstrainCursorHarder;
|
||||
CursorHideCountPtr pCursorHideCounts;
|
||||
struct list barriers;
|
||||
} CursorScreenRec, *CursorScreenPtr;
|
||||
|
||||
#define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey))
|
||||
|
@ -184,9 +198,11 @@ CursorCloseScreen (int index, ScreenPtr pScreen)
|
|||
Bool ret;
|
||||
CloseScreenProcPtr close_proc;
|
||||
DisplayCursorProcPtr display_proc;
|
||||
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) (index, pScreen);
|
||||
free(cs);
|
||||
|
@ -1029,6 +1045,382 @@ 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 (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 (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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, 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 */
|
||||
|
||||
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_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 (!list_is_empty(&cs->barriers) && !IsFloating(dev) && mode == Relative) {
|
||||
int ox, oy;
|
||||
int dir;
|
||||
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);
|
||||
|
||||
nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
|
||||
if (nearest) {
|
||||
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;
|
||||
}
|
||||
|
||||
nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
|
||||
if (nearest) {
|
||||
barrier_clamp_to_barrier(nearest, dir, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cs->ConstrainCursorHarder) {
|
||||
screen->ConstrainCursorHarder = cs->ConstrainCursorHarder;
|
||||
screen->ConstrainCursorHarder(dev, screen, mode, x, y);
|
||||
screen->ConstrainCursorHarder = CursorConstrainCursorHarder;
|
||||
}
|
||||
}
|
||||
|
||||
static struct PointerBarrierClient *
|
||||
CreatePointerBarrierClient(ScreenPtr screen, ClientPtr client,
|
||||
xXFixesCreatePointerBarrierReq *stuff)
|
||||
{
|
||||
CursorScreenPtr cs = GetCursorScreen(screen);
|
||||
struct PointerBarrierClient *ret = malloc(sizeof(*ret));
|
||||
|
||||
if (ret) {
|
||||
ret->screen = screen;
|
||||
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);
|
||||
list_add(&ret->entry, &cs->barriers);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ProcXFixesCreatePointerBarrier (ClientPtr client)
|
||||
{
|
||||
int err;
|
||||
WindowPtr pWin;
|
||||
struct PointerBarrierClient *barrier;
|
||||
struct PointerBarrier b;
|
||||
REQUEST (xXFixesCreatePointerBarrierReq);
|
||||
|
||||
REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
|
||||
LEGAL_NEW_RESOURCE(stuff->barrier, client);
|
||||
|
||||
err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
|
||||
if (err != Success) {
|
||||
client->errorValue = stuff->window;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This sure does need fixing. */
|
||||
if (stuff->num_devices)
|
||||
return BadImplementation;
|
||||
|
||||
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 (!(barrier = CreatePointerBarrierClient(pWin->drawable.pScreen,
|
||||
client, stuff)))
|
||||
return BadAlloc;
|
||||
|
||||
if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
|
||||
return BadAlloc;
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
int
|
||||
SProcXFixesCreatePointerBarrier (ClientPtr client)
|
||||
{
|
||||
int n;
|
||||
REQUEST(xXFixesCreatePointerBarrierReq);
|
||||
|
||||
swaps(&stuff->length, n);
|
||||
REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
|
||||
swapl(&stuff->barrier, n);
|
||||
swapl(&stuff->window, n);
|
||||
swaps(&stuff->x1, n);
|
||||
swaps(&stuff->y1, n);
|
||||
swaps(&stuff->x2, n);
|
||||
swaps(&stuff->y2, n);
|
||||
swapl(&stuff->directions, n);
|
||||
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 */
|
||||
list_for_each_entry(b, &cs->barriers, entry) {
|
||||
if (b == barrier) {
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
SProcXFixesDestroyPointerBarrier (ClientPtr client)
|
||||
{
|
||||
int n;
|
||||
REQUEST(xXFixesDestroyPointerBarrierReq);
|
||||
|
||||
swaps(&stuff->length, n);
|
||||
REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
|
||||
swapl(&stuff->barrier, n);
|
||||
return ProcXFixesVector[stuff->xfixesReqType](client);
|
||||
}
|
||||
|
||||
Bool
|
||||
XFixesCursorInit (void)
|
||||
{
|
||||
|
@ -1048,8 +1440,10 @@ XFixesCursorInit (void)
|
|||
cs = (CursorScreenPtr) calloc(1, sizeof (CursorScreenRec));
|
||||
if (!cs)
|
||||
return FALSE;
|
||||
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);
|
||||
}
|
||||
|
@ -1059,7 +1453,10 @@ XFixesCursorInit (void)
|
|||
"XFixesCursorHideCount");
|
||||
CursorWindowType = CreateNewResourceType(CursorFreeWindow,
|
||||
"XFixesCursorWindow");
|
||||
PointerBarrierType = CreateNewResourceType(CursorFreeBarrier,
|
||||
"XFixesPointerBarrier");
|
||||
|
||||
return CursorClientType && CursorHideCountType && CursorWindowType;
|
||||
return CursorClientType && CursorHideCountType && CursorWindowType &&
|
||||
PointerBarrierType;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2010 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"),
|
||||
|
@ -47,10 +48,6 @@
|
|||
|
||||
#include "xfixesint.h"
|
||||
#include "protocol-versions.h"
|
||||
/*
|
||||
* Must use these instead of the constants from xfixeswire.h. They advertise
|
||||
* what we implement, not what the protocol headers define.
|
||||
*/
|
||||
|
||||
static unsigned char XFixesReqCode;
|
||||
int XFixesEventBase;
|
||||
|
@ -97,11 +94,12 @@ ProcXFixesQueryVersion(ClientPtr client)
|
|||
|
||||
/* Major version controls available requests */
|
||||
static const int version_requests[] = {
|
||||
X_XFixesQueryVersion, /* before client sends QueryVersion */
|
||||
X_XFixesGetCursorImage, /* Version 1 */
|
||||
X_XFixesChangeCursorByName, /* Version 2 */
|
||||
X_XFixesExpandRegion, /* Version 3 */
|
||||
X_XFixesShowCursor, /* Version 4 */
|
||||
X_XFixesQueryVersion, /* before client sends QueryVersion */
|
||||
X_XFixesGetCursorImage, /* Version 1 */
|
||||
X_XFixesChangeCursorByName, /* Version 2 */
|
||||
X_XFixesExpandRegion, /* Version 3 */
|
||||
X_XFixesShowCursor, /* Version 4 */
|
||||
X_XFixesDestroyPointerBarrier, /* Version 5 */
|
||||
};
|
||||
|
||||
#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
|
||||
|
@ -142,6 +140,9 @@ int (*ProcXFixesVector[XFixesNumberRequests])(ClientPtr) = {
|
|||
/*************** Version 4 ****************/
|
||||
ProcXFixesHideCursor,
|
||||
ProcXFixesShowCursor,
|
||||
/*************** Version 5 ****************/
|
||||
ProcXFixesCreatePointerBarrier,
|
||||
ProcXFixesDestroyPointerBarrier,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -205,6 +206,9 @@ static int (*SProcXFixesVector[XFixesNumberRequests])(ClientPtr) = {
|
|||
/*************** Version 4 ****************/
|
||||
SProcXFixesHideCursor,
|
||||
SProcXFixesShowCursor,
|
||||
/*************** Version 5 ****************/
|
||||
SProcXFixesCreatePointerBarrier,
|
||||
SProcXFixesDestroyPointerBarrier,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -260,6 +264,8 @@ XFixesExtensionInit(void)
|
|||
EventSwapVector[XFixesEventBase + XFixesCursorNotify] =
|
||||
(EventSwapPtr) SXFixesCursorNotifyEvent;
|
||||
SetResourceTypeErrorValue(RegionResType, XFixesErrorBase + BadRegion);
|
||||
SetResourceTypeErrorValue(PointerBarrierType,
|
||||
XFixesErrorBase + BadBarrier);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#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) \
|
||||
|
@ -51,5 +52,21 @@ 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);
|
||||
|
||||
|
||||
|
||||
#endif /* _XFIXES_H_ */
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2010 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"),
|
||||
|
@ -278,6 +279,21 @@ ProcXFixesShowCursor (ClientPtr client);
|
|||
int
|
||||
SProcXFixesShowCursor (ClientPtr client);
|
||||
|
||||
/* Version 5 */
|
||||
|
||||
int
|
||||
ProcXFixesCreatePointerBarrier (ClientPtr client);
|
||||
|
||||
int
|
||||
SProcXFixesCreatePointerBarrier (ClientPtr client);
|
||||
|
||||
int
|
||||
ProcXFixesDestroyPointerBarrier (ClientPtr client);
|
||||
|
||||
int
|
||||
SProcXFixesDestroyPointerBarrier (ClientPtr client);
|
||||
|
||||
/* Xinerama */
|
||||
extern int (*PanoramiXSaveXFixesVector[XFixesNumberRequests])(ClientPtr);
|
||||
void PanoramiXFixesInit (void);
|
||||
void PanoramiXFixesReset (void);
|
||||
|
|
Loading…
Reference in New Issue
Block a user