1 From 14f1112bec18ccece8e732fe6c200a56546230c7 Mon Sep 17 00:00:00 2001
2 From: Adam Jackson <ajax@redhat.com>
3 Date: Thu, 17 Mar 2011 13:56:17 -0400
4 Subject: [PATCH] CRTC confine and pointer barriers
6 ---
7 dix/events.c | 7 +
8 dix/getevents.c | 12 +-
9 include/dix.h | 1 +
10 include/protocol-versions.h | 2 +-
11 mi/mipointer.c | 16 ++-
12 mi/mipointer.h | 6 +
13 randr/randr.c | 2 +
14 randr/randrstr.h | 4 +
15 randr/rrcrtc.c | 155 ++++++++++++++++
16 xfixes/cursor.c | 399 ++++++++++++++++++++++++++++++++++++++++++-
17 xfixes/xfixes.c | 24 ++-
18 xfixes/xfixes.h | 17 ++
19 xfixes/xfixesint.h | 16 ++
20 14 files changed, 658 insertions(+), 16 deletions(-)
22 Index: xorg-server/dix/events.c
23 ===================================================================
24 --- xorg-server.orig/dix/events.c 2011-08-24 12:52:44.325647127 +0300
25 +++ xorg-server/dix/events.c 2011-08-24 12:57:24.685651121 +0300
26 @@ -328,6 +328,13 @@
27 return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD;
28 }
30 +Bool
31 +IsFloating(DeviceIntPtr dev)
32 +{
33 + return GetMaster(dev, MASTER_KEYBOARD) == NULL;
34 +}
35 +
36 +
37 /**
38 * Max event opcode.
39 */
40 Index: xorg-server/dix/getevents.c
41 ===================================================================
42 --- xorg-server.orig/dix/getevents.c 2011-08-24 12:52:44.315647128 +0300
43 +++ xorg-server/dix/getevents.c 2011-08-24 12:57:20.625651063 +0300
44 @@ -816,7 +816,11 @@
45 * miPointerSetPosition() and then scale back into device coordinates (if
46 * needed). miPSP will change x/y if the screen was crossed.
47 *
48 + * The coordinates provided are always absolute. The parameter mode whether
49 + * it was relative or absolute movement that landed us at those coordinates.
50 + *
51 * @param dev The device to be moved.
52 + * @param mode Movement mode (Absolute or Relative)
53 * @param x Pointer to current x-axis value, may be modified.
54 * @param y Pointer to current y-axis value, may be modified.
55 * @param x_frac Fractional part of current x-axis value, may be modified.
56 @@ -828,7 +832,8 @@
57 * @param screeny_frac Fractional part of screen y coordinate, as above.
58 */
59 static void
60 -positionSprite(DeviceIntPtr dev, int *x, int *y, float x_frac, float y_frac,
61 +positionSprite(DeviceIntPtr dev, int mode,
62 + int *x, int *y, float x_frac, float y_frac,
63 ScreenPtr scr, int *screenx, int *screeny, float *screenx_frac, float *screeny_frac)
64 {
65 int old_screenx, old_screeny;
66 @@ -867,7 +872,7 @@
67 old_screeny = *screeny;
68 /* This takes care of crossing screens for us, as well as clipping
69 * to the current screen. */
70 - miPointerSetPosition(dev, screenx, screeny);
71 + _miPointerSetPosition(dev, mode, screenx, screeny);
73 if (dev->u.master) {
74 dev->u.master->last.valuators[0] = *screenx;
75 @@ -1202,7 +1207,8 @@
76 if ((flags & POINTER_NORAW) == 0)
77 set_raw_valuators(raw, &mask, raw->valuators.data);
79 - positionSprite(pDev, &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac);
80 + positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative,
81 + &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac);
82 updateHistory(pDev, &mask, ms);
84 /* Update the valuators with the true value sent to the client*/
85 Index: xorg-server/include/dix.h
86 ===================================================================
87 --- xorg-server.orig/include/dix.h 2011-08-24 12:52:44.355647127 +0300
88 +++ xorg-server/include/dix.h 2011-08-24 12:57:24.695651123 +0300
89 @@ -570,6 +570,7 @@
90 extern Bool _X_EXPORT IsKeyboardDevice(DeviceIntPtr dev);
91 extern Bool IsPointerEvent(InternalEvent *event);
92 extern _X_EXPORT Bool IsMaster(DeviceIntPtr dev);
93 +extern _X_EXPORT Bool IsFloating(DeviceIntPtr dev);
95 extern _X_HIDDEN void CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
96 extern _X_HIDDEN int CorePointerProc(DeviceIntPtr dev, int what);
97 Index: xorg-server/include/protocol-versions.h
98 ===================================================================
99 --- xorg-server.orig/include/protocol-versions.h 2011-08-24 12:52:44.365647129 +0300
100 +++ xorg-server/include/protocol-versions.h 2011-08-24 12:57:20.735651065 +0300
101 @@ -126,7 +126,7 @@
102 #define SERVER_XF86VIDMODE_MINOR_VERSION 2
104 /* Fixes */
105 -#define SERVER_XFIXES_MAJOR_VERSION 4
106 +#define SERVER_XFIXES_MAJOR_VERSION 5
107 #define SERVER_XFIXES_MINOR_VERSION 0
109 /* X Input */
110 Index: xorg-server/mi/mipointer.c
111 ===================================================================
112 --- xorg-server.orig/mi/mipointer.c 2011-08-24 12:56:49.645650622 +0300
113 +++ xorg-server/mi/mipointer.c 2011-08-24 12:56:49.825650624 +0300
114 @@ -229,6 +229,10 @@
115 SetupScreen (pScreen);
117 GenerateEvent = generateEvent;
118 +
119 + if (pScreen->ConstrainCursorHarder)
120 + pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y);
121 +
122 /* device dependent - must pend signal and call miPointerWarpCursor */
123 (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y);
124 if (!generateEvent)
125 @@ -488,7 +492,7 @@
126 }
128 void
129 -miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y)
130 +_miPointerSetPosition(DeviceIntPtr pDev, int mode, int *x, int *y)
131 {
132 miPointerScreenPtr pScreenPriv;
133 ScreenPtr pScreen;
134 @@ -532,6 +536,9 @@
135 if (*y >= pPointer->limits.y2)
136 *y = pPointer->limits.y2 - 1;
138 + if (pScreen->ConstrainCursorHarder)
139 + pScreen->ConstrainCursorHarder(pDev, pScreen, mode, x, y);
140 +
141 if (pPointer->x == *x && pPointer->y == *y &&
142 pPointer->pScreen == pScreen)
143 return;
144 @@ -539,6 +546,13 @@
145 miPointerMoveNoEvent(pDev, pScreen, *x, *y);
146 }
148 +/* ABI hack */
149 +void
150 +miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y)
151 +{
152 + _miPointerSetPosition(pDev, Absolute, x, y);
153 +}
154 +
155 void
156 miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y)
157 {
158 Index: xorg-server/mi/mipointer.h
159 ===================================================================
160 --- xorg-server.orig/mi/mipointer.h 2011-08-24 12:52:44.375647128 +0300
161 +++ xorg-server/mi/mipointer.h 2011-08-24 12:56:49.825650624 +0300
162 @@ -131,6 +131,12 @@
164 /* Moves the cursor to the specified position. May clip the co-ordinates:
165 * x and y are modified in-place. */
166 +extern _X_EXPORT void _miPointerSetPosition(
167 + DeviceIntPtr pDev,
168 + int mode,
169 + int *x,
170 + int *y);
171 +
172 extern _X_EXPORT void miPointerSetPosition(
173 DeviceIntPtr pDev,
174 int *x,
175 Index: xorg-server/randr/randr.c
176 ===================================================================
177 --- xorg-server.orig/randr/randr.c 2011-08-24 12:56:49.745650625 +0300
178 +++ xorg-server/randr/randr.c 2011-08-24 12:56:49.825650624 +0300
179 @@ -270,6 +270,8 @@
181 wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen);
183 + pScreen->ConstrainCursorHarder = RRConstrainCursorHarder;
184 +
185 pScrPriv->numOutputs = 0;
186 pScrPriv->outputs = NULL;
187 pScrPriv->numCrtcs = 0;
188 Index: xorg-server/randr/randrstr.h
189 ===================================================================
190 --- xorg-server.orig/randr/randrstr.h 2011-08-24 12:52:44.305647126 +0300
191 +++ xorg-server/randr/randrstr.h 2011-08-24 12:56:49.825650624 +0300
192 @@ -297,6 +297,7 @@
193 int rate;
194 int size;
195 #endif
196 + Bool discontiguous;
197 } rrScrPrivRec, *rrScrPrivPtr;
199 extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec;
200 @@ -700,6 +701,9 @@
201 int
202 ProcRRSetPanning (ClientPtr client);
204 +void
205 +RRConstrainCursorHarder (DeviceIntPtr, ScreenPtr, int, int *, int *);
206 +
207 /* rrdispatch.c */
208 extern _X_EXPORT Bool
209 RRClientKnowsRates (ClientPtr pClient);
210 Index: xorg-server/randr/rrcrtc.c
211 ===================================================================
212 --- xorg-server.orig/randr/rrcrtc.c 2011-08-24 12:52:44.285647124 +0300
213 +++ xorg-server/randr/rrcrtc.c 2011-08-24 12:56:49.825650624 +0300
214 @@ -1,5 +1,6 @@
215 /*
216 * Copyright © 2006 Keith Packard
217 + * Copyright 2010 Red Hat, Inc
218 *
219 * Permission to use, copy, modify, distribute, and sell this software and its
220 * documentation for any purpose is hereby granted without fee, provided that
221 @@ -22,6 +23,7 @@
223 #include "randrstr.h"
224 #include "swaprep.h"
225 +#include "mipointer.h"
227 RESTYPE RRCrtcType;
229 @@ -292,6 +294,92 @@
230 return FALSE;
231 }
233 +static void
234 +crtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom)
235 +{
236 + *left = crtc->x;
237 + *top = crtc->y;
238 +
239 + switch (crtc->rotation) {
240 + case RR_Rotate_0:
241 + case RR_Rotate_180:
242 + default:
243 + *right = crtc->x + crtc->mode->mode.width;
244 + *bottom = crtc->y + crtc->mode->mode.height;
245 + return;
246 + case RR_Rotate_90:
247 + case RR_Rotate_270:
248 + *right = crtc->x + crtc->mode->mode.height;
249 + *bottom = crtc->y + crtc->mode->mode.width;
250 + return;
251 + }
252 +}
253 +
254 +/* overlapping counts as adjacent */
255 +static Bool
256 +crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b)
257 +{
258 + /* left, right, top, bottom... */
259 + int al, ar, at, ab;
260 + int bl, br, bt, bb;
261 + int cl, cr, ct, cb; /* the overlap, if any */
262 +
263 + crtc_bounds(a, &al, &ar, &at, &ab);
264 + crtc_bounds(b, &bl, &br, &bt, &bb);
265 +
266 + cl = max(al, bl);
267 + cr = min(ar, br);
268 + ct = max(at, bt);
269 + cb = min(ab, bb);
270 +
271 + return (cl <= cr) && (ct <= cb);
272 +}
273 +
274 +/* Depth-first search and mark all CRTCs reachable from cur */
275 +static void
276 +mark_crtcs (rrScrPrivPtr pScrPriv, int *reachable, int cur)
277 +{
278 + int i;
279 + reachable[cur] = TRUE;
280 + for (i = 0; i < pScrPriv->numCrtcs; ++i) {
281 + if (reachable[i] || !pScrPriv->crtcs[i]->mode)
282 + continue;
283 + if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i]))
284 + mark_crtcs(pScrPriv, reachable, i);
285 + }
286 +}
287 +
288 +static void
289 +RRComputeContiguity (ScreenPtr pScreen)
290 +{
291 + rrScrPriv(pScreen);
292 + Bool discontiguous = TRUE;
293 + int i, n = pScrPriv->numCrtcs;
294 +
295 + int *reachable = calloc(n, sizeof(int));
296 + if (!reachable)
297 + goto out;
298 +
299 + /* Find first enabled CRTC and start search for reachable CRTCs from it */
300 + for (i = 0; i < n; ++i) {
301 + if (pScrPriv->crtcs[i]->mode) {
302 + mark_crtcs(pScrPriv, reachable, i);
303 + break;
304 + }
305 + }
306 +
307 + /* Check that all enabled CRTCs were marked as reachable */
308 + for (i = 0; i < n; ++i)
309 + if (pScrPriv->crtcs[i]->mode && !reachable[i])
310 + goto out;
311 +
312 + discontiguous = FALSE;
313 +
314 +out:
315 + free(reachable);
316 + pScrPriv->discontiguous = discontiguous;
317 +}
318 +
319 /*
320 * Request that the Crtc be reconfigured
321 */
322 @@ -306,6 +394,7 @@
323 {
324 ScreenPtr pScreen = crtc->pScreen;
325 Bool ret = FALSE;
326 + Bool recompute = TRUE;
327 rrScrPriv(pScreen);
329 /* See if nothing changed */
330 @@ -318,6 +407,7 @@
331 !RRCrtcPendingProperties (crtc) &&
332 !RRCrtcPendingTransform (crtc))
333 {
334 + recompute = FALSE;
335 ret = TRUE;
336 }
337 else
338 @@ -381,6 +471,10 @@
339 RRPostPendingProperties (outputs[o]);
340 }
341 }
342 +
343 + if (recompute)
344 + RRComputeContiguity(pScreen);
345 +
346 return ret;
347 }
349 @@ -1349,3 +1443,64 @@
350 free(reply);
351 return Success;
352 }
353 +
354 +void
355 +RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, int *y)
356 +{
357 + rrScrPriv (pScreen);
358 + int i;
359 +
360 + /* intentional dead space -> let it float */
361 + if (pScrPriv->discontiguous)
362 + return;
363 +
364 + /* if we're moving inside a crtc, we're fine */
365 + for (i = 0; i < pScrPriv->numCrtcs; i++) {
366 + RRCrtcPtr crtc = pScrPriv->crtcs[i];
367 +
368 + int left, right, top, bottom;
369 +
370 + if (!crtc->mode)
371 + continue;
372 +
373 + crtc_bounds(crtc, &left, &right, &top, &bottom);
374 +
375 + if ((*x >= left) && (*x <= right) && (*y >= top) && (*y <= bottom))
376 + return;
377 + }
378 +
379 + /* if we're trying to escape, clamp to the CRTC we're coming from */
380 + for (i = 0; i < pScrPriv->numCrtcs; i++) {
381 + RRCrtcPtr crtc = pScrPriv->crtcs[i];
382 + int nx, ny;
383 + int left, right, top, bottom;
384 +
385 + if (!crtc->mode)
386 + continue;
387 +
388 + crtc_bounds(crtc, &left, &right, &top, &bottom);
389 + miPointerGetPosition(pDev, &nx, &ny);
390 +
391 + if ((nx >= left) && (nx <= right) && (ny >= top) && (ny <= bottom)) {
392 + if ((*x <= left) || (*x >= right)) {
393 + int dx = *x - nx;
394 +
395 + if (dx > 0)
396 + *x = right;
397 + else if (dx < 0)
398 + *x = left;
399 + }
400 +
401 + if ((*y <= top) || (*y >= bottom)) {
402 + int dy = *y - ny;
403 +
404 + if (dy > 0)
405 + *y = bottom;
406 + else if (dy < 0)
407 + *y = top;
408 + }
409 +
410 + return;
411 + }
412 + }
413 +}
414 Index: xorg-server/xfixes/cursor.c
415 ===================================================================
416 --- xorg-server.orig/xfixes/cursor.c 2011-08-24 12:52:44.345647126 +0300
417 +++ xorg-server/xfixes/cursor.c 2011-08-24 12:56:49.825650624 +0300
418 @@ -1,5 +1,6 @@
419 /*
420 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
421 + * Copyright 2010 Red Hat, Inc.
422 *
423 * Permission is hereby granted, free of charge, to any person obtaining a
424 * copy of this software and associated documentation files (the "Software"),
425 @@ -50,13 +51,16 @@
426 #include "cursorstr.h"
427 #include "dixevents.h"
428 #include "servermd.h"
429 +#include "mipointer.h"
430 #include "inputstr.h"
431 #include "windowstr.h"
432 #include "xace.h"
433 +#include "list.h"
435 static RESTYPE CursorClientType;
436 static RESTYPE CursorHideCountType;
437 static RESTYPE CursorWindowType;
438 +RESTYPE PointerBarrierType;
439 static CursorPtr CursorCurrent[MAXDEVICES];
441 static DevPrivateKeyRec CursorScreenPrivateKeyRec;
442 @@ -107,6 +111,14 @@
443 XID resource;
444 } CursorHideCountRec;
446 +typedef struct PointerBarrierClient *PointerBarrierClientPtr;
447 +
448 +struct PointerBarrierClient {
449 + ScreenPtr screen;
450 + struct PointerBarrier barrier;
451 + struct list entry;
452 +};
453 +
454 /*
455 * Wrap DisplayCursor to catch cursor change events
456 */
457 @@ -114,7 +126,9 @@
458 typedef struct _CursorScreen {
459 DisplayCursorProcPtr DisplayCursor;
460 CloseScreenProcPtr CloseScreen;
461 + ConstrainCursorHarderProcPtr ConstrainCursorHarder;
462 CursorHideCountPtr pCursorHideCounts;
463 + struct list barriers;
464 } CursorScreenRec, *CursorScreenPtr;
466 #define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey))
467 @@ -184,9 +198,11 @@
468 Bool ret;
469 CloseScreenProcPtr close_proc;
470 DisplayCursorProcPtr display_proc;
471 + ConstrainCursorHarderProcPtr constrain_proc;
473 Unwrap (cs, pScreen, CloseScreen, close_proc);
474 Unwrap (cs, pScreen, DisplayCursor, display_proc);
475 + Unwrap (cs, pScreen, ConstrainCursorHarder, constrain_proc);
476 deleteCursorHideCountsForScreen(pScreen);
477 ret = (*pScreen->CloseScreen) (index, pScreen);
478 free(cs);
479 @@ -1029,6 +1045,382 @@
480 return 1;
481 }
483 +static BOOL
484 +barrier_is_horizontal(const struct PointerBarrier *barrier)
485 +{
486 + return barrier->y1 == barrier->y2;
487 +}
488 +
489 +static BOOL
490 +barrier_is_vertical(const struct PointerBarrier *barrier)
491 +{
492 + return barrier->x1 == barrier->x2;
493 +}
494 +
495 +/**
496 + * @return The set of barrier movement directions the movement vector
497 + * x1/y1 → x2/y2 represents.
498 + */
499 +int
500 +barrier_get_direction(int x1, int y1, int x2, int y2)
501 +{
502 + int direction = 0;
503 +
504 + /* which way are we trying to go */
505 + if (x2 > x1)
506 + direction |= BarrierPositiveX;
507 + if (x2 < x1)
508 + direction |= BarrierNegativeX;
509 + if (y2 > y1)
510 + direction |= BarrierPositiveY;
511 + if (y2 < y1)
512 + direction |= BarrierNegativeY;
513 +
514 + return direction;
515 +}
516 +
517 +/**
518 + * Test if the barrier may block movement in the direction defined by
519 + * x1/y1 → x2/y2. This function only tests whether the directions could be
520 + * blocked, it does not test if the barrier actually blocks the movement.
521 + *
522 + * @return TRUE if the barrier blocks the direction of movement or FALSE
523 + * otherwise.
524 + */
525 +BOOL
526 +barrier_is_blocking_direction(const struct PointerBarrier *barrier, int direction)
527 +{
528 + /* Barriers define which way is ok, not which way is blocking */
529 + return (barrier->directions & direction) != direction;
530 +}
531 +
532 +/**
533 + * Test if the movement vector x1/y1 → x2/y2 is intersecting with the
534 + * barrier. A movement vector with the startpoint or endpoint adjacent to
535 + * the barrier itself counts as intersecting.
536 + *
537 + * @param x1 X start coordinate of movement vector
538 + * @param y1 Y start coordinate of movement vector
539 + * @param x2 X end coordinate of movement vector
540 + * @param y2 Y end coordinate of movement vector
541 + * @param[out] distance The distance between the start point and the
542 + * intersection with the barrier (if applicable).
543 + * @return TRUE if the barrier intersects with the given vector
544 + */
545 +BOOL
546 +barrier_is_blocking(const struct PointerBarrier *barrier,
547 + int x1, int y1, int x2, int y2,
548 + double *distance)
549 +{
550 + BOOL rc = FALSE;
551 + float ua, ub, ud;
552 + int dir = barrier_get_direction(x1, y1, x2, y2);
553 +
554 + /* Algorithm below doesn't handle edge cases well, hence the extra
555 + * checks. */
556 + if (barrier_is_vertical(barrier)) {
557 + /* handle immediate barrier adjacency, moving away */
558 + if (dir & BarrierPositiveX && x1 == barrier->x1)
559 + return FALSE;
560 + if (dir & BarrierNegativeX && x1 == (barrier->x1 - 1))
561 + return FALSE;
562 + /* startpoint adjacent to barrier, moving towards -> block */
563 + if (x1 == barrier->x1 && y1 >= barrier->y1 && y1 <= barrier->y2) {
564 + *distance = 0;
565 + return TRUE;
566 + }
567 + } else {
568 + /* handle immediate barrier adjacency, moving away */
569 + if (dir & BarrierPositiveY && y1 == barrier->y1)
570 + return FALSE;
571 + if (dir & BarrierNegativeY && y1 == (barrier->y1 - 1))
572 + return FALSE;
573 + /* startpoint adjacent to barrier, moving towards -> block */
574 + if (y1 == barrier->y1 && x1 >= barrier->x1 && x1 <= barrier->x2) {
575 + *distance = 0;
576 + return TRUE;
577 + }
578 + }
579 +
580 + /* not an edge case, compute distance */
581 + ua = 0;
582 + ud = (barrier->y2 - barrier->y1) * (x2 - x1) - (barrier->x2 - barrier->x1) * (y2 - y1);
583 + if (ud != 0) {
584 + ua = ((barrier->x2 - barrier->x1) * (y1 - barrier->y1) -
585 + (barrier->y2 - barrier->y1) * (x1 - barrier->x1)) / ud;
586 + ub = ((x2 - x1) * (y1 - barrier->y1) -
587 + (y2 - y1) * (x1 - barrier->x1)) / ud;
588 + if (ua < 0 || ua > 1 || ub < 0 || ub > 1)
589 + ua = 0;
590 + }
591 +
592 + if (ua > 0 && ua <= 1)
593 + {
594 + double ix = barrier->x1 + ua * (barrier->x2 - barrier->x1);
595 + double iy = barrier->y1 + ua * (barrier->y2 - barrier->y1);
596 +
597 + *distance = sqrt(pow(x1 - ix, 2) + pow(y1 - iy, 2));
598 + rc = TRUE;
599 + }
600 +
601 + return rc;
602 +}
603 +
604 +/**
605 + * Find the nearest barrier that is blocking movement from x1/y1 to x2/y2.
606 + *
607 + * @param dir Only barriers blocking movement in direction dir are checked
608 + * @param x1 X start coordinate of movement vector
609 + * @param y1 Y start coordinate of movement vector
610 + * @param x2 X end coordinate of movement vector
611 + * @param y2 Y end coordinate of movement vector
612 + * @return The barrier nearest to the movement origin that blocks this movement.
613 + */
614 +static struct PointerBarrier*
615 +barrier_find_nearest(CursorScreenPtr cs, int dir,
616 + int x1, int y1, int x2, int y2)
617 +{
618 + struct PointerBarrierClient *c;
619 + struct PointerBarrier *nearest = NULL;
620 + double min_distance = INT_MAX; /* can't get higher than that in X anyway */
621 +
622 + list_for_each_entry(c, &cs->barriers, entry) {
623 + struct PointerBarrier *b = &c->barrier;
624 + double distance;
625 +
626 + if (!barrier_is_blocking_direction(b, dir))
627 + continue;
628 +
629 + if (barrier_is_blocking(b, x1, y1, x2, y2, &distance))
630 + {
631 + if (min_distance > distance)
632 + {
633 + min_distance = distance;
634 + nearest = b;
635 + }
636 + }
637 + }
638 +
639 + return nearest;
640 +}
641 +
642 +/**
643 + * Clamp to the given barrier given the movement direction specified in dir.
644 + *
645 + * @param barrier The barrier to clamp to
646 + * @param dir The movement direction
647 + * @param[out] x The clamped x coordinate.
648 + * @param[out] y The clamped x coordinate.
649 + */
650 +void
651 +barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, int *y)
652 +{
653 + if (barrier_is_vertical(barrier))
654 + {
655 + if ((dir & BarrierNegativeX) & ~barrier->directions)
656 + *x = barrier->x1;
657 + if ((dir & BarrierPositiveX) & ~barrier->directions)
658 + *x = barrier->x1 - 1;
659 + }
660 + if (barrier_is_horizontal(barrier))
661 + {
662 + if ((dir & BarrierNegativeY) & ~barrier->directions)
663 + *y = barrier->y1;
664 + if ((dir & BarrierPositiveY) & ~barrier->directions)
665 + *y = barrier->y1 - 1;
666 + }
667 +}
668 +
669 +static void
670 +CursorConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, int *x, int *y)
671 +{
672 + CursorScreenPtr cs = GetCursorScreen(screen);
673 +
674 + if (!list_is_empty(&cs->barriers) && !IsFloating(dev) && mode == Relative) {
675 + int ox, oy;
676 + int dir;
677 + struct PointerBarrier *nearest = NULL;
678 +
679 + /* where are we coming from */
680 + miPointerGetPosition(dev, &ox, &oy);
681 +
682 + /* How this works:
683 + * Given the origin and the movement vector, get the nearest barrier
684 + * to the origin that is blocking the movement.
685 + * Clamp to that barrier.
686 + * Then, check from the clamped intersection to the original
687 + * destination, again finding the nearest barrier and clamping.
688 + */
689 + dir = barrier_get_direction(ox, oy, *x, *y);
690 +
691 + nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
692 + if (nearest) {
693 + barrier_clamp_to_barrier(nearest, dir, x, y);
694 +
695 + if (barrier_is_vertical(nearest)) {
696 + dir &= ~(BarrierNegativeX | BarrierPositiveX);
697 + ox = *x;
698 + } else if (barrier_is_horizontal(nearest)) {
699 + dir &= ~(BarrierNegativeY | BarrierPositiveY);
700 + oy = *y;
701 + }
702 +
703 + nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y);
704 + if (nearest) {
705 + barrier_clamp_to_barrier(nearest, dir, x, y);
706 + }
707 + }
708 + }
709 +
710 + if (cs->ConstrainCursorHarder) {
711 + screen->ConstrainCursorHarder = cs->ConstrainCursorHarder;
712 + screen->ConstrainCursorHarder(dev, screen, mode, x, y);
713 + screen->ConstrainCursorHarder = CursorConstrainCursorHarder;
714 + }
715 +}
716 +
717 +static struct PointerBarrierClient *
718 +CreatePointerBarrierClient(ScreenPtr screen, ClientPtr client,
719 + xXFixesCreatePointerBarrierReq *stuff)
720 +{
721 + CursorScreenPtr cs = GetCursorScreen(screen);
722 + struct PointerBarrierClient *ret = malloc(sizeof(*ret));
723 +
724 + if (ret) {
725 + ret->screen = screen;
726 + ret->barrier.x1 = min(stuff->x1, stuff->x2);
727 + ret->barrier.x2 = max(stuff->x1, stuff->x2);
728 + ret->barrier.y1 = min(stuff->y1, stuff->y2);
729 + ret->barrier.y2 = max(stuff->y1, stuff->y2);
730 + ret->barrier.directions = stuff->directions & 0x0f;
731 + if (barrier_is_horizontal(&ret->barrier))
732 + ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
733 + if (barrier_is_vertical(&ret->barrier))
734 + ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY);
735 + list_add(&ret->entry, &cs->barriers);
736 + }
737 +
738 + return ret;
739 +}
740 +
741 +int
742 +ProcXFixesCreatePointerBarrier (ClientPtr client)
743 +{
744 + int err;
745 + WindowPtr pWin;
746 + struct PointerBarrierClient *barrier;
747 + struct PointerBarrier b;
748 + REQUEST (xXFixesCreatePointerBarrierReq);
749 +
750 + REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
751 + LEGAL_NEW_RESOURCE(stuff->barrier, client);
752 +
753 + err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
754 + if (err != Success) {
755 + client->errorValue = stuff->window;
756 + return err;
757 + }
758 +
759 + /* This sure does need fixing. */
760 + if (stuff->num_devices)
761 + return BadImplementation;
762 +
763 + b.x1 = stuff->x1;
764 + b.x2 = stuff->x2;
765 + b.y1 = stuff->y1;
766 + b.y2 = stuff->y2;
767 +
768 + if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b))
769 + return BadValue;
770 +
771 + /* no 0-sized barriers */
772 + if (barrier_is_horizontal(&b) && barrier_is_vertical(&b))
773 + return BadValue;
774 +
775 + if (!(barrier = CreatePointerBarrierClient(pWin->drawable.pScreen,
776 + client, stuff)))
777 + return BadAlloc;
778 +
779 + if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
780 + return BadAlloc;
781 +
782 + return Success;
783 +}
784 +
785 +int
786 +SProcXFixesCreatePointerBarrier (ClientPtr client)
787 +{
788 + int n;
789 + REQUEST(xXFixesCreatePointerBarrierReq);
790 +
791 + swaps(&stuff->length, n);
792 + REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq);
793 + swapl(&stuff->barrier, n);
794 + swapl(&stuff->window, n);
795 + swaps(&stuff->x1, n);
796 + swaps(&stuff->y1, n);
797 + swaps(&stuff->x2, n);
798 + swaps(&stuff->y2, n);
799 + swapl(&stuff->directions, n);
800 + return ProcXFixesVector[stuff->xfixesReqType](client);
801 +}
802 +
803 +static int
804 +CursorFreeBarrier(void *data, XID id)
805 +{
806 + struct PointerBarrierClient *b = NULL, *barrier;
807 + ScreenPtr screen;
808 + CursorScreenPtr cs;
809 +
810 + barrier = container_of(data, struct PointerBarrierClient, barrier);
811 + screen = barrier->screen;
812 + cs = GetCursorScreen(screen);
813 +
814 + /* find and unlink from the screen private */
815 + list_for_each_entry(b, &cs->barriers, entry) {
816 + if (b == barrier) {
817 + list_del(&b->entry);
818 + break;
819 + }
820 + }
821 +
822 + free(barrier);
823 + return Success;
824 +}
825 +
826 +int
827 +ProcXFixesDestroyPointerBarrier (ClientPtr client)
828 +{
829 + int err;
830 + void *barrier;
831 + REQUEST (xXFixesDestroyPointerBarrierReq);
832 +
833 + REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
834 +
835 + err = dixLookupResourceByType((void **)&barrier, stuff->barrier,
836 + PointerBarrierType, client,
837 + DixDestroyAccess);
838 + if (err != Success) {
839 + client->errorValue = stuff->barrier;
840 + return err;
841 + }
842 +
843 + FreeResource(stuff->barrier, RT_NONE);
844 + return Success;
845 +}
846 +
847 +int
848 +SProcXFixesDestroyPointerBarrier (ClientPtr client)
849 +{
850 + int n;
851 + REQUEST(xXFixesDestroyPointerBarrierReq);
852 +
853 + swaps(&stuff->length, n);
854 + REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
855 + swapl(&stuff->barrier, n);
856 + return ProcXFixesVector[stuff->xfixesReqType](client);
857 +}
858 +
859 Bool
860 XFixesCursorInit (void)
861 {
862 @@ -1048,8 +1440,10 @@
863 cs = (CursorScreenPtr) calloc(1, sizeof (CursorScreenRec));
864 if (!cs)
865 return FALSE;
866 + list_init(&cs->barriers);
867 Wrap (cs, pScreen, CloseScreen, CursorCloseScreen);
868 Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor);
869 + Wrap (cs, pScreen, ConstrainCursorHarder, CursorConstrainCursorHarder);
870 cs->pCursorHideCounts = NULL;
871 SetCursorScreen (pScreen, cs);
872 }
873 @@ -1059,7 +1453,10 @@
874 "XFixesCursorHideCount");
875 CursorWindowType = CreateNewResourceType(CursorFreeWindow,
876 "XFixesCursorWindow");
877 + PointerBarrierType = CreateNewResourceType(CursorFreeBarrier,
878 + "XFixesPointerBarrier");
880 - return CursorClientType && CursorHideCountType && CursorWindowType;
881 + return CursorClientType && CursorHideCountType && CursorWindowType &&
882 + PointerBarrierType;
883 }
885 Index: xorg-server/xfixes/xfixes.c
886 ===================================================================
887 --- xorg-server.orig/xfixes/xfixes.c 2011-08-24 12:52:44.355647127 +0300
888 +++ xorg-server/xfixes/xfixes.c 2011-08-24 12:56:49.825650624 +0300
889 @@ -1,5 +1,6 @@
890 /*
891 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
892 + * Copyright 2010 Red Hat, Inc.
893 *
894 * Permission is hereby granted, free of charge, to any person obtaining a
895 * copy of this software and associated documentation files (the "Software"),
896 @@ -47,10 +48,6 @@
898 #include "xfixesint.h"
899 #include "protocol-versions.h"
900 -/*
901 - * Must use these instead of the constants from xfixeswire.h. They advertise
902 - * what we implement, not what the protocol headers define.
903 - */
905 static unsigned char XFixesReqCode;
906 int XFixesEventBase;
907 @@ -97,11 +94,12 @@
909 /* Major version controls available requests */
910 static const int version_requests[] = {
911 - X_XFixesQueryVersion, /* before client sends QueryVersion */
912 - X_XFixesGetCursorImage, /* Version 1 */
913 - X_XFixesChangeCursorByName, /* Version 2 */
914 - X_XFixesExpandRegion, /* Version 3 */
915 - X_XFixesShowCursor, /* Version 4 */
916 + X_XFixesQueryVersion, /* before client sends QueryVersion */
917 + X_XFixesGetCursorImage, /* Version 1 */
918 + X_XFixesChangeCursorByName, /* Version 2 */
919 + X_XFixesExpandRegion, /* Version 3 */
920 + X_XFixesShowCursor, /* Version 4 */
921 + X_XFixesDestroyPointerBarrier, /* Version 5 */
922 };
924 #define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
925 @@ -142,6 +140,9 @@
926 /*************** Version 4 ****************/
927 ProcXFixesHideCursor,
928 ProcXFixesShowCursor,
929 +/*************** Version 5 ****************/
930 + ProcXFixesCreatePointerBarrier,
931 + ProcXFixesDestroyPointerBarrier,
932 };
934 static int
935 @@ -205,6 +206,9 @@
936 /*************** Version 4 ****************/
937 SProcXFixesHideCursor,
938 SProcXFixesShowCursor,
939 +/*************** Version 5 ****************/
940 + SProcXFixesCreatePointerBarrier,
941 + SProcXFixesDestroyPointerBarrier,
942 };
944 static int
945 @@ -260,6 +264,8 @@
946 EventSwapVector[XFixesEventBase + XFixesCursorNotify] =
947 (EventSwapPtr) SXFixesCursorNotifyEvent;
948 SetResourceTypeErrorValue(RegionResType, XFixesErrorBase + BadRegion);
949 + SetResourceTypeErrorValue(PointerBarrierType,
950 + XFixesErrorBase + BadBarrier);
951 }
952 }
954 Index: xorg-server/xfixes/xfixes.h
955 ===================================================================
956 --- xorg-server.orig/xfixes/xfixes.h 2011-08-24 12:52:44.335647125 +0300
957 +++ xorg-server/xfixes/xfixes.h 2011-08-24 12:56:49.825650624 +0300
958 @@ -30,6 +30,7 @@
959 #include "resource.h"
961 extern _X_EXPORT RESTYPE RegionResType;
962 +extern _X_EXPORT RESTYPE PointerBarrierType;
963 extern _X_EXPORT int XFixesErrorBase;
965 #define VERIFY_REGION(pRegion, rid, client, mode) \
966 @@ -51,5 +52,21 @@
967 extern _X_EXPORT RegionPtr
968 XFixesRegionCopy (RegionPtr pRegion);
970 +struct PointerBarrier {
971 + CARD16 x1, x2, y1, y2;
972 + CARD32 directions;
973 +};
974 +
975 +
976 +extern int
977 +barrier_get_direction(int, int, int, int);
978 +extern BOOL
979 +barrier_is_blocking(const struct PointerBarrier*, int, int, int, int, double*);
980 +extern BOOL
981 +barrier_is_blocking_direction(const struct PointerBarrier*, int);
982 +extern void
983 +barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, int *y);
984 +
985 +
987 #endif /* _XFIXES_H_ */
988 Index: xorg-server/xfixes/xfixesint.h
989 ===================================================================
990 --- xorg-server.orig/xfixes/xfixesint.h 2011-08-24 12:52:44.345647126 +0300
991 +++ xorg-server/xfixes/xfixesint.h 2011-08-24 12:56:49.825650624 +0300
992 @@ -1,5 +1,6 @@
993 /*
994 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
995 + * Copyright 2010 Red Hat, Inc.
996 *
997 * Permission is hereby granted, free of charge, to any person obtaining a
998 * copy of this software and associated documentation files (the "Software"),
999 @@ -278,6 +279,21 @@
1000 int
1001 SProcXFixesShowCursor (ClientPtr client);
1003 +/* Version 5 */
1004 +
1005 +int
1006 +ProcXFixesCreatePointerBarrier (ClientPtr client);
1007 +
1008 +int
1009 +SProcXFixesCreatePointerBarrier (ClientPtr client);
1010 +
1011 +int
1012 +ProcXFixesDestroyPointerBarrier (ClientPtr client);
1013 +
1014 +int
1015 +SProcXFixesDestroyPointerBarrier (ClientPtr client);
1016 +
1017 +/* Xinerama */
1018 extern int (*PanoramiXSaveXFixesVector[XFixesNumberRequests])(ClientPtr);
1019 void PanoramiXFixesInit (void);
1020 void PanoramiXFixesReset (void);