Merge remote-tracking branch 'ajax/xserver-next'
This commit is contained in:
		
						commit
						0643c05651
					
				|  | @ -810,7 +810,7 @@ dnl specific modules against it | |||
| PKG_CHECK_MODULES(PIXMAN, $LIBPIXMAN) | ||||
| REQUIRED_LIBS="$REQUIRED_LIBS $LIBPIXMAN $LIBXFONT xau" | ||||
| 
 | ||||
| REQUIRED_MODULES="[fixesproto >= 4.1] [damageproto >= 1.1] [xcmiscproto >= 1.2.0] [xtrans >= 1.2.2] [bigreqsproto >= 1.1.0] $SDK_REQUIRED_MODULES" | ||||
| REQUIRED_MODULES="[fixesproto >= 5.0] [damageproto >= 1.1] [xcmiscproto >= 1.2.0] [xtrans >= 1.2.2] [bigreqsproto >= 1.1.0] $SDK_REQUIRED_MODULES" | ||||
| 
 | ||||
| if test "x$CONFIG_UDEV" = xyes && | ||||
|  { test "x$CONFIG_DBUS_API" = xyes || test "x$CONFIG_HAL" = xyes; }; then | ||||
|  |  | |||
|  | @ -122,7 +122,7 @@ | |||
| #define SERVER_XF86VIDMODE_MINOR_VERSION	2 | ||||
| 
 | ||||
| /* Fixes */ | ||||
| #define SERVER_XFIXES_MAJOR_VERSION		4 | ||||
| #define SERVER_XFIXES_MAJOR_VERSION		5 | ||||
| #define SERVER_XFIXES_MINOR_VERSION		0 | ||||
| 
 | ||||
| /* X Input */ | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| if ENABLE_UNIT_TESTS | ||||
| if HAVE_LD_WRAP | ||||
| SUBDIRS= . xi2 | ||||
| noinst_PROGRAMS = xkb input xtest list misc | ||||
| noinst_PROGRAMS = xkb input xtest list misc fixes | ||||
| check_LTLIBRARIES = libxservertest.la | ||||
| 
 | ||||
| TESTS=$(noinst_PROGRAMS) | ||||
|  | @ -19,6 +19,7 @@ input_LDADD=$(TEST_LDADD) | |||
| xtest_LDADD=$(TEST_LDADD) | ||||
| list_LDADD=$(TEST_LDADD) | ||||
| misc_LDADD=$(TEST_LDADD) | ||||
| fixes_LDADD=$(TEST_LDADD) | ||||
| 
 | ||||
| libxservertest_la_LIBADD = \
 | ||||
|             $(XSERVER_LIBS) \
 | ||||
|  |  | |||
|  | @ -0,0 +1,327 @@ | |||
| /**
 | ||||
|  * Copyright © 2011 Red Hat, Inc. | ||||
|  * | ||||
|  *  Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  *  copy of this software and associated documentation files (the "Software"), | ||||
|  *  to deal in the Software without restriction, including without limitation | ||||
|  *  the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  *  and/or sell copies of the Software, and to permit persons to whom the | ||||
|  *  Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  *  The above copyright notice and this permission notice (including the next | ||||
|  *  paragraph) shall be included in all copies or substantial portions of the | ||||
|  *  Software. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | ||||
|  *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
|  *  DEALINGS IN THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #ifdef HAVE_DIX_CONFIG_H | ||||
| #include <dix-config.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <X11/X.h> | ||||
| #include <xfixesint.h> | ||||
| #include <X11/extensions/xfixeswire.h> | ||||
| 
 | ||||
| static void | ||||
| _fixes_test_direction(struct PointerBarrier *barrier, int d[4], int permitted) | ||||
| { | ||||
|     BOOL blocking; | ||||
|     int i, j; | ||||
|     int dir = barrier_get_direction(d[0], d[1], d[2], d[3]); | ||||
| 
 | ||||
|     barrier->directions = 0; | ||||
|     blocking = barrier_is_blocking_direction(barrier, dir); | ||||
|     assert(blocking); | ||||
| 
 | ||||
|     for (j = 0; j <= BarrierNegativeY; j++) | ||||
|     { | ||||
|         for (i = 0; i <= BarrierNegativeY; i++) | ||||
|         { | ||||
|             barrier->directions |= 1 << i; | ||||
|             blocking = barrier_is_blocking_direction(barrier, dir); | ||||
|             assert((barrier->directions & permitted) == permitted ? !blocking : blocking); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| fixes_pointer_barrier_direction_test(void) | ||||
| { | ||||
|     struct PointerBarrier barrier; | ||||
| 
 | ||||
|     int x = 100; | ||||
|     int y = 100; | ||||
| 
 | ||||
|     int directions[8][4] = { | ||||
|         { x, y, x, y + 100},            /* S  */ | ||||
|         { x + 50, y, x - 50, y + 100},  /* SW */ | ||||
|         { x + 100, y, x, y},            /* W  */ | ||||
|         { x + 100, y + 50, x, y - 50},  /* NW */ | ||||
|         { x, y + 100, x, y},            /* N  */ | ||||
|         { x - 50, y + 100, x + 50, y},  /* NE */ | ||||
|         { x, y, x + 100, y},            /* E  */ | ||||
|         { x, y - 50, x + 100, y + 50},  /* SE */ | ||||
|     }; | ||||
| 
 | ||||
