summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2011-05-25 05:54:35 -0400
committerAdam Jackson <ajax@redhat.com>2011-05-31 15:10:51 -0400
commitd45f5b2493bc0a2882bf972849b5c9c50cd533ca (patch)
tree08ee6bc366efad2b49299a6f6b350042c8d5af0b
parent4621bb270a36d35d4ab67f1d7fb47674683dfc5b (diff)
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>
-rw-r--r--configure.ac2
-rw-r--r--include/protocol-versions.h2
-rw-r--r--test/Makefile.am3
-rw-r--r--test/fixes.c327
-rw-r--r--xfixes/cursor.c399
-rw-r--r--xfixes/xfixes.c24
-rw-r--r--xfixes/xfixes.h17
-rw-r--r--xfixes/xfixesint.h16
8 files changed, 777 insertions, 13 deletions
diff --git a/configure.ac b/configure.ac
index 655c0e4ba..ba1d1768f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -810,7 +810,7 @@ dnl specific modules against it
810PKG_CHECK_MODULES(PIXMAN, $LIBPIXMAN) 810PKG_CHECK_MODULES(PIXMAN, $LIBPIXMAN)
811REQUIRED_LIBS="$REQUIRED_LIBS $LIBPIXMAN $LIBXFONT xau" 811REQUIRED_LIBS="$REQUIRED_LIBS $LIBPIXMAN $LIBXFONT xau"
812 812
813REQUIRED_MODULES="[fixesproto >= 4.1] [damageproto >= 1.1] [xcmiscproto >= 1.2.0] [xtrans >= 1.2.2] [bigreqsproto >= 1.1.0] $SDK_REQUIRED_MODULES" 813REQUIRED_MODULES="[fixesproto >= 5.0] [damageproto >= 1.1] [xcmiscproto >= 1.2.0] [xtrans >= 1.2.2] [bigreqsproto >= 1.1.0] $SDK_REQUIRED_MODULES"
814 814
815if test "x$CONFIG_UDEV" = xyes && 815if test "x$CONFIG_UDEV" = xyes &&
816 { test "x$CONFIG_DBUS_API" = xyes || test "x$CONFIG_HAL" = xyes; }; then 816 { 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 8692ded8a..7b7a9f53c 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -122,7 +122,7 @@
122#define SERVER_XF86VIDMODE_MINOR_VERSION 2 122#define SERVER_XF86VIDMODE_MINOR_VERSION 2
123 123
124/* Fixes */ 124/* Fixes */
125#define SERVER_XFIXES_MAJOR_VERSION 4 125#define SERVER_XFIXES_MAJOR_VERSION 5
126#define SERVER_XFIXES_MINOR_VERSION 0 126#define SERVER_XFIXES_MINOR_VERSION 0
127 127
128/* X Input */ 128/* X Input */
diff --git a/test/Makefile.am b/test/Makefile.am
index b7ee070a1..5574e7d1e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,7 +1,7 @@
1if ENABLE_UNIT_TESTS 1if ENABLE_UNIT_TESTS
2if HAVE_LD_WRAP 2if HAVE_LD_WRAP
3SUBDIRS= . xi2 3SUBDIRS= . xi2
4noinst_PROGRAMS = xkb input xtest list misc 4noinst_PROGRAMS = xkb input xtest list misc fixes
5check_LTLIBRARIES = libxservertest.la 5check_LTLIBRARIES = libxservertest.la
6 6
7TESTS=$(noinst_PROGRAMS) 7TESTS=$(noinst_PROGRAMS)
@@ -19,6 +19,7 @@ input_LDADD=$(TEST_LDADD)
19xtest_LDADD=$(TEST_LDADD) 19xtest_LDADD=$(TEST_LDADD)
20list_LDADD=$(TEST_LDADD) 20list_LDADD=$(TEST_LDADD)
21misc_LDADD=$(TEST_LDADD) 21misc_LDADD=$(TEST_LDADD)
22fixes_LDADD=$(TEST_LDADD)
22 23
23libxservertest_la_LIBADD = \ 24libxservertest_la_LIBADD = \
24 $(XSERVER_LIBS) \ 25 $(XSERVER_LIBS) \
diff --git a/test/fixes.c b/test/fixes.c
new file mode 100644
index 000000000..8c804ba26
--- /dev/null
+++ b/test/fixes.c
@@ -0,0 +1,327 @@
1/**
2 * Copyright © 2011 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_DIX_CONFIG_H
25#include <dix-config.h>
26#endif
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <X11/X.h>
31#include <xfixesint.h>
32#include <X11/extensions/xfixeswire.h>
33
34static void
35_fixes_test_direction(struct PointerBarrier *barrier, int d[4], int permitted)
36{
37 BOOL blocking;
38 int i, j;
39 int dir = barrier_get_direction(d[0], d[1], d[2], d[3]);
40
41 barrier->directions = 0;
42 blocking = barrier_is_blocking_direction(barrier, dir);
43 assert(blocking);
44
45 for (j = 0; j <= BarrierNegativeY; j++)
46 {
47 for (i = 0; i <= BarrierNegativeY; i++)
48 {
49 barrier->directions |= 1 << i;
50 blocking = barrier_is_blocking_direction(barrier, dir);
51 assert((barrier->directions & permitted) == permitted ? !blocking : blocking);
52 }
53 }
54
55}
56
57static void
58fixes_pointer_barrier_direction_test(void)
59{
60 struct PointerBarrier barrier;
61
62 int x = 100;
63 int y = 100;
64
65 int directions[8][4] = {
66 { x, y, x, y + 100}, /* S */
67 { x + 50, y, x - 50, y + 100}, /* SW */
68 { x + 100, y, x, y}, /* W */
69 { x + 100, y + 50, x, y - 50}, /* NW */
70 { x, y + 100, x, y}, /* N */
71 { x - 50, y + 100, x + 50, y}, /* NE */
72 { x, y, x + 100, y}, /* E */
73 { x, y - 50, x + 100, y + 50}, /* SE */
74 };
75
76 barrier.x1 = x;
77 barrier.x2 = x;
78 barrier.y1 = y - 50;
79 barrier.y2 = y + 49;
80
81
82 _fixes_test_direction(&barrier, directions[0], BarrierPositiveY);
83 _fixes_test_direction(&barrier, directions[1], BarrierPositiveY | BarrierNegativeX);
84 _fixes_test_direction(&barrier, directions[2], BarrierNegativeX);
85 _fixes_test_direction(&barrier, directions[3], BarrierNegativeY | BarrierNegativeX);
86 _fixes_test_direction(&barrier, directions[4], BarrierNegativeY);
87 _fixes_test_direction(&barrier, directions[5], BarrierPositiveX | BarrierNegativeY);
88 _fixes_test_direction(&barrier, directions[6], BarrierPositiveX);
89 _fixes_test_direction(&barrier, directions[7], BarrierPositiveY | BarrierPositiveX);
90
91
92}
93
94
95static void
96fixes_pointer_barriers_test(void)
97{
98 struct PointerBarrier barrier;
99 int x1, y1, x2, y2;
100 double distance;
101
102 int x = 100;
103 int y = 100;
104
105 /* vert barrier */
106 barrier.x1 = x;
107 barrier.x2 = x;
108 barrier.y1 = y - 50;
109 barrier.y2 = y + 50;
110
111 /* across at half-way */
112 x1 = x + 1;
113 x2 = x - 1;
114 y1 = y;
115 y2 = y;
116 assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
117 assert(distance == 1);
118
119 /* definitely not across */
120 x1 = x + 10;
121 x2 = x + 5;
122 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
123
124 /* across, but outside of y range */
125 x1 = x + 1;
126 x2 = x -1;
127 y1 = y + 100;
128 y2 = y + 100;
129 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
130
131 /* across, diagonally */
132 x1 = x + 5;
133 x2 = x - 5;
134 y1 = y + 5;
135 y2 = y - 5;
136 assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
137
138 /* across but outside boundary, diagonally */
139 x1 = x + 5;
140 x2 = x - 5;
141 y1 = y + 100;
142 y2 = y + 50;
143 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
144
145 /* edge case: startpoint of movement on barrier → blocking */
146 x1 = x;
147 x2 = x - 1;
148 y1 = y;
149 y2 = y;
150 assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
151
152 /* edge case: startpoint of movement on barrier → not blocking, positive */
153 x1 = x;
154 x2 = x + 1;
155 y1 = y;
156 y2 = y;
157 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
158
159 /* edge case: startpoint of movement on barrier → not blocking, negative */
160 x1 = x - 1;
161 x2 = x - 2;
162 y1 = y;
163 y2 = y;
164 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
165
166 /* edge case: endpoint of movement on barrier → blocking */
167 x1 = x + 1;
168 x2 = x;
169 y1 = y;
170 y2 = y;
171 assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
172
173 /* startpoint on barrier but outside y range */
174 x1 = x;
175 x2 = x - 1;
176 y1 = y + 100;
177 y2 = y + 100;
178 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
179
180 /* endpoint on barrier but outside y range */
181 x1 = x + 1;
182 x2 = x;
183 y1 = y + 100;
184 y2 = y + 100;
185 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
186
187
188 /* horizontal barrier */
189 barrier.x1 = x - 50;
190 barrier.x2 = x + 50;
191 barrier.y1 = y;
192 barrier.y2 = y;
193
194 /* across at half-way */
195 x1 = x;
196 x2 = x;
197 y1 = y - 1;
198 y2 = y + 1;
199 assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
200
201 /* definitely not across */
202 y1 = y + 10;
203 y2 = y + 5;
204 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
205
206 /* across, but outside of y range */
207 x1 = x + 100;
208 x2 = x + 100;
209 y1 = y + 1;
210 y2 = y -1;
211 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
212
213 /* across, diagonally */
214 y1 = y + 5;
215 y2 = y - 5;
216 x1 = x + 5;
217 x2 = x - 5;
218 assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
219
220 /* across but outside boundary, diagonally */
221 y1 = y + 5;
222 y2 = y - 5;
223 x1 = x + 100;
224 x2 = x + 50;
225 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
226
227 /* edge case: startpoint of movement on barrier → blocking */
228 y1 = y;
229 y2 = y - 1;
230 x1 = x;
231 x2 = x;
232 assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
233
234 /* edge case: startpoint of movement on barrier → not blocking, positive */
235 y1 = y;
236 y2 = y + 1;
237 x1 = x;
238 x2 = x;
239 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
240
241 /* edge case: startpoint of movement on barrier → not blocking, negative */
242 y1 = y - 1;
243 y2 = y - 2;
244 x1 = x;
245 x2 = x;
246 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
247
248 /* edge case: endpoint of movement on barrier → blocking */
249 y1 = y + 1;
250 y2 = y;
251 x1 = x;
252 x2 = x;
253 assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
254
255 /* startpoint on barrier but outside y range */
256 y1 = y;
257 y2 = y - 1;
258 x1 = x + 100;
259 x2 = x + 100;
260 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
261
262 /* endpoint on barrier but outside y range */
263 y1 = y + 1;
264 y2 = y;
265 x1 = x + 100;
266 x2 = x + 100;
267 assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance));
268
269}
270
271static void fixes_pointer_barrier_clamp_test(void)
272{
273 struct PointerBarrier barrier;
274
275 int x = 100;
276 int y = 100;
277
278 int cx, cy; /* clamped */
279
280 /* vert barrier */
281 barrier.x1 = x;
282 barrier.x2 = x;
283 barrier.y1 = y - 50;
284 barrier.y2 = y + 49;
285 barrier.directions = 0;
286
287 cx = INT_MAX;
288 cy = INT_MAX;
289 barrier_clamp_to_barrier(&barrier, BarrierPositiveX, &cx, &cy);
290 assert(cx == barrier.x1 - 1);
291 assert(cy == INT_MAX);
292
293 cx = 0;
294 cy = INT_MAX;
295 barrier_clamp_to_barrier(&barrier, BarrierNegativeX, &cx, &cy);
296 assert(cx == barrier.x1);
297 assert(cy == INT_MAX);
298
299 /* horiz barrier */
300 barrier.x1 = x - 50;
301 barrier.x2 = x + 49;
302 barrier.y1 = y;
303 barrier.y2 = y;
304 barrier.directions = 0;
305
306 cx = INT_MAX;
307 cy = INT_MAX;
308 barrier_clamp_to_barrier(&barrier, BarrierPositiveY, &cx, &cy);
309 assert(cx == INT_MAX);
310 assert(cy == barrier.y1 - 1);
311
312 cx = INT_MAX;
313 cy = 0;
314 barrier_clamp_to_barrier(&barrier, BarrierNegativeY, &cx, &cy);
315 assert(cx == INT_MAX);
316 assert(cy == barrier.y1);
317}
318
319int main(int argc, char** argv)
320{
321
322 fixes_pointer_barriers_test();
323 fixes_pointer_barrier_direction_test();
324 fixes_pointer_barrier_clamp_test();
325
326 return 0;
327}
diff --git a/xfixes/cursor.c b/xfixes/cursor.c
index fb608f694..01eb70d92 100644
--- a/xfixes/cursor.c
+++ b/xfixes/cursor.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2010 Red Hat, Inc.
3 * 4 *
4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"), 6 * copy of this software and associated documentation files (the "Software"),
@@ -50,13 +51,16 @@
50#include "cursorstr.h" 51#include "cursorstr.h"
51#include "dixevents.h" 52#include "dixevents.h"
52#include "servermd.h" 53#include "servermd.h"
54#include "mipointer.h"
53#include "inputstr.h" 55#include "inputstr.h"
54#include "windowstr.h" 56#include "windowstr.h"
55#include "xace.h" 57#include "xace.h"
58#include "list.h"
56 59
57static RESTYPE CursorClientType; 60static RESTYPE CursorClientType;
58static RESTYPE CursorHideCountType; 61static RESTYPE CursorHideCountType;
59static RESTYPE CursorWindowType; 62static RESTYPE CursorWindowType;
63RESTYPE PointerBarrierType;
60static CursorPtr CursorCurrent[MAXDEVICES]; 64static CursorPtr CursorCurrent[MAXDEVICES];
61 65
62static DevPrivateKeyRec CursorScreenPrivateKeyRec; 66static DevPrivateKeyRec CursorScreenPrivateKeyRec;
@@ -107,6 +111,14 @@ typedef struct _CursorHideCountRec {
107 XID resource; 111 XID resource;
108} CursorHideCountRec; 112} CursorHideCountRec;
109 113
114typedef struct PointerBarrierClient *PointerBarrierClientPtr;
115
116struct PointerBarrierClient {
117 ScreenPtr screen;
118 struct PointerBarrier barrier;
119 struct list entry;
120};
121
110/* 122/*
111 * Wrap DisplayCursor to catch cursor change events 123 * Wrap DisplayCursor to catch cursor change events
112 */ 124 */
@@ -114,7 +126,9 @@ typedef struct _CursorHideCountRec {
114typedef struct _CursorScreen { 126typedef struct _CursorScreen {
115 DisplayCursorProcPtr DisplayCursor; 127 DisplayCursorProcPtr DisplayCursor;
116 CloseScreenProcPtr CloseScreen; 128 CloseScreenProcPtr CloseScreen;
129 ConstrainCursorHarderProcPtr ConstrainCursorHarder;
117 CursorHideCountPtr pCursorHideCounts; 130 CursorHideCountPtr pCursorHideCounts;
131 struct list barriers;
118} CursorScreenRec, *CursorScreenPtr; 132} CursorScreenRec, *CursorScreenPtr;
119 133
120#define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey)) 134#define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey))
@@ -184,9 +198,11 @@ CursorCloseScreen (int index, ScreenPtr pScreen)
184 Bool ret; 198 Bool ret;
185 CloseScreenProcPtr close_proc; 199 CloseScreenProcPtr close_proc;
186 DisplayCursorProcPtr display_proc; 200 DisplayCursorProcPtr display_proc;
201 ConstrainCursorHarderProcPtr constrain_proc;
187 202
188 Unwrap (cs, pScreen, CloseScreen, close_proc); 203 Unwrap (cs, pScreen, CloseScreen, close_proc);
189 Unwrap (cs, pScreen, DisplayCursor, display_proc); 204 Unwrap (cs, pScreen, DisplayCursor, display_proc);
205 Unwrap (cs, pScreen, ConstrainCursorHarder, constrain_proc);
190 deleteCursorHideCountsForScreen(pScreen); 206 deleteCursorHideCountsForScreen(pScreen);
191 ret = (*pScreen->CloseScreen) (index, pScreen); 207 ret = (*pScreen->CloseScreen) (index, pScreen);
192 free(cs); 208 free(cs);
@@ -1029,6 +1045,382 @@ CursorFreeWindow (pointer data, XID id)
1029 return 1; 1045 return 1;
1030} 1046}
1031 1047
1048static BOOL
1049barrier_is_horizontal(const struct PointerBarrier *barrier)
1050{
1051 return barrier->y1 == barrier->y2;
1052}
1053
1054static BOOL
1055barrier_is_vertical(const struct PointerBarrier *barrier)
1056{
1057 return barrier->x1 == barrier->x2;
1058}
1059
1060/**
1061 * @return The set of barrier movement directions the movement vector
1062 * x1/y1 → x2/y2 represents.
1063 */
1064int
1065barrier_get_direction(int x1, int y1, int x2, int y2)
1066{
1067 int direction = 0;
1068
1069 /* which way are we trying to go */
1070 if (x2 > x1)
1071 direction |= BarrierPositiveX;
1072 if (x2 < x1)
1073 direction |= BarrierNegativeX;
1074 if (y2 > y1)
1075 direction |= BarrierPositiveY;
1076 if (y2 < y1)
1077 direction |= BarrierNegativeY;
1078
1079 return direction;
1080}
1081
1082/**
1083 * Test if the barrier may block movement in the direction defined by
1084 * x1/y1 → x2/y2. This function only tests whether the directions could be
1085 * blocked, it does not test if the barrier actually blocks the movement.
1086 *
1087 * @return TRUE if the barrier blocks the direction of movement or FALSE
1088 * otherwise.
1089 */
1090BOOL
1091barrier_is_blocking_direction(const struct PointerBarrier *barrier, int direction)
1092{
1093 /* Barriers define which way is ok, not which way is blocking */
1094 return (barrier->directions & direction) != direction;
1095}
1096
1097/**
1098 * Test if the movement vector x1/y1 → x2/y2 is intersecting with the
1099 * barrier. A movement vector with the startpoint or endpoint adjacent to
1100 * the barrier itself counts as intersecting.
1101 *
1102 * @param x1 X start coordinate of movement vector
1103 * @param y1 Y start coordinate of movement vector
1104 * @param x2 X end coordinate of movement vector
1105 * @param y2 Y end coordinate of movement vector
1106 * @param[out] distance The distance between the start point and the
1107 * intersection with the barrier (if applicable).
1108 * @return TRUE if the barrier intersects with the given vector
1109 */
1110BOOL
1111barrier_is_blocking(const struct PointerBarrier *barrier,
1112 int x1, int y1, int x2, int y2,
1113 double *distance)
1114{
1115 BOOL rc = FALSE;
1116 float ua, ub, ud;
1117 int dir = barrier_get_direction(x1, y1, x2, y2);
1118
1119 /* Algorithm below doesn't handle edge cases well, hence the extra
1120 * checks. */
1121 if (barrier_is_vertical(barrier)) {
1122 /* handle immediate barrier adjacency, moving away */
1123 if (dir & BarrierPositiveX && x1 == barrier->x1)
1124 return FALSE;
1125 if (dir & BarrierNegativeX && x1 == (barrier->x1 - 1))
1126 return FALSE;
1127 /* startpoint adjacent to barrier, moving towards -> block */
1128 if (x1 == barrier->x1 && y1 >= barrier->y1 && y1 <= barrier->y2) {
1129 *distance = 0;
1130 return TRUE;
1131 }
1132 } else {
1133 /* handle immediate barrier adjacency, moving away */
1134 if (dir & BarrierPositiveY && y1 == barrier->y1)
1135 return FALSE;
1136 if (dir & BarrierNegativeY && y1 == (barrier->y1 - 1))
1137 return FALSE;
1138 /* startpoint adjacent to barrier, moving towards -> block */
1139 if (y1 == barrier->y1 && x1 >= barrier->x1 && x1 <= barrier->x2) {
1140 *distance = 0;
1141 return TRUE;
1142 }
1143 }
1144
1145 /* not an edge case, compute distance */
1146 ua = 0;
1147 ud = (barrier->y2 - barrier->y1) * (x2 - x1) - (barrier->x2 - barrier->x1) * (y2 - y1);
1148 if (ud != 0) {
1149 ua = ((barrier->x2 - barrier->x1) * (y1 - barrier->y1) -
1150 (barrier->y2 - barrier->y1) * (x1 - barrier->x1)) / ud;
1151 ub = ((x2 - x1) * (y1 - barrier->y1) -
1152 (y2 - y1) * (x1 - barrier->x1)) / ud;
1153 if (ua < 0 || ua > 1 || ub < 0 || ub > 1)
1154 ua = 0;
1155 }
1156
1157 if (ua > 0 && ua <= 1)
1158 {
1159 double ix = barrier->x1 + ua * (barrier->x2 - barrier->x1);
1160 double iy = barrier->y1 + ua * (barrier->y2 - barrier->y1);
1161
1162 *distance = sqrt(pow(x1 - ix, 2) + pow(y1 - iy, 2));
1163 rc = TRUE;
1164 }
1165
1166 return rc;
1167}
1168
1169/**
1170 * Find the nearest barrier that is blocking movement from x1/y1 to x2/y2.
1171 *
1172 * @param dir Only barriers blocking movement in direction dir are checked
1173 * @param x1 X start coordinate of movement vector
1174 * @param y1 Y start coordinate of movement vector
1175 * @param x2 X end coordinate of movement vector
1176 * @param y2 Y end coordinate of movement vector
1177 * @return The barrier nearest to the movement origin that blocks this movement.
1178 */
1179static struct PointerBarrier*
1180barrier_find_nearest(CursorScreenPtr cs, int dir,
1181 int x1, int y1, int x2, int y2)
1182{
1183 struct PointerBarrierClient *c;
1184 struct PointerBarrier *nearest = NULL;
1185 double min_distance = INT_MAX; /* can't get higher than that in X anyway */
1186
1187 list_for_each_entry(c, &cs->barriers, entry) {
1188 struct PointerBarrier *b = &c->barrier;
1189 double distance;
1190
1191 if (!barrier_is_blocking_direction(b, dir))
1192 continue;
1193
1194 if (barrier_is_blocking(b, x1, y1, x2, y2, &distance))
1195 {
1196 if (min_distance > distance)
1197 {
1198 min_distance = distance;
1199 nearest = b;
1200 }
1201 }
1202 }
1203
1204 return nearest;
1205}
1206
1207/**
1208 * Clamp to the given barrier given the movement direction specified in dir.
1209 *
1210 * @param barrier The barrier to clamp to
1211 * @param dir The movement direction
1212 * @param[out] x The clamped x coordinate.
1213 * @param[out] y The clamped x coordinate.
1214 */
1215void
1216barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, int *y)
1217{
1218 if (barrier_is_vertical(barrier))
1219 {
1220 if ((dir & BarrierNegativeX) & ~barrier->directions)
1221 *x = barrier->x1;
1222 if ((dir & BarrierPositiveX) & ~barrier->directions)
1223 *x = barrier->x1 - 1;
1224 }
1225 if (barrier_is_horizontal(barrier))
1226 {
1227 if ((dir & BarrierNegativeY) & ~barrier->directions)
1228 *y = barrier->y1;
1229 if ((dir & BarrierPositiveY) & ~barrier->directions)
1230 *y = barrier->y1 - 1;
1231 }
1232}
1233
1234static void
1235CursorConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, int *x, int *y)
1236{
1237 CursorScreenPtr cs = GetCursorScreen(screen);
1238
1239 if (!list_is_empty(&cs->barriers) && !IsFloating(dev) && mode == Relative) {
1240 int ox, oy;
1241 int dir;
1242 struct PointerBarrier *nearest = NULL;
1243
1244 /* where are we coming from */
1245 miPointerGetPosition(dev, &ox, &oy);
1246
1247 /* How this works:
1248 * Given the origin and the movement vector, get the nearest barrier
1249 * to the origin that is blocking the movement.
1250 * Clamp to that barrier.
1251 * Then, check from the clamped intersection to the original
1252 * destination, again finding the nearest barrier and clamping.
1253 */
1254 dir = barrier_get_direction(ox, oy, *x, *y);
1255
1256 nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
1257 if (nearest) {
1258 barrier_clamp_to_barrier(nearest, dir, x, y);
1259
1260 if (barrier_is_vertical(nearest)) {
1261 dir &= ~(BarrierNegativeX | BarrierPositiveX);
1262 ox = *x;
1263 } else if (barrier_is_horizontal(nearest)) {
1264 dir &= ~(BarrierNegativeY | BarrierPositiveY);
1265 oy = *y;
1266 }
1267
1268 nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
1269 if (nearest) {
1270 barrier_clamp_to_barrier(nearest, dir, x, y);
1271 }
1272 }
1273 }
1274
1275 if (cs->ConstrainCursorHarder) {
1276 screen->ConstrainCursorHarder = cs->ConstrainCursorHarder;
1277 screen->ConstrainCursorHarder(dev, screen, mode, x, y);
1278 screen->ConstrainCursorHarder = CursorConstrainCursorHarder;
1279 }
1280}
1281
1282static struct PointerBarrierClient *
1283CreatePointerBarrierClient(ScreenPtr screen, ClientPtr client,
1284 xXFixesCreatePointerBarrierReq *stuff)
1285{
1286 CursorScreenPtr cs = GetCursorScreen(screen);
1287 struct PointerBarrierClient *ret = malloc(sizeof(*ret));
1288
1289 if (ret) {
1290 ret->screen = screen;
1291 ret->barrier.x1 = min(stuff->x1, stuff->x2);
1292 ret->barrier.x2 = max(stuff->x1, stuff->x2);
1293 ret->barrier.y1 = min(stuff->y1, stuff->y2);
1294 ret->barrier.y2 = max(stuff->y1, stuff->y2);
1295 ret->barrier.directions = stuff->directions & 0x0f;
1296 if (barrier_is_horizontal(&ret->barrier))
1297 ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
1298 if (barrier_is_vertical(&ret->barrier))
1299 ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY);
1300 list_add(&ret->entry, &cs->barriers);
1301 }
1302
1303 return ret;
1304}
1305
1306int
1307ProcXFixesCreatePointerBarrier (ClientPtr client)
1308{
1309 int err;
1310 WindowPtr pWin;
1311 struct PointerBarrierClient *barrier;
1312 struct PointerBarrier b;
1313 REQUEST (xXFixesCreatePointerBarrierReq);
1314
1315 REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
1316 LEGAL_NEW_RESOURCE(stuff->barrier, client);
1317
1318 err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
1319 if (err != Success) {
1320 client->errorValue = stuff->window;
1321 return err;
1322 }
1323
1324 /* This sure does need fixing. */
1325 if (stuff->num_devices)
1326 return BadImplementation;
1327
1328 b.x1 = stuff->x1;
1329 b.x2 = stuff->x2;
1330 b.y1 = stuff->y1;
1331 b.y2 = stuff->y2;
1332
1333 if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b))
1334 return BadValue;
1335
1336 /* no 0-sized barriers */
1337 if (barrier_is_horizontal(&b) && barrier_is_vertical(&b))
1338 return BadValue;
1339
1340 if (!(barrier = CreatePointerBarrierClient(pWin->drawable.pScreen,
1341 client, stuff)))
1342 return BadAlloc;
1343
1344 if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
1345 return BadAlloc;
1346
1347 return Success;
1348}
1349
1350int
1351SProcXFixesCreatePointerBarrier (ClientPtr client)
1352{
1353 int n;
1354 REQUEST(xXFixesCreatePointerBarrierReq);
1355
1356 swaps(&stuff->length, n);
1357 REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
1358 swapl(&stuff->barrier, n);
1359 swapl(&stuff->window, n);
1360 swaps(&stuff->x1, n);
1361 swaps(&stuff->y1, n);
1362 swaps(&stuff->x2, n);
1363 swaps(&stuff->y2, n);
1364 swapl(&stuff->directions, n);
1365 return ProcXFixesVector[stuff->xfixesReqType](client);
1366}
1367
1368static int
1369CursorFreeBarrier(void *data, XID id)
1370{
1371 struct PointerBarrierClient *b = NULL, *barrier;
1372 ScreenPtr screen;
1373 CursorScreenPtr cs;
1374
1375 barrier = container_of(data, struct PointerBarrierClient, barrier);
1376 screen = barrier->screen;
1377 cs = GetCursorScreen(screen);
1378
1379 /* find and unlink from the screen private */
1380 list_for_each_entry(b, &cs->barriers, entry) {
1381 if (b == barrier) {
1382 list_del(&b->entry);
1383 break;
1384 }
1385 }
1386
1387 free(barrier);
1388 return Success;
1389}
1390
1391int
1392ProcXFixesDestroyPointerBarrier (ClientPtr client)
1393{
1394 int err;
1395 void *barrier;
1396 REQUEST (xXFixesDestroyPointerBarrierReq);
1397
1398 REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
1399
1400 err = dixLookupResourceByType((void **)&barrier, stuff->barrier,
1401 PointerBarrierType, client,
1402 DixDestroyAccess);
1403 if (err != Success) {
1404 client->errorValue = stuff->barrier;
1405 return err;
1406 }
1407
1408 FreeResource(stuff->barrier, RT_NONE);
1409 return Success;
1410}
1411
1412int
1413SProcXFixesDestroyPointerBarrier (ClientPtr client)
1414{
1415 int n;
1416 REQUEST(xXFixesDestroyPointerBarrierReq);
1417
1418 swaps(&stuff->length, n);
1419 REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
1420 swapl(&stuff->barrier, n);
1421 return ProcXFixesVector[stuff->xfixesReqType](client);
1422}
1423
1032Bool 1424Bool
1033XFixesCursorInit (void) 1425XFixesCursorInit (void)
1034{ 1426{
@@ -1048,8 +1440,10 @@ XFixesCursorInit (void)
1048 cs = (CursorScreenPtr) calloc(1, sizeof (CursorScreenRec)); 1440 cs = (CursorScreenPtr) calloc(1, sizeof (CursorScreenRec));
1049 if (!cs) 1441 if (!cs)
1050 return FALSE; 1442 return FALSE;
1443 list_init(&cs->barriers);
1051 Wrap (cs, pScreen, CloseScreen, CursorCloseScreen); 1444 Wrap (cs, pScreen, CloseScreen, CursorCloseScreen);
1052 Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor); 1445 Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor);
1446 Wrap (cs, pScreen, ConstrainCursorHarder, CursorConstrainCursorHarder);
1053 cs->pCursorHideCounts = NULL; 1447 cs->pCursorHideCounts = NULL;
1054 SetCursorScreen (pScreen, cs); 1448 SetCursorScreen (pScreen, cs);
1055 } 1449 }
@@ -1059,7 +1453,10 @@ XFixesCursorInit (void)
1059 "XFixesCursorHideCount"); 1453 "XFixesCursorHideCount");
1060 CursorWindowType = CreateNewResourceType(CursorFreeWindow, 1454 CursorWindowType = CreateNewResourceType(CursorFreeWindow,
1061 "XFixesCursorWindow"); 1455 "XFixesCursorWindow");
1456 PointerBarrierType = CreateNewResourceType(CursorFreeBarrier,
1457 "XFixesPointerBarrier");
1062 1458
1063 return CursorClientType && CursorHideCountType && CursorWindowType; 1459 return CursorClientType && CursorHideCountType && CursorWindowType &&
1460 PointerBarrierType;
1064} 1461}
1065 1462
diff --git a/xfixes/xfixes.c b/xfixes/xfixes.c
index 54f0df341..e0ebedd80 100644
--- a/xfixes/xfixes.c
+++ b/xfixes/xfixes.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2010 Red Hat, Inc.
3 * 4 *
4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"), 6 * copy of this software and associated documentation files (the "Software"),
@@ -47,10 +48,6 @@
47 48
48#include "xfixesint.h" 49#include "xfixesint.h"
49#include "protocol-versions.h" 50#include "protocol-versions.h"
50/*
51 * Must use these instead of the constants from xfixeswire.h. They advertise
52 * what we implement, not what the protocol headers define.
53 */
54 51
55static unsigned char XFixesReqCode; 52static unsigned char XFixesReqCode;
56int XFixesEventBase; 53int XFixesEventBase;
@@ -97,11 +94,12 @@ ProcXFixesQueryVersion(ClientPtr client)
97 94
98/* Major version controls available requests */ 95/* Major version controls available requests */
99static const int version_requests[] = { 96static const int version_requests[] = {
100 X_XFixesQueryVersion, /* before client sends QueryVersion */ 97 X_XFixesQueryVersion, /* before client sends QueryVersion */
101 X_XFixesGetCursorImage, /* Version 1 */ 98 X_XFixesGetCursorImage, /* Version 1 */
102 X_XFixesChangeCursorByName, /* Version 2 */ 99 X_XFixesChangeCursorByName, /* Version 2 */
103 X_XFixesExpandRegion, /* Version 3 */ 100 X_XFixesExpandRegion, /* Version 3 */
104 X_XFixesShowCursor, /* Version 4 */ 101 X_XFixesShowCursor, /* Version 4 */
102 X_XFixesDestroyPointerBarrier, /* Version 5 */
105}; 103};
106 104
107#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) 105#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
@@ -142,6 +140,9 @@ int (*ProcXFixesVector[XFixesNumberRequests])(ClientPtr) = {
142/*************** Version 4 ****************/ 140/*************** Version 4 ****************/
143 ProcXFixesHideCursor, 141 ProcXFixesHideCursor,
144 ProcXFixesShowCursor, 142 ProcXFixesShowCursor,
143/*************** Version 5 ****************/
144 ProcXFixesCreatePointerBarrier,
145 ProcXFixesDestroyPointerBarrier,
145}; 146};
146 147
147static int 148static int
@@ -205,6 +206,9 @@ static int (*SProcXFixesVector[XFixesNumberRequests])(ClientPtr) = {
205/*************** Version 4 ****************/ 206/*************** Version 4 ****************/
206 SProcXFixesHideCursor, 207 SProcXFixesHideCursor,
207 SProcXFixesShowCursor, 208 SProcXFixesShowCursor,
209/*************** Version 5 ****************/
210 SProcXFixesCreatePointerBarrier,
211 SProcXFixesDestroyPointerBarrier,
208}; 212};
209 213
210static int 214static int
@@ -260,6 +264,8 @@ XFixesExtensionInit(void)
260 EventSwapVector[XFixesEventBase + XFixesCursorNotify] = 264 EventSwapVector[XFixesEventBase + XFixesCursorNotify] =
261 (EventSwapPtr) SXFixesCursorNotifyEvent; 265 (EventSwapPtr) SXFixesCursorNotifyEvent;
262 SetResourceTypeErrorValue(RegionResType, XFixesErrorBase + BadRegion); 266 SetResourceTypeErrorValue(RegionResType, XFixesErrorBase + BadRegion);
267 SetResourceTypeErrorValue(PointerBarrierType,
268 XFixesErrorBase + BadBarrier);
263 } 269 }
264} 270}
265 271
diff --git a/xfixes/xfixes.h b/xfixes/xfixes.h
index 1638350c2..5765e64b5 100644
--- a/xfixes/xfixes.h
+++ b/xfixes/xfixes.h
@@ -30,6 +30,7 @@
30#include "resource.h" 30#include "resource.h"
31 31
32extern _X_EXPORT RESTYPE RegionResType; 32extern _X_EXPORT RESTYPE RegionResType;
33extern _X_EXPORT RESTYPE PointerBarrierType;
33extern _X_EXPORT int XFixesErrorBase; 34extern _X_EXPORT int XFixesErrorBase;
34 35
35#define VERIFY_REGION(pRegion, rid, client, mode) \ 36#define VERIFY_REGION(pRegion, rid, client, mode) \
@@ -51,5 +52,21 @@ extern _X_EXPORT int XFixesErrorBase;
51extern _X_EXPORT RegionPtr 52extern _X_EXPORT RegionPtr
52XFixesRegionCopy (RegionPtr pRegion); 53XFixesRegionCopy (RegionPtr pRegion);
53 54
55struct PointerBarrier {
56 CARD16 x1, x2, y1, y2;
57 CARD32 directions;
58};
59
60
61extern int
62barrier_get_direction(int, int, int, int);
63extern BOOL
64barrier_is_blocking(const struct PointerBarrier*, int, int, int, int, double*);
65extern BOOL
66barrier_is_blocking_direction(const struct PointerBarrier*, int);
67extern void
68barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, int *y);
69
70
54 71
55#endif /* _XFIXES_H_ */ 72#endif /* _XFIXES_H_ */
diff --git a/xfixes/xfixesint.h b/xfixes/xfixesint.h
index d00536968..6ba276e8c 100644
--- a/xfixes/xfixesint.h
+++ b/xfixes/xfixesint.h
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2010 Red Hat, Inc.
3 * 4 *
4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"), 6 * copy of this software and associated documentation files (the "Software"),
@@ -278,6 +279,21 @@ ProcXFixesShowCursor (ClientPtr client);
278int 279int
279SProcXFixesShowCursor (ClientPtr client); 280SProcXFixesShowCursor (ClientPtr client);
280 281
282/* Version 5 */
283
284int
285ProcXFixesCreatePointerBarrier (ClientPtr client);
286
287int
288SProcXFixesCreatePointerBarrier (ClientPtr client);
289
290int
291ProcXFixesDestroyPointerBarrier (ClientPtr client);
292
293int
294SProcXFixesDestroyPointerBarrier (ClientPtr client);
295
296/* Xinerama */
281extern int (*PanoramiXSaveXFixesVector[XFixesNumberRequests])(ClientPtr); 297extern int (*PanoramiXSaveXFixesVector[XFixesNumberRequests])(ClientPtr);
282void PanoramiXFixesInit (void); 298void PanoramiXFixesInit (void);
283void PanoramiXFixesReset (void); 299void PanoramiXFixesReset (void);