ChangeLog | 94 ++++++++++ configure.ac | 14 - debian/changelog | 7 debian/control | 4 debian/serverminver | 2 debian/watch | 1 dix/main.c | 2 include/privates.h | 2 include/protocol-versions.h | 2 m4/xorg-tls.m4 | 6 test/Makefile.am | 3 test/fixes.c | 327 ++++++++++++++++++++++++++++++++++++ xfixes/cursor.c | 399 +++++++++++++++++++++++++++++++++++++++++++- xfixes/xfixes.c | 24 +- xfixes/xfixes.h | 17 + xfixes/xfixesint.h | 16 + 16 files changed, 886 insertions(+), 34 deletions(-)
New commits: commit c437bd08fbe6d5c93f8d98c1f139d7ad8e34b413 Author: Cyril Brulebois <[email protected]> Date: Fri Jun 3 01:25:38 2011 +0200 Bump xutils-dev again for even newer macros. diff --git a/debian/control b/debian/control index cc0d83e..3ed0e07 100644 --- a/debian/control +++ b/debian/control @@ -17,7 +17,7 @@ Build-Depends: flex, automake, libtool, - xutils-dev (>= 1:7.6+3), + xutils-dev (>= 1:7.6+4), xfonts-utils (>= 1:7.5+1), x11proto-bigreqs-dev (>= 1:1.1.0), x11proto-composite-dev (>= 1:0.4), commit edeb8b9598c072d82d7d32eca67809b8dec103b9 Author: Cyril Brulebois <[email protected]> Date: Fri Jun 3 01:25:34 2011 +0200 Bump x11proto-fixes-dev build-dep for pointer barriers support. diff --git a/debian/changelog b/debian/changelog index 63cbca9..bec6c1b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ xorg-server (2:1.10.99.901-1) UNRELEASED; urgency=low * Bump pixman build-dep/dep to 0.21.8. * Bump xutils-dev build-dep for new macros. * Drop libglib2.0-dev build-dep, no longer needed for unit tests. + * Bump x11proto-fixes-dev build-dep for pointer barriers support. -- Cyril Brulebois <[email protected]> Tue, 31 May 2011 13:52:04 +0200 diff --git a/debian/control b/debian/control index 678362f..cc0d83e 100644 --- a/debian/control +++ b/debian/control @@ -23,7 +23,7 @@ Build-Depends: x11proto-composite-dev (>= 1:0.4), x11proto-core-dev (>= 7.0.17), x11proto-damage-dev (>= 1.1), - x11proto-fixes-dev (>= 1:4.1), + x11proto-fixes-dev (>= 1:5.0), x11proto-kb-dev (>= 1.0.3), x11proto-xinerama-dev, x11proto-randr-dev (>= 1.2.99.3), commit c6d66c12cf11ccd736aa05f1dbf963084e95bc00 Author: Cyril Brulebois <[email protected]> Date: Fri Jun 3 01:25:28 2011 +0200 Update serverminver accordingly. diff --git a/debian/serverminver b/debian/serverminver index 01f0694..5580dc9 100644 --- a/debian/serverminver +++ b/debian/serverminver @@ -1,3 +1,3 @@ -2:1.10.99.1 +2:1.10.99.901 ABI_VIDEODRV_VERSION:11.0 ABI_XINPUT_VERSION:13.0 commit bea957121f69b452f73a4a2873d25f344bda4d21 Author: Cyril Brulebois <[email protected]> Date: Fri Jun 3 01:11:50 2011 +0200 Bump changelogs. diff --git a/ChangeLog b/ChangeLog index 3a4c7bc..b7df3cb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,81 @@ +commit db228d3d07a6d831f53e4c05c878327ad4d045eb +Author: Keith Packard <[email protected]> +Date: Wed Jun 1 11:20:10 2011 -0700 + + Version bumped to 1.10.99.901 (1.11 RC1) + + Signed-off-by: Keith Packard <[email protected]> + +commit 0643c056512d10be8db223d18d6563292d57e916 +Merge: a2e6cfc d45f5b2 +Author: Keith Packard <[email protected]> +Date: Tue May 31 23:45:07 2011 -0700 + + Merge remote-tracking branch 'ajax/xserver-next' + +commit a2e6cfc18aec1c0027b51572b03ec9f2ab074b56 +Merge: bc04065 8d84fd2 +Author: Keith Packard <[email protected]> +Date: Tue May 31 23:42:52 2011 -0700 + + Merge remote-tracking branch 'sandmann/for-keithp' + +commit d45f5b2493bc0a2882bf972849b5c9c50cd533ca +Author: Adam Jackson <[email protected]> +Date: Wed May 25 05:54:35 2011 -0400 + + 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 <[email protected]> + Tested-by: Peter Hutterer <[email protected]> + Signed-off-by: Adam Jackson <[email protected]> + Signed-off-by: Peter Hutterer <[email protected]> + +commit bc04065b5ce277f3ac3491ff221a60ef3c7605cf +Author: Alan Coopersmith <[email protected]> +Date: Fri May 20 19:24:34 2011 -0700 + + "privates.h", line 198: warning: void function cannot return value + + Providing an argument to return in a function with void return type + is not allowed by the C standard, and makes the Sun compilers unhappy. + (They actually flag it as an error, unless using a new enough version + to be able to downgrade it to a warning with "-features=extensions".) + + Signed-off-by: Alan Coopersmith <[email protected]> + Reviewed-by: Jeremy Huddleston <[email protected]> + Reviewed-by: Daniel Stone <[email protected]> + Reviewed-by: Cyril Brulebois <[email protected]> + +commit eadf5021794782fde861d471ed408675f4926b89 +Author: Alan Coopersmith <[email protected]> +Date: Mon May 2 19:48:42 2011 -0700 + + Use XORG_STRICT_OPTION from util-macros 1.14 to set -Werror flags + + Signed-off-by: Alan Coopersmith <[email protected]> + Reviewed-by: Jeremy Huddleston <[email protected]> + +commit 9275b1fb6f82a6971c4177ddd3d5a859a8f24119 +Author: Alan Coopersmith <[email protected]> +Date: Mon May 2 19:47:44 2011 -0700 + + Use XORG_COMPILER_BRAND from util-macros 1.14 to check for SUNCC + + Signed-off-by: Alan Coopersmith <[email protected]> + Reviewed-by: Peter Hutterer <[email protected]> + Reviewed-by: Jeremy Huddleston <[email protected]> + commit 4621bb270a36d35d4ab67f1d7fb47674683dfc5b Author: Peter Hutterer <[email protected]> Date: Wed May 18 15:00:54 2011 +1000 @@ -26,6 +104,22 @@ Date: Mon Jan 31 14:43:01 2011 +1000 Signed-off-by: Peter Hutterer <[email protected]> Acked-by: Dan Nicholson <[email protected]> +commit 8d84fd2566f8466b6152724df7eefc73780df093 +Author: Søren Sandmann Pedersen <[email protected]> +Date: Wed May 25 12:14:05 2011 -0400 + + Don't call pixman_disable_out_of_bounds_workaround() anymore + + Pixman used to have a workaround for a bug in old X servers, and this + function was used to disable that workaround in servers known to be + fixed. + + Since 0.22, which the X server depends on, the workaround doesn't + exist anymore, so there is no point disabling it. + + Reviewed-by: Cyril Brulebois <kibi at debian.org> + Signed-off-by: Soren Sandmann <[email protected]> + commit b6c7b9b2f39e970cedb6bc1e073f901e28cb0fa3 Author: Aaron Plattner <[email protected]> Date: Tue May 24 16:02:42 2011 -0700 diff --git a/debian/changelog b/debian/changelog index 5ab7974..63cbca9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,6 @@ -xorg-server (2:1.10.99.1-1) UNRELEASED; urgency=low +xorg-server (2:1.10.99.901-1) UNRELEASED; urgency=low - * New upstream snapshot. The version string is Debian-specific, and - should sort nicely before 1.10.99.901, which should be the first - release candidate for 1.11. + * New upstream release candidate. * Bump serverminver, as well as input and video ABI. * Adapt 15-nouveau.diff to cope with the glxdricommon-ification of GLX probing. Nouveau users might still see an error (EE) mentioning commit 9226b6058c5501c43ad711ce7131e17af306d5f3 Author: Cyril Brulebois <[email protected]> Date: Fri Jun 3 01:07:25 2011 +0200 Mention git URL in a comment. diff --git a/debian/watch b/debian/watch index 249555d..60a37d4 100644 --- a/debian/watch +++ b/debian/watch @@ -1,2 +1,3 @@ +#git=git://anongit.freedesktop.org/xorg/xserver version=3 http://xorg.freedesktop.org/releases/individual/xserver/ xorg-server-(.*)\.tar\.gz commit db228d3d07a6d831f53e4c05c878327ad4d045eb Author: Keith Packard <[email protected]> Date: Wed Jun 1 11:20:10 2011 -0700 Version bumped to 1.10.99.901 (1.11 RC1) Signed-off-by: Keith Packard <[email protected]> diff --git a/configure.ac b/configure.ac index fcb8ea9..22566c9 100644 --- a/configure.ac +++ b/configure.ac @@ -26,8 +26,8 @@ dnl dnl Process this file with autoconf to create configure. AC_PREREQ(2.57) -AC_INIT([xorg-server], 1.10.99.1, [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], xorg-server) -RELEASE_DATE="unreleased" +AC_INIT([xorg-server], 1.10.99.901, [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], xorg-server) +RELEASE_DATE="2011-06-01" AC_CONFIG_SRCDIR([Makefile.am]) AM_INIT_AUTOMAKE([foreign dist-bzip2]) AM_MAINTAINER_MODE commit d45f5b2493bc0a2882bf972849b5c9c50cd533ca Author: Adam Jackson <[email protected]> Date: Wed May 25 05:54:35 2011 -0400 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 <[email protected]> Tested-by: Peter Hutterer <[email protected]> Signed-off-by: Adam Jackson <[email protected]> Signed-off-by: Peter Hutterer <[email protected]> diff --git a/configure.ac b/configure.ac index 655c0e4..ba1d176 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/include/protocol-versions.h b/include/protocol-versions.h index 8692ded..7b7a9f5 100644 --- a/include/protocol-versions.h +++ b/include/protocol-versions.h @@ -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 */ diff --git a/test/Makefile.am b/test/Makefile.am index b7ee070..5574e7d 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -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) \ diff --git a/test/fixes.c b/test/fixes.c new file mode 100644 index 0000000..8c804ba --- /dev/null +++ b/test/fixes.c @@ -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; +} diff --git a/xfixes/cursor.c b/xfixes/cursor.c index fb608f6..01eb70d 100644 --- a/xfixes/cursor.c +++ b/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; -- To UNSUBSCRIBE, email to [email protected] with a subject of "unsubscribe". Trouble? Contact [email protected] Archive: http://lists.debian.org/[email protected]