|     barrier.x1 = x; | ||||
|     barrier.x2 = x; | ||||
|     barrier.y1 = y - 50; | ||||
|     barrier.y2 = y + 49; | ||||
| 
 | ||||
| 
 | ||||
|     _fixes_test_direction(&barrier, directions[0], BarrierPositiveY); | ||||
|     _fixes_test_direction(&barrier, directions[1], BarrierPositiveY | BarrierNegativeX); | ||||
|     _fixes_test_direction(&barrier, directions[2], BarrierNegativeX); | ||||
|     _fixes_test_direction(&barrier, directions[3], BarrierNegativeY | BarrierNegativeX); | ||||
|     _fixes_test_direction(&barrier, directions[4], BarrierNegativeY); | ||||
|     _fixes_test_direction(&barrier, directions[5], BarrierPositiveX | BarrierNegativeY); | ||||
|     _fixes_test_direction(&barrier, directions[6], BarrierPositiveX); | ||||
|     _fixes_test_direction(&barrier, directions[7], BarrierPositiveY | BarrierPositiveX); | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void | ||||
| fixes_pointer_barriers_test(void) | ||||
| { | ||||
|     struct PointerBarrier barrier; | ||||
|     int x1, y1, x2, y2; | ||||
|     double distance; | ||||
| 
 | ||||
|     int x = 100; | ||||
|     int y = 100; | ||||
| 
 | ||||
|     /* vert barrier */ | ||||
|     barrier.x1 = x; | ||||
|     barrier.x2 = x; | ||||
|     barrier.y1 = y - 50; | ||||
|     barrier.y2 = y + 50; | ||||
| 
 | ||||
|     /* across at half-way */ | ||||
|     x1 = x + 1; | ||||
|     x2 = x - 1; | ||||
|     y1 = y; | ||||
|     y2 = y; | ||||
|     assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
|     assert(distance == 1); | ||||
| 
 | ||||
|     /* definitely not across */ | ||||
|     x1 = x + 10; | ||||
|     x2 = x + 5; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* across, but outside of y range */ | ||||
|     x1 = x + 1; | ||||
|     x2 = x -1; | ||||
|     y1 = y + 100; | ||||
|     y2 = y + 100; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* across, diagonally */ | ||||
|     x1 = x + 5; | ||||
|     x2 = x - 5; | ||||
|     y1 = y + 5; | ||||
|     y2 = y - 5; | ||||
|     assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* across but outside boundary, diagonally */ | ||||
|     x1 = x + 5; | ||||
|     x2 = x - 5; | ||||
|     y1 = y + 100; | ||||
|     y2 = y + 50; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* edge case: startpoint of movement on barrier → blocking */ | ||||
|     x1 = x; | ||||
|     x2 = x - 1; | ||||
|     y1 = y; | ||||
|     y2 = y; | ||||
|     assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* edge case: startpoint of movement on barrier → not blocking, positive */ | ||||
|     x1 = x; | ||||
|     x2 = x + 1; | ||||
|     y1 = y; | ||||
|     y2 = y; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* edge case: startpoint of movement on barrier → not blocking, negative */ | ||||
|     x1 = x - 1; | ||||
|     x2 = x - 2; | ||||
|     y1 = y; | ||||
|     y2 = y; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* edge case: endpoint of movement on barrier → blocking */ | ||||
|     x1 = x + 1; | ||||
|     x2 = x; | ||||
|     y1 = y; | ||||
|     y2 = y; | ||||
|     assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* startpoint on barrier but outside y range */ | ||||
|     x1 = x; | ||||
|     x2 = x - 1; | ||||
|     y1 = y + 100; | ||||
|     y2 = y + 100; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* endpoint on barrier but outside y range */ | ||||
|     x1 = x + 1; | ||||
|     x2 = x; | ||||
|     y1 = y + 100; | ||||
|     y2 = y + 100; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
| 
 | ||||
|     /* horizontal barrier */ | ||||
|     barrier.x1 = x - 50; | ||||
|     barrier.x2 = x + 50; | ||||
|     barrier.y1 = y; | ||||
|     barrier.y2 = y; | ||||
| 
 | ||||
|     /* across at half-way */ | ||||
|     x1 = x; | ||||
|     x2 = x; | ||||
|     y1 = y - 1; | ||||
|     y2 = y + 1; | ||||
|     assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* definitely not across */ | ||||
|     y1 = y + 10; | ||||
|     y2 = y + 5; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* across, but outside of y range */ | ||||
|     x1 = x + 100; | ||||
|     x2 = x + 100; | ||||
|     y1 = y + 1; | ||||
|     y2 = y -1; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* across, diagonally */ | ||||
|     y1 = y + 5; | ||||
|     y2 = y - 5; | ||||
|     x1 = x + 5; | ||||
|     x2 = x - 5; | ||||
|     assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* across but outside boundary, diagonally */ | ||||
|     y1 = y + 5; | ||||
|     y2 = y - 5; | ||||
|     x1 = x + 100; | ||||
|     x2 = x + 50; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* edge case: startpoint of movement on barrier → blocking */ | ||||
|     y1 = y; | ||||
|     y2 = y - 1; | ||||
|     x1 = x; | ||||
|     x2 = x; | ||||
|     assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* edge case: startpoint of movement on barrier → not blocking, positive */ | ||||
|     y1 = y; | ||||
|     y2 = y + 1; | ||||
|     x1 = x; | ||||
|     x2 = x; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* edge case: startpoint of movement on barrier → not blocking, negative */ | ||||
|     y1 = y - 1; | ||||
|     y2 = y - 2; | ||||
|     x1 = x; | ||||
|     x2 = x; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* edge case: endpoint of movement on barrier → blocking */ | ||||
|     y1 = y + 1; | ||||
|     y2 = y; | ||||
|     x1 = x; | ||||
|     x2 = x; | ||||
|     assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* startpoint on barrier but outside y range */ | ||||
|     y1 = y; | ||||
|     y2 = y - 1; | ||||
|     x1 = x + 100; | ||||
|     x2 = x + 100; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
|     /* endpoint on barrier but outside y range */ | ||||
|     y1 = y + 1; | ||||
|     y2 = y; | ||||
|     x1 = x + 100; | ||||
|     x2 = x + 100; | ||||
|     assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static void fixes_pointer_barrier_clamp_test(void) | ||||
| { | ||||
|     struct PointerBarrier barrier; | ||||
| 
 | ||||
|     int x = 100; | ||||
|     int y = 100; | ||||
| 
 | ||||
|     int cx, cy; /* clamped */ | ||||
| 
 | ||||
|     /* vert barrier */ | ||||
|     barrier.x1 = x; | ||||
|     barrier.x2 = x; | ||||
|     barrier.y1 = y - 50; | ||||
|     barrier.y2 = y + 49; | ||||
|     barrier.directions = 0; | ||||
| 
 | ||||
|     cx = INT_MAX; | ||||
|     cy = INT_MAX; | ||||
|     barrier_clamp_to_barrier(&barrier, BarrierPositiveX, &cx, &cy); | ||||
|     assert(cx == barrier.x1 - 1); | ||||
|     assert(cy == INT_MAX); | ||||
| 
 | ||||
|     cx = 0; | ||||
|     cy = INT_MAX; | ||||
|     barrier_clamp_to_barrier(&barrier, BarrierNegativeX, &cx, &cy); | ||||
|     assert(cx == barrier.x1); | ||||
|     assert(cy == INT_MAX); | ||||
| 
 | ||||
|     /* horiz barrier */ | ||||
|     barrier.x1 = x - 50; | ||||
|     barrier.x2 = x + 49; | ||||
|     barrier.y1 = y; | ||||
|     barrier.y2 = y; | ||||
|     barrier.directions = 0; | ||||
| 
 | ||||
|     cx = INT_MAX; | ||||
|     cy = INT_MAX; | ||||
|     barrier_clamp_to_barrier(&barrier, BarrierPositiveY, &cx, &cy); | ||||
|     assert(cx == INT_MAX); | ||||
|     assert(cy == barrier.y1 - 1); | ||||
| 
 | ||||
|     cx = INT_MAX; | ||||
|     cy = 0; | ||||
|     barrier_clamp_to_barrier(&barrier, BarrierNegativeY, &cx, &cy); | ||||
|     assert(cx == INT_MAX); | ||||
|     assert(cy == barrier.y1); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 
 | ||||
|     fixes_pointer_barriers_test(); | ||||
|     fixes_pointer_barrier_direction_test(); | ||||
|     fixes_pointer_barrier_clamp_test(); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										399
									
								
								xfixes/cursor.c
								
								
								
								
							
							
						
						
									
										399
									
								
								xfixes/cursor.c
								
								
								
								
							|  | @ -1,5 +1,6 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. | ||||
|  * Copyright 2010 Red Hat, Inc. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  | @ -50,13 +51,16 @@ | |||
| #include "cursorstr.h" | ||||
| #include "dixevents.h" | ||||
| #include "servermd.h" | ||||
| #include "mipointer.h" | ||||
| #include "inputstr.h" | ||||
| #include "windowstr.h" | ||||
| #include "xace.h" | ||||
| #include "list.h" | ||||
| 
 | ||||
| static RESTYPE		CursorClientType; | ||||
| static RESTYPE		CursorHideCountType; | ||||
| static RESTYPE		CursorWindowType; | ||||
| RESTYPE			PointerBarrierType; | ||||
| static CursorPtr	CursorCurrent[MAXDEVICES]; | ||||
| 
 | ||||
| static DevPrivateKeyRec CursorScreenPrivateKeyRec; | ||||
|  | @ -107,6 +111,14 @@ typedef struct _CursorHideCountRec { | |||
|     XID			 resource; | ||||
| } CursorHideCountRec; | ||||
| 
 | ||||
| typedef struct PointerBarrierClient *PointerBarrierClientPtr; | ||||
| 
 | ||||
| struct PointerBarrierClient { | ||||
|     ScreenPtr screen; | ||||
|     struct PointerBarrier barrier; | ||||
|     struct list entry; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Wrap DisplayCursor to catch cursor change events | ||||
|  */ | ||||
|  | @ -114,7 +126,9 @@ typedef struct _CursorHideCountRec { | |||
| typedef struct _CursorScreen { | ||||
|     DisplayCursorProcPtr	DisplayCursor; | ||||
|     CloseScreenProcPtr		CloseScreen; | ||||
|     ConstrainCursorHarderProcPtr ConstrainCursorHarder; | ||||
|     CursorHideCountPtr          pCursorHideCounts; | ||||
|     struct list                 barriers; | ||||
| } CursorScreenRec, *CursorScreenPtr; | ||||
| 
 | ||||
| #define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey)) | ||||
|  | @ -184,9 +198,11 @@ CursorCloseScreen (int index, ScreenPtr pScreen) | |||
|     Bool		ret; | ||||
|     CloseScreenProcPtr	close_proc; | ||||
|     DisplayCursorProcPtr display_proc; | ||||
|     ConstrainCursorHarderProcPtr constrain_proc; | ||||
| 
 | ||||
|     Unwrap (cs, pScreen, CloseScreen, close_proc); | ||||
|     Unwrap (cs, pScreen, DisplayCursor, display_proc); | ||||
|     Unwrap (cs, pScreen, ConstrainCursorHarder, constrain_proc); | ||||
|     deleteCursorHideCountsForScreen(pScreen); | ||||
|     ret = (*pScreen->CloseScreen) (index, pScreen); | ||||
|     free(cs); | ||||
|  | @ -1029,6 +1045,382 @@ CursorFreeWindow (pointer data, XID id) | |||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| static BOOL | ||||
| barrier_is_horizontal(const struct PointerBarrier *barrier) | ||||
| { | ||||
|     return barrier->y1 == barrier->y2; | ||||
| } | ||||
| 
 | ||||
| static BOOL | ||||
| barrier_is_vertical(const struct PointerBarrier *barrier) | ||||
| { | ||||
|     return barrier->x1 == barrier->x2; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @return The set of barrier movement directions the movement vector | ||||
|  * x1/y1 → x2/y2 represents. | ||||
|  */ | ||||
| int | ||||
| barrier_get_direction(int x1, int y1, int x2, int y2) | ||||
| { | ||||
|     int direction = 0; | ||||
| 
 | ||||
|     /* which way are we trying to go */ | ||||
|     if (x2 > x1) | ||||
| 	direction |= BarrierPositiveX; | ||||
|     if (x2 < x1) | ||||
| 	direction |= BarrierNegativeX; | ||||
|     if (y2 > y1) | ||||
| 	direction |= BarrierPositiveY; | ||||
|     if (y2 < y1) | ||||
| 	direction |= BarrierNegativeY; | ||||
| 
 | ||||
|     return direction; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Test if the barrier may block movement in the direction defined by | ||||
|  * x1/y1 → x2/y2. This function only tests whether the directions could be | ||||
|  * blocked, it does not test if the barrier actually blocks the movement. | ||||
|  * | ||||
|  * @return TRUE if the barrier blocks the direction of movement or FALSE | ||||
|  * otherwise. | ||||
|  */ | ||||
| BOOL | ||||
| barrier_is_blocking_direction(const struct PointerBarrier *barrier, int direction) | ||||
| { | ||||
|     /* Barriers define which way is ok, not which way is blocking */ | ||||
|     return (barrier->directions & direction) != direction; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Test if the movement vector x1/y1 → x2/y2 is intersecting with the | ||||
|  * barrier. A movement vector with the startpoint or endpoint adjacent to | ||||
|  * the barrier itself counts as intersecting. | ||||
|  * | ||||
|  * @param x1 X start coordinate of movement vector | ||||
|  * @param y1 Y start coordinate of movement vector | ||||
|  * @param x2 X end coordinate of movement vector | ||||
|  * @param y2 Y end coordinate of movement vector | ||||
|  * @param[out] distance The distance between the start point and the | ||||
|  * intersection with the barrier (if applicable). | ||||
|  * @return TRUE if the barrier intersects with the given vector | ||||
|  */ | ||||
| BOOL | ||||
| barrier_is_blocking(const struct PointerBarrier *barrier, | ||||
| 		    int x1, int y1, int x2, int y2, | ||||
| 		    double *distance) | ||||
| { | ||||
|     BOOL rc = FALSE; | ||||
|     float ua, ub, ud; | ||||
|     int dir = barrier_get_direction(x1, y1, x2, y2); | ||||
| 
 | ||||
|     /* Algorithm below doesn't handle edge cases well, hence the extra
 | ||||
|      * checks. */ | ||||
|     if (barrier_is_vertical(barrier)) { | ||||
| 	/* handle immediate barrier adjacency, moving away */ | ||||
| 	if (dir & BarrierPositiveX && x1 == barrier->x1) | ||||
| 	    return FALSE; | ||||
| 	if (dir & BarrierNegativeX && x1 == (barrier->x1 - 1)) | ||||
| 	    return FALSE; | ||||
| 	/* startpoint adjacent to barrier, moving towards -> block */ | ||||
| 	if (x1 == barrier->x1 && y1 >= barrier->y1 && y1 <= barrier->y2) { | ||||
| 	    *distance = 0; | ||||
| 	    return TRUE; | ||||
| 	} | ||||
|     } else { | ||||
| 	/* handle immediate barrier adjacency, moving away */ | ||||
| 	if (dir & BarrierPositiveY && y1 == barrier->y1) | ||||
| 	    return FALSE; | ||||
| 	if (dir & BarrierNegativeY && y1 == (barrier->y1 - 1)) | ||||
| 	    return FALSE; | ||||
| 	/* startpoint adjacent to barrier, moving towards -> block */ | ||||
| 	if (y1 == barrier->y1 && x1 >= barrier->x1 && x1 <= barrier->x2) { | ||||
| 	    *distance = 0; | ||||
| 	    return TRUE; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* not an edge case, compute distance */ | ||||
|     ua = 0; | ||||
|     ud = (barrier->y2 - barrier->y1) * (x2 - x1) - (barrier->x2 - barrier->x1) * (y2 - y1); | ||||
|     if (ud != 0) { | ||||
| 	ua = ((barrier->x2 - barrier->x1) * (y1 - barrier->y1) - | ||||
| 	     (barrier->y2 - barrier->y1) * (x1 - barrier->x1)) / ud; | ||||
| 	ub = ((x2 - x1) * (y1 - barrier->y1) - | ||||
| 	     (y2 - y1) * (x1 - barrier->x1)) / ud; | ||||
| 	if (ua < 0 || ua > 1 || ub < 0 || ub > 1) | ||||
| 	    ua = 0; | ||||
|     } | ||||
| 
 | ||||
|     if (ua > 0 && ua <= 1) | ||||
|     { | ||||
| 	double ix = barrier->x1 + ua * (barrier->x2 - barrier->x1); | ||||
| 	double iy = barrier->y1 + ua * (barrier->y2 - barrier->y1); | ||||
| 
 | ||||
| 	*distance = sqrt(pow(x1 - ix, 2) + pow(y1 - iy, 2)); | ||||
| 	rc = TRUE; | ||||
|     } | ||||
| 
 | ||||
|     return rc; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Find the nearest barrier that is blocking movement from x1/y1 to x2/y2. | ||||
|  * | ||||
|  * @param dir Only barriers blocking movement in direction dir are checked | ||||
|  * @param x1 X start coordinate of movement vector | ||||
|  * @param y1 Y start coordinate of movement vector | ||||
|  * @param x2 X end coordinate of movement vector | ||||
|  * @param y2 Y end coordinate of movement vector | ||||
|  * @return The barrier nearest to the movement origin that blocks this movement. | ||||
|  */ | ||||
| static struct PointerBarrier* | ||||
| barrier_find_nearest(CursorScreenPtr cs, int dir, | ||||
| 		     int x1, int y1, int x2, int y2) | ||||
| { | ||||
|     struct PointerBarrierClient *c; | ||||
|     struct PointerBarrier *nearest = NULL; | ||||
|     double min_distance = INT_MAX; /* can't get higher than that in X anyway */ | ||||
| 
 | ||||
|     list_for_each_entry(c, &cs->barriers, entry) { | ||||
| 	struct PointerBarrier *b = &c->barrier; | ||||
| 	double distance; | ||||
| 
 | ||||
| 	if (!barrier_is_blocking_direction(b, dir)) | ||||
| 	    continue; | ||||
| 
 | ||||
| 	if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) | ||||
| 	{ | ||||
| 	    if (min_distance > distance) | ||||
| 	    { | ||||
| 		min_distance = distance; | ||||
| 		nearest = b; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|     return nearest; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Clamp to the given barrier given the movement direction specified in dir. | ||||
|  * | ||||
|  * @param barrier The barrier to clamp to | ||||
|  * @param dir The movement direction | ||||
|  * @param[out] x The clamped x coordinate. | ||||
|  * @param[out] y The clamped x coordinate. | ||||
|  */ | ||||
| void | ||||
| barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, int *y) | ||||
| { | ||||
|     if (barrier_is_vertical(barrier)) | ||||
|     { | ||||
| 	if ((dir & BarrierNegativeX) & ~barrier->directions) | ||||
| 	    *x = barrier->x1; | ||||
| 	if ((dir & BarrierPositiveX) & ~barrier->directions) | ||||
| 	    *x = barrier->x1 - 1; | ||||
|     } | ||||
|     if (barrier_is_horizontal(barrier)) | ||||
|     { | ||||
| 	if ((dir & BarrierNegativeY) & ~barrier->directions) | ||||
| 	    *y = barrier->y1; | ||||
| 	if ((dir & BarrierPositiveY) & ~barrier->directions) | ||||
| 	    *y = barrier->y1 - 1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| CursorConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, int *x, int *y) | ||||
| { | ||||
|     CursorScreenPtr cs = GetCursorScreen(screen); | ||||
| 
 | ||||
|     if (!list_is_empty(&cs->barriers) && !IsFloating(dev) && mode == Relative) { | ||||
| 	int ox, oy; | ||||
| 	int dir; | ||||
| 	struct PointerBarrier *nearest = NULL; | ||||
| 
 | ||||
| 	/* where are we coming from */ | ||||
| 	miPointerGetPosition(dev, &ox, &oy); | ||||
| 
 | ||||
| 	/* How this works:
 | ||||
| 	 * Given the origin and the movement vector, get the nearest barrier | ||||
| 	 * to the origin that is blocking the movement. | ||||
| 	 * Clamp to that barrier. | ||||
| 	 * Then, check from the clamped intersection to the original | ||||
| 	 * destination, again finding the nearest barrier and clamping. | ||||
| 	 */ | ||||
| 	dir = barrier_get_direction(ox, oy, *x, *y); | ||||
| 
 | ||||
| 	nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y); | ||||
| 	if (nearest) { | ||||
| 	    barrier_clamp_to_barrier(nearest, dir, x, y); | ||||
| 
 | ||||
| 	    if (barrier_is_vertical(nearest)) { | ||||
| 		dir &= ~(BarrierNegativeX | BarrierPositiveX); | ||||
| 		ox = *x; | ||||
| 	    } else if (barrier_is_horizontal(nearest)) { | ||||
| 		dir &= ~(BarrierNegativeY | BarrierPositiveY); | ||||
| 		oy = *y; | ||||
| 	    } | ||||
| 
 | ||||
| 	    nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y); | ||||
| 	    if (nearest) { | ||||
| 		barrier_clamp_to_barrier(nearest, dir, x, y); | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|     if (cs->ConstrainCursorHarder) { | ||||
| 	screen->ConstrainCursorHarder = cs->ConstrainCursorHarder; | ||||
| 	screen->ConstrainCursorHarder(dev, screen, mode, x, y); | ||||
| 	screen->ConstrainCursorHarder = CursorConstrainCursorHarder; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static struct PointerBarrierClient * | ||||
| CreatePointerBarrierClient(ScreenPtr screen, ClientPtr client, | ||||
| 			   xXFixesCreatePointerBarrierReq *stuff) | ||||
| { | ||||
|     CursorScreenPtr cs = GetCursorScreen(screen); | ||||
|     struct PointerBarrierClient *ret = malloc(sizeof(*ret)); | ||||
| 
 | ||||
|     if (ret) { | ||||
| 	ret->screen = screen; | ||||
| 	ret->barrier.x1 = min(stuff->x1, stuff->x2); | ||||
| 	ret->barrier.x2 = max(stuff->x1, stuff->x2); | ||||
| 	ret->barrier.y1 = min(stuff->y1, stuff->y2); | ||||
| 	ret->barrier.y2 = max(stuff->y1, stuff->y2); | ||||
| 	ret->barrier.directions = stuff->directions & 0x0f; | ||||
| 	if (barrier_is_horizontal(&ret->barrier)) | ||||
| 	    ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX); | ||||
| 	if (barrier_is_vertical(&ret->barrier)) | ||||
| 	    ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY); | ||||
| 	list_add(&ret->entry, &cs->barriers); | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| ProcXFixesCreatePointerBarrier (ClientPtr client) | ||||
| { | ||||
|     int err; | ||||
|     WindowPtr pWin; | ||||
|     struct PointerBarrierClient *barrier; | ||||
|     struct PointerBarrier b; | ||||
|     REQUEST (xXFixesCreatePointerBarrierReq); | ||||
| 
 | ||||
|     REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq); | ||||
|     LEGAL_NEW_RESOURCE(stuff->barrier, client); | ||||
| 
 | ||||
|     err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); | ||||
|     if (err != Success) { | ||||
| 	client->errorValue = stuff->window; | ||||
| 	return err; | ||||
|     } | ||||
| 
 | ||||
|     /* This sure does need fixing. */ | ||||
|     if (stuff->num_devices) | ||||
| 	return BadImplementation; | ||||
| 
 | ||||
|     b.x1 = stuff->x1; | ||||
|     b.x2 = stuff->x2; | ||||
|     b.y1 = stuff->y1; | ||||
|     b.y2 = stuff->y2; | ||||
| 
 | ||||
|     if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b)) | ||||
| 	return BadValue; | ||||
| 
 | ||||
|     /* no 0-sized barriers */ | ||||
|     if (barrier_is_horizontal(&b) && barrier_is_vertical(&b)) | ||||
| 	return BadValue; | ||||
| 
 | ||||
|     if (!(barrier = CreatePointerBarrierClient(pWin->drawable.pScreen, | ||||
| 					       client, stuff))) | ||||
| 	return BadAlloc; | ||||
| 
 | ||||
|     if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier)) | ||||
| 	return BadAlloc; | ||||
| 
 | ||||
|     return Success; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| SProcXFixesCreatePointerBarrier (ClientPtr client) | ||||
| { | ||||
|     int n; | ||||
|     REQUEST(xXFixesCreatePointerBarrierReq); | ||||
| 
 | ||||
|     swaps(&stuff->length, n); | ||||
|     REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq); | ||||
|     swapl(&stuff->barrier, n); | ||||
|     swapl(&stuff->window, n); | ||||
|     swaps(&stuff->x1, n); | ||||
|     swaps(&stuff->y1, n); | ||||
|     swaps(&stuff->x2, n); | ||||
|     swaps(&stuff->y2, n); | ||||
|     swapl(&stuff->directions, n); | ||||
|     return ProcXFixesVector[stuff->xfixesReqType](client); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| CursorFreeBarrier(void *data, XID id) | ||||
| { | ||||
|     struct PointerBarrierClient *b = NULL, *barrier; | ||||
|     ScreenPtr screen; | ||||
|     CursorScreenPtr cs; | ||||
| 
 | ||||
|     barrier = container_of(data, struct PointerBarrierClient, barrier); | ||||
|     screen = barrier->screen; | ||||
|     cs = GetCursorScreen(screen); | ||||
| 
 | ||||
|     /* find and unlink from the screen private */ | ||||
|     list_for_each_entry(b, &cs->barriers, entry) { | ||||
| 	if (b == barrier) { | ||||
| 	    list_del(&b->entry); | ||||
| 	    break; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|     free(barrier); | ||||
|     return Success; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| ProcXFixesDestroyPointerBarrier (ClientPtr client) | ||||
| { | ||||
|     int err; | ||||
|     void *barrier; | ||||
|     REQUEST (xXFixesDestroyPointerBarrierReq); | ||||
| 
 | ||||
|     REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); | ||||
| 
 | ||||
|     err = dixLookupResourceByType((void **)&barrier, stuff->barrier, | ||||
| 				  PointerBarrierType, client, | ||||
| 				  DixDestroyAccess); | ||||
|     if (err != Success) { | ||||
| 	client->errorValue = stuff->barrier; | ||||
| 	return err; | ||||
|     } | ||||
| 
 | ||||
|     FreeResource(stuff->barrier, RT_NONE); | ||||
|     return Success; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| SProcXFixesDestroyPointerBarrier (ClientPtr client) | ||||
| { | ||||
|     int n; | ||||
|     REQUEST(xXFixesDestroyPointerBarrierReq); | ||||
| 
 | ||||
|     swaps(&stuff->length, n); | ||||
|     REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); | ||||
|     swapl(&stuff->barrier, n); | ||||
|     return ProcXFixesVector[stuff->xfixesReqType](client); | ||||
| } | ||||
| 
 | ||||
| Bool | ||||
| XFixesCursorInit (void) | ||||
| { | ||||
|  | @ -1048,8 +1440,10 @@ XFixesCursorInit (void) | |||
| 	cs = (CursorScreenPtr) calloc(1, sizeof (CursorScreenRec)); | ||||
| 	if (!cs) | ||||
| 	    return FALSE; | ||||
| 	list_init(&cs->barriers); | ||||
| 	Wrap (cs, pScreen, CloseScreen, CursorCloseScreen); | ||||
| 	Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor); | ||||
| 	Wrap (cs, pScreen, ConstrainCursorHarder, CursorConstrainCursorHarder); | ||||
| 	cs->pCursorHideCounts = NULL; | ||||
| 	SetCursorScreen (pScreen, cs); | ||||
|     } | ||||
|  | @ -1059,7 +1453,10 @@ XFixesCursorInit (void) | |||
| 						"XFixesCursorHideCount"); | ||||
|     CursorWindowType = CreateNewResourceType(CursorFreeWindow, | ||||
| 					     "XFixesCursorWindow"); | ||||
|     PointerBarrierType = CreateNewResourceType(CursorFreeBarrier, | ||||
| 					      "XFixesPointerBarrier"); | ||||
| 
 | ||||
|     return CursorClientType && CursorHideCountType && CursorWindowType; | ||||
|     return CursorClientType && CursorHideCountType && CursorWindowType && | ||||
| 	   PointerBarrierType; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. | ||||
|  * Copyright 2010 Red Hat, Inc. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  | @ -47,10 +48,6 @@ | |||
| 
 | ||||
| #include "xfixesint.h" | ||||
| #include "protocol-versions.h" | ||||
| /*
 | ||||
|  * Must use these instead of the constants from xfixeswire.h.  They advertise | ||||
|  * what we implement, not what the protocol headers define. | ||||
|  */ | ||||
| 
 | ||||
| static unsigned char	XFixesReqCode; | ||||
| int		XFixesEventBase; | ||||
|  | @ -102,6 +99,7 @@ static const int version_requests[] = { | |||
|     X_XFixesChangeCursorByName,	    /* Version 2 */ | ||||
|     X_XFixesExpandRegion,	    /* Version 3 */ | ||||
|     X_XFixesShowCursor,		    /* Version 4 */ | ||||
|     X_XFixesDestroyPointerBarrier,  /* Version 5 */ | ||||
| }; | ||||
| 
 | ||||
| #define NUM_VERSION_REQUESTS	(sizeof (version_requests) / sizeof (version_requests[0])) | ||||
|  | @ -142,6 +140,9 @@ int	(*ProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { | |||
| /*************** Version 4 ****************/ | ||||
|     ProcXFixesHideCursor, | ||||
|     ProcXFixesShowCursor, | ||||
| /*************** Version 5 ****************/ | ||||
|     ProcXFixesCreatePointerBarrier, | ||||
|     ProcXFixesDestroyPointerBarrier, | ||||
| }; | ||||
| 
 | ||||
| static int | ||||
|  | @ -205,6 +206,9 @@ static int (*SProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { | |||
| /*************** Version 4 ****************/ | ||||
|     SProcXFixesHideCursor, | ||||
|     SProcXFixesShowCursor, | ||||
| /*************** Version 5 ****************/ | ||||
|     SProcXFixesCreatePointerBarrier, | ||||
|     SProcXFixesDestroyPointerBarrier, | ||||
| }; | ||||
| 
 | ||||
| static int | ||||
|  | @ -260,6 +264,8 @@ XFixesExtensionInit(void) | |||
| 	EventSwapVector[XFixesEventBase + XFixesCursorNotify] = | ||||
| 	    (EventSwapPtr) SXFixesCursorNotifyEvent; | ||||
| 	SetResourceTypeErrorValue(RegionResType, XFixesErrorBase + BadRegion); | ||||
| 	SetResourceTypeErrorValue(PointerBarrierType, | ||||
| 				  XFixesErrorBase + BadBarrier); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ | |||
| #include "resource.h" | ||||
| 
 | ||||
| extern _X_EXPORT RESTYPE RegionResType; | ||||
| extern _X_EXPORT RESTYPE PointerBarrierType; | ||||
| extern _X_EXPORT int XFixesErrorBase; | ||||
| 
 | ||||
| #define VERIFY_REGION(pRegion, rid, client, mode)			\ | ||||
|  | @ -51,5 +52,21 @@ extern _X_EXPORT int XFixesErrorBase; | |||
| extern _X_EXPORT RegionPtr | ||||
| XFixesRegionCopy (RegionPtr pRegion); | ||||
| 
 | ||||
| struct PointerBarrier { | ||||
|     CARD16 x1, x2, y1, y2; | ||||
|     CARD32 directions; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| extern int | ||||
| barrier_get_direction(int, int, int, int); | ||||
| extern BOOL | ||||
| barrier_is_blocking(const struct PointerBarrier*, int, int, int, int, double*); | ||||
| extern BOOL | ||||
| barrier_is_blocking_direction(const struct PointerBarrier*, int); | ||||
| extern void | ||||
| barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, int *y); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif /* _XFIXES_H_ */ | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. | ||||
|  * Copyright 2010 Red Hat, Inc. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  | @ -278,6 +279,21 @@ ProcXFixesShowCursor (ClientPtr client); | |||
| int  | ||||
| SProcXFixesShowCursor (ClientPtr client); | ||||
| 
 | ||||
| /* Version 5 */ | ||||
| 
 | ||||
| int | ||||
| ProcXFixesCreatePointerBarrier (ClientPtr client); | ||||
| 
 | ||||
| int | ||||
| SProcXFixesCreatePointerBarrier (ClientPtr client); | ||||
| 
 | ||||
| int | ||||
| ProcXFixesDestroyPointerBarrier (ClientPtr client); | ||||
| 
 | ||||
| int | ||||
| SProcXFixesDestroyPointerBarrier (ClientPtr client); | ||||
| 
 | ||||
| /* Xinerama */ | ||||
| extern int (*PanoramiXSaveXFixesVector[XFixesNumberRequests])(ClientPtr); | ||||
| void PanoramiXFixesInit (void); | ||||
| void PanoramiXFixesReset (void); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue