2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation on the rights to use, copy, modify, merge,
10 * publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * David H. Dawes <dawes@xfree86.org>
31 * Kevin E. Martin <kem@redhat.com>
32 * Rickard E. (Rik) Faith <faith@redhat.com>
37 * This file contains code than supports cursor movement, including the
38 * code that initializes and reinitializes the screen positions and
39 * computes screen overlap.
41 * "This code is based very closely on the XFree86 equivalent
42 * (xfree86/common/xf86Cursor.c)." --David Dawes.
44 * "This code was then extensively re-written, as explained here."
47 * The code in xf86Cursor.c used edge lists to implement the
48 * CursorOffScreen function. The edge list computation was complex
49 * (especially in the face of arbitrarily overlapping screens) compared
50 * with the speed savings in the CursorOffScreen function. The new
51 * implementation has erred on the side of correctness, readability, and
52 * maintainability over efficiency. For the common (non-edge) case, the
53 * dmxCursorOffScreen function does avoid a loop over all the screens.
54 * When the cursor has left the screen, all the screens are searched,
55 * and the first screen (in dmxScreens order) containing the cursor will
56 * be returned. If run-time profiling shows that this routing is a
57 * performance bottle-neck, then an edge list may have to be
58 * reimplemented. An edge list algorithm is O(edges) whereas the new
59 * algorithm is O(dmxNumScreens). Since edges is usually 1-3 and
60 * dmxNumScreens may be 30-60 for large backend walls, this trade off
63 * The xf86InitOrigins routine uses bit masks during the computation and
64 * is therefore limited to the length of a word (e.g., 32 or 64 bits)
65 * screens. Because Xdmx is expected to be used with a large number of
66 * backend displays, this limitation was removed. The new
67 * implementation has erred on the side of readability over efficiency,
68 * using the dmxSL* routines to manage a screen list instead of a
69 * bitmap, and a function call to decrease the length of the main
70 * routine. Both algorithms are of the same order, and both are called
71 * only at server generation time, so trading clarity and long-term
72 * maintainability for efficiency does not seem justified in this case.
75 #ifdef HAVE_DMX_CONFIG_H
76 #include <dmx-config.h>
79 #define DMX_CURSOR_DEBUG 0
83 #include "dmxcursor.h"
88 #include "mipointer.h"
89 #include "windowstr.h"
91 #include "cursorstr.h"
92 #include "dixevents.h" /* For GetSpriteCursor() */
95 #define DMXDBG0(f) dmxLog(dmxDebug,f)
96 #define DMXDBG1(f,a) dmxLog(dmxDebug,f,a)
97 #define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b)
98 #define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
99 #define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d)
100 #define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e)
101 #define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g)
102 #define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
106 #define DMXDBG2(f,a,b)
107 #define DMXDBG3(f,a,b,c)
108 #define DMXDBG4(f,a,b,c,d)
109 #define DMXDBG5(f,a,b,c,d,e)
110 #define DMXDBG6(f,a,b,c,d,e,g)
111 #define DMXDBG7(f,a,b,c,d,e,g,h)
114 static int dmxCursorDoMultiCursors
= 1;
116 /** Turn off support for displaying multiple cursors on overlapped
117 back-end displays. See #dmxCursorDoMultiCursors. */
118 void dmxCursorNoMulti(void)
120 dmxCursorDoMultiCursors
= 0;
123 static Bool
dmxCursorOffScreen(ScreenPtr
*ppScreen
, int *x
, int *y
)
125 DMXScreenInfo
*dmxScreen
;
132 if (screenInfo
.numScreens
== 1)
135 /* On current screen? */
136 dmxScreen
= &dmxScreens
[(*ppScreen
)->myNum
];
138 && localX
< dmxScreen
->rootWidth
140 && localY
< dmxScreen
->rootHeight
)
143 /* Convert to global coordinate space */
144 globalX
= dmxScreen
->rootXOrigin
+ localX
;
145 globalY
= dmxScreen
->rootYOrigin
+ localY
;
147 /* Is cursor on the current screen?
148 * This efficiently exits this routine
149 * for the most common case. */
150 if (ppScreen
&& *ppScreen
) {
151 dmxScreen
= &dmxScreens
[(*ppScreen
)->myNum
];
152 if (globalX
>= dmxScreen
->rootXOrigin
153 && globalX
< dmxScreen
->rootXOrigin
+ dmxScreen
->rootWidth
154 && globalY
>= dmxScreen
->rootYOrigin
155 && globalY
< dmxScreen
->rootYOrigin
+ dmxScreen
->rootHeight
)
159 /* Find first screen cursor is on */
160 for (i
= 0; i
< dmxNumScreens
; i
++) {
161 dmxScreen
= &dmxScreens
[i
];
162 if (globalX
>= dmxScreen
->rootXOrigin
163 && globalX
< dmxScreen
->rootXOrigin
+ dmxScreen
->rootWidth
164 && globalY
>= dmxScreen
->rootYOrigin
165 && globalY
< dmxScreen
->rootYOrigin
+ dmxScreen
->rootHeight
) {
166 if (dmxScreen
->index
== (*ppScreen
)->myNum
)
168 *ppScreen
= screenInfo
.screens
[dmxScreen
->index
];
169 *x
= globalX
- dmxScreen
->rootXOrigin
;
170 *y
= globalY
- dmxScreen
->rootYOrigin
;
177 static void dmxCrossScreen(ScreenPtr pScreen
, Bool entering
)
181 static void dmxWarpCursor(ScreenPtr pScreen
, int x
, int y
)
183 DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen
->myNum
, x
, y
);
185 /* This call is depracated. Replace with???? */
186 miPointerWarpCursor(pScreen
, x
, y
);
188 pScreen
->SetCursorPosition(pScreen
, x
, y
, FALSE
);
192 miPointerScreenFuncRec dmxPointerCursorFuncs
=
197 dmxeqEnqueue
, /*XXX incompatible type/function! */
202 /** Create a list of screens that we'll manipulate. */
203 static int *dmxSLCreate(void)
205 int *list
= malloc(dmxNumScreens
* sizeof(*list
));
208 for (i
= 0; i
< dmxNumScreens
; i
++)
214 static void dmxSLFree(int *list
)
219 /** Find next uninitialized entry in list. */
220 static int dmxSLFindNext(int *list
)
223 for (i
= 0; i
< dmxNumScreens
; i
++)
229 /** Make one pass over all the screens and return the number updated. */
230 static int dmxTryComputeScreenOrigins(int *screensLeft
)
233 DMXScreenInfo
*screen
;
237 for (i
= 0; i
< dmxNumScreens
; i
++) {
240 screen
= &dmxScreens
[i
];
241 switch (screen
->where
) {
243 dixScreenOrigins
[i
].x
= screen
->whereX
;
244 dixScreenOrigins
[i
].y
= screen
->whereY
;
245 ++changed
, screensLeft
[i
] = 0;
248 ref
= screen
->whereRefScreen
;
249 if (screensLeft
[ref
])
251 dixScreenOrigins
[i
].x
= dixScreenOrigins
[ref
].x
+ screen
->whereX
;
252 dixScreenOrigins
[i
].y
= dixScreenOrigins
[ref
].y
+ screen
->whereY
;
253 ++changed
, screensLeft
[i
] = 0;
256 ref
= screen
->whereRefScreen
;
257 if (screensLeft
[ref
])
259 pScreen
= screenInfo
.screens
[ref
];
260 dixScreenOrigins
[i
].x
= dixScreenOrigins
[ref
].x
+ pScreen
->width
;
261 dixScreenOrigins
[i
].y
= dixScreenOrigins
[ref
].y
;
262 ++changed
, screensLeft
[i
] = 0;
265 ref
= screen
->whereRefScreen
;
266 if (screensLeft
[ref
])
268 pScreen
= screenInfo
.screens
[i
];
269 dixScreenOrigins
[i
].x
= dixScreenOrigins
[ref
].x
- pScreen
->width
;
270 dixScreenOrigins
[i
].y
= dixScreenOrigins
[ref
].y
;
271 ++changed
, screensLeft
[i
] = 0;
274 ref
= screen
->whereRefScreen
;
275 if (screensLeft
[ref
])
277 pScreen
= screenInfo
.screens
[ref
];
278 dixScreenOrigins
[i
].x
= dixScreenOrigins
[ref
].x
;
279 dixScreenOrigins
[i
].y
= dixScreenOrigins
[ref
].y
+ pScreen
->height
;
280 ++changed
, screensLeft
[i
] = 0;
283 ref
= screen
->whereRefScreen
;
284 if (screensLeft
[ref
])
286 pScreen
= screenInfo
.screens
[i
];
287 dixScreenOrigins
[i
].x
= dixScreenOrigins
[ref
].x
;
288 dixScreenOrigins
[i
].y
= dixScreenOrigins
[ref
].y
- pScreen
->height
;
289 ++changed
, screensLeft
[i
] = 0;
292 dmxLog(dmxFatal
, "No position information for screen %d\n", i
);
298 static void dmxComputeScreenOrigins(void)
304 /* Compute origins based on
305 * configuration information. */
306 screensLeft
= dmxSLCreate();
307 while ((i
= dmxSLFindNext(screensLeft
)) >= 0) {
308 while (dmxTryComputeScreenOrigins(screensLeft
));
309 if ((i
= dmxSLFindNext(screensLeft
)) >= 0) {
310 /* All of the remaining screens are referencing each other.
311 * Assign a value to one of them and go through again. This
312 * guarantees that we will eventually terminate.
314 ref
= dmxScreens
[i
].whereRefScreen
;
315 dixScreenOrigins
[ref
].x
= dixScreenOrigins
[ref
].y
= 0;
316 screensLeft
[ref
] = 0;
319 dmxSLFree(screensLeft
);
322 /* Justify the topmost and leftmost to
324 minX
= dixScreenOrigins
[0].x
;
325 minY
= dixScreenOrigins
[0].y
;
326 for (i
= 1; i
< dmxNumScreens
; i
++) { /* Compute minX, minY */
327 if (dixScreenOrigins
[i
].x
< minX
)
328 minX
= dixScreenOrigins
[i
].x
;
329 if (dixScreenOrigins
[i
].y
< minY
)
330 minY
= dixScreenOrigins
[i
].y
;
333 for (i
= 0; i
< dmxNumScreens
; i
++) {
334 dixScreenOrigins
[i
].x
-= minX
;
335 dixScreenOrigins
[i
].y
-= minY
;
340 /** Recompute origin information in the #dmxScreens list. This is
341 * either called from #dmxInitOrigins() or from #dmxReconfig(). */
342 void dmxReInitOrigins(void)
346 if (dmxNumScreens
> MAXSCREENS
)
347 dmxLog(dmxFatal
, "dmxNumScreens = %d > MAXSCREENS = %d\n",
348 dmxNumScreens
, MAXSCREENS
);
350 for (i
= 0; i
< dmxNumScreens
; i
++) {
351 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
352 dmxLogOutput(dmxScreen
,
353 "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d"
354 " (be=%dx%d depth=%d bpp=%d)\n",
355 dmxScreen
->scrnWidth
, dmxScreen
->scrnHeight
,
356 dmxScreen
->scrnX
, dmxScreen
->scrnY
,
358 dmxScreen
->rootWidth
, dmxScreen
->rootHeight
,
359 dmxScreen
->rootX
, dmxScreen
->rootY
,
361 dmxScreen
->rootXOrigin
, dmxScreen
->rootYOrigin
,
362 dmxScreen
->beWidth
, dmxScreen
->beHeight
,
363 dmxScreen
->beDepth
, dmxScreen
->beBPP
);
367 /** Initialize screen origins (and relative position). This is called
368 * for each server generation. For dynamic reconfiguration, use
369 * #dmxReInitOrigins() instead. */
370 void dmxInitOrigins(void)
374 if (dmxNumScreens
> MAXSCREENS
)
375 dmxLog(dmxFatal
, "dmxNumScreens = %d > MAXSCREENS = %d\n",
376 dmxNumScreens
, MAXSCREENS
);
378 for (i
= 0; i
< dmxNumScreens
; i
++) {
379 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
380 dmxLogOutput(dmxScreen
,
381 "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)"
382 " (be=%dx%d depth=%d bpp=%d)\n",
383 dmxScreen
->scrnWidth
, dmxScreen
->scrnHeight
,
384 dmxScreen
->scrnX
, dmxScreen
->scrnY
,
386 dmxScreen
->rootWidth
, dmxScreen
->rootHeight
,
387 dmxScreen
->rootX
, dmxScreen
->rootY
,
389 dmxScreen
->whereX
, dmxScreen
->whereY
,
392 dmxScreen
->beWidth
, dmxScreen
->beHeight
,
393 dmxScreen
->beDepth
, dmxScreen
->beBPP
);
396 dmxComputeScreenOrigins();
398 for (i
= 0; i
< dmxNumScreens
; i
++) {
399 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
400 dmxScreen
->rootXOrigin
= dixScreenOrigins
[i
].x
;
401 dmxScreen
->rootYOrigin
= dixScreenOrigins
[i
].y
;
407 /** Returns non-zero if the global \a x, \a y coordinate is on the
408 * screen window of the \a dmxScreen. */
409 int dmxOnScreen(int x
, int y
, DMXScreenInfo
*dmxScreen
)
411 #if DMX_CURSOR_DEBUG > 1
413 "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n",
414 dmxScreen
->index
, x
, y
,
415 dmxScreen
->rootWidth
, dmxScreen
->rootHeight
,
416 dmxScreen
->rootX
, dmxScreen
->rootY
,
417 dmxScreen
->rootXOrigin
, dmxScreen
->rootYOrigin
,
418 dmxScreen
->scrnWidth
, dmxScreen
->scrnHeight
,
419 dmxScreen
->scrnX
, dmxScreen
->scrnY
);
421 if (x
>= dmxScreen
->rootXOrigin
422 && x
< dmxScreen
->rootXOrigin
+ dmxScreen
->rootWidth
423 && y
>= dmxScreen
->rootYOrigin
424 && y
< dmxScreen
->rootYOrigin
+ dmxScreen
->rootHeight
) return 1;
428 /** Returns non-zero if \a a overlaps \a b. */
429 static int dmxDoesOverlap(DMXScreenInfo
*a
, DMXScreenInfo
*b
)
431 if (dmxOnScreen(a
->rootXOrigin
,
435 if (dmxOnScreen(a
->rootXOrigin
,
436 a
->rootYOrigin
+ a
->scrnWidth
, b
))
439 if (dmxOnScreen(a
->rootXOrigin
+ a
->scrnHeight
,
443 if (dmxOnScreen(a
->rootXOrigin
+ a
->scrnHeight
,
444 a
->rootYOrigin
+ a
->scrnWidth
, b
))
447 if (dmxOnScreen(b
->rootXOrigin
,
451 if (dmxOnScreen(b
->rootXOrigin
,
452 b
->rootYOrigin
+ b
->scrnWidth
, a
))
455 if (dmxOnScreen(b
->rootXOrigin
+ b
->scrnHeight
,
459 if (dmxOnScreen(b
->rootXOrigin
+ b
->scrnHeight
,
460 b
->rootYOrigin
+ b
->scrnWidth
, a
))
466 /** Used with #dmxInterateOverlap to print out a list of screens which
467 * overlap each other. */
468 static void *dmxPrintOverlap(DMXScreenInfo
*dmxScreen
, void *closure
)
470 DMXScreenInfo
*a
= closure
;
471 if (dmxScreen
!= a
) {
472 if (dmxScreen
->cursorNotShared
)
473 dmxLogOutputCont(a
, " [%d/%s]", dmxScreen
->index
, dmxScreen
->name
);
475 dmxLogOutputCont(a
, " %d/%s", dmxScreen
->index
, dmxScreen
->name
);
480 /** Iterate over the screens which overlap with the \a start screen,
481 * calling \a f with the \a closure for each argument. Often used with
482 * #dmxPrintOverlap. */
483 static void *dmxIterateOverlap(DMXScreenInfo
*start
,
484 void *(*f
)(DMXScreenInfo
*dmxScreen
, void *),
489 if (!start
->over
) return f(start
, closure
);
491 for (pt
= start
->over
; /* condition at end of loop */; pt
= pt
->over
) {
493 if ((retval
= f(pt
, closure
))) return retval
;
494 if (pt
== start
) break;
499 /** Used with #dmxPropertyIterate to determine if screen \a a is the
500 * same as the screen \a closure. */
501 static void *dmxTestSameDisplay(DMXScreenInfo
*a
, void *closure
)
503 DMXScreenInfo
*b
= closure
;
510 /** Detects overlapping dmxScreens and creates circular lists. This
511 * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and
512 * the computation only needs to be performed for every server
513 * generation or dynamic reconfiguration . */
514 void dmxInitOverlap(void)
517 DMXScreenInfo
*a
, *b
, *pt
;
519 for (i
= 0; i
< dmxNumScreens
; i
++)
520 dmxScreens
[i
].over
= NULL
;
522 for (i
= 0; i
< dmxNumScreens
; i
++) {
525 for (j
= i
+1; j
< dmxNumScreens
; j
++) {
530 if (dmxDoesOverlap(a
, b
)) {
531 DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n",
532 a
->index
, b
->index
, a
, a
->over
, b
, b
->over
);
533 b
->over
= (a
->over
? a
->over
: a
);
539 for (i
= 0; i
< dmxNumScreens
; i
++) {
545 /* Flag all pairs that are on same display */
546 for (pt
= a
->over
; pt
!= a
; pt
= pt
->over
) {
547 if (dmxPropertyIterate(a
, dmxTestSameDisplay
, pt
)) {
548 /* The ->over sets contain the transitive set of screens
549 * that overlap. For screens that are on the same
550 * backend display, we only want to exclude pairs of
551 * screens that mutually overlap on the backend display,
552 * so we call dmxDoesOverlap, which is stricter than the
554 if (!dmxDoesOverlap(a
, pt
))
556 a
->cursorNotShared
= 1;
557 pt
->cursorNotShared
= 1;
559 "Screen %d and %d overlap on %s\n",
560 a
->index
, pt
->index
, a
->name
);
565 for (i
= 0; i
< dmxNumScreens
; i
++) {
569 dmxLogOutput(a
, "Overlaps");
570 dmxIterateOverlap(a
, dmxPrintOverlap
, a
);
571 dmxLogOutputCont(a
, "\n");
576 /** Create \a pCursor on the back-end associated with \a pScreen. */
577 void dmxBECreateCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
579 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
580 dmxCursorPrivPtr pCursorPriv
= DMX_GET_CURSOR_PRIV(pCursor
, pScreen
);
581 CursorBitsPtr pBits
= pCursor
->bits
;
593 m
= GCFunction
| GCPlaneMask
| GCForeground
| GCBackground
| GCClipMask
;
595 v
.plane_mask
= AllPlanes
;
600 for (i
= 0; i
< dmxScreen
->beNumPixmapFormats
; i
++) {
601 if (dmxScreen
->bePixmapFormats
[i
].depth
== 1) {
602 /* Create GC in the back-end servers */
603 gc
= XCreateGC(dmxScreen
->beDisplay
, dmxScreen
->scrnDefDrawables
[i
],
609 dmxLog(dmxFatal
, "dmxRealizeCursor: gc not initialized\n");
611 src
= XCreatePixmap(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
,
612 pBits
->width
, pBits
->height
, 1);
613 msk
= XCreatePixmap(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
,
614 pBits
->width
, pBits
->height
, 1);
616 img
= XCreateImage(dmxScreen
->beDisplay
,
617 dmxScreen
->beVisuals
[dmxScreen
->beDefVisualIndex
].visual
,
618 1, XYBitmap
, 0, (char *)pBits
->source
,
619 pBits
->width
, pBits
->height
,
620 BitmapPad(dmxScreen
->beDisplay
), 0);
622 XPutImage(dmxScreen
->beDisplay
, src
, gc
, img
, 0, 0, 0, 0,
623 pBits
->width
, pBits
->height
);
627 img
= XCreateImage(dmxScreen
->beDisplay
,
628 dmxScreen
->beVisuals
[dmxScreen
->beDefVisualIndex
].visual
,
629 1, XYBitmap
, 0, (char *)pBits
->mask
,
630 pBits
->width
, pBits
->height
,
631 BitmapPad(dmxScreen
->beDisplay
), 0);
633 XPutImage(dmxScreen
->beDisplay
, msk
, gc
, img
, 0, 0, 0, 0,
634 pBits
->width
, pBits
->height
);
638 fg
.red
= pCursor
->foreRed
;
639 fg
.green
= pCursor
->foreGreen
;
640 fg
.blue
= pCursor
->foreBlue
;
642 bg
.red
= pCursor
->backRed
;
643 bg
.green
= pCursor
->backGreen
;
644 bg
.blue
= pCursor
->backBlue
;
646 pCursorPriv
->cursor
= XCreatePixmapCursor(dmxScreen
->beDisplay
,
649 pBits
->xhot
, pBits
->yhot
);
651 XFreePixmap(dmxScreen
->beDisplay
, src
);
652 XFreePixmap(dmxScreen
->beDisplay
, msk
);
653 XFreeGC(dmxScreen
->beDisplay
, gc
);
655 dmxSync(dmxScreen
, FALSE
);
658 static Bool
_dmxRealizeCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
660 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
661 dmxCursorPrivPtr pCursorPriv
;
663 DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen
->myNum
, pCursor
);
665 pCursor
->devPriv
[pScreen
->myNum
] = xalloc(sizeof(*pCursorPriv
));
666 if (!pCursor
->devPriv
[pScreen
->myNum
])
669 pCursorPriv
= DMX_GET_CURSOR_PRIV(pCursor
, pScreen
);
670 pCursorPriv
->cursor
= (Cursor
)0;
672 if (!dmxScreen
->beDisplay
)
675 dmxBECreateCursor(pScreen
, pCursor
);
679 /** Free \a pCursor on the back-end associated with \a pScreen. */
680 Bool
dmxBEFreeCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
682 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
683 dmxCursorPrivPtr pCursorPriv
= DMX_GET_CURSOR_PRIV(pCursor
, pScreen
);
686 XFreeCursor(dmxScreen
->beDisplay
, pCursorPriv
->cursor
);
687 pCursorPriv
->cursor
= (Cursor
)0;
694 static Bool
_dmxUnrealizeCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
696 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
698 DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n",
699 pScreen
->myNum
, pCursor
);
701 if (dmxScreen
->beDisplay
) {
702 if (dmxBEFreeCursor(pScreen
, pCursor
))
703 xfree(pCursor
->devPriv
[pScreen
->myNum
]);
705 pCursor
->devPriv
[pScreen
->myNum
] = NULL
;
710 static void _dmxMoveCursor(ScreenPtr pScreen
, int x
, int y
)
712 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
713 int newX
= x
+ dmxScreen
->rootX
;
714 int newY
= y
+ dmxScreen
->rootY
;
716 if (newX
< 0) newX
= 0;
717 if (newY
< 0) newY
= 0;
719 DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n",
720 pScreen
->myNum
, x
, y
, newX
, newY
);
721 if (dmxScreen
->beDisplay
) {
722 XWarpPointer(dmxScreen
->beDisplay
, None
, dmxScreen
->scrnWin
,
723 0, 0, 0, 0, newX
, newY
);
724 dmxSync(dmxScreen
, TRUE
);
728 static void _dmxSetCursor(ScreenPtr pScreen
, CursorPtr pCursor
, int x
, int y
)
730 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
732 DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen
->myNum
, pCursor
, x
, y
);
735 dmxCursorPrivPtr pCursorPriv
= DMX_GET_CURSOR_PRIV(pCursor
, pScreen
);
736 if (dmxScreen
->curCursor
!= pCursorPriv
->cursor
) {
737 if (dmxScreen
->beDisplay
)
738 XDefineCursor(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
,
739 pCursorPriv
->cursor
);
740 dmxScreen
->cursor
= pCursor
;
741 dmxScreen
->curCursor
= pCursorPriv
->cursor
;
742 dmxScreen
->cursorVisible
= 1;
744 _dmxMoveCursor(pScreen
, x
, y
);
746 if (dmxScreen
->beDisplay
)
747 XDefineCursor(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
,
748 dmxScreen
->noCursor
);
749 dmxScreen
->cursor
= NULL
;
750 dmxScreen
->curCursor
= (Cursor
)0;
751 dmxScreen
->cursorVisible
= 0;
753 if (dmxScreen
->beDisplay
) dmxSync(dmxScreen
, TRUE
);
756 static Bool
dmxRealizeCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
758 DMXScreenInfo
*start
= &dmxScreens
[pScreen
->myNum
];
761 if (!start
->over
|| !dmxCursorDoMultiCursors
|| start
->cursorNotShared
)
762 return _dmxRealizeCursor(pScreen
, pCursor
);
764 for (pt
= start
->over
; /* condition at end of loop */; pt
= pt
->over
) {
765 if (pt
->cursorNotShared
)
767 _dmxRealizeCursor(screenInfo
.screens
[pt
->index
], pCursor
);
774 static Bool
dmxUnrealizeCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
776 DMXScreenInfo
*start
= &dmxScreens
[pScreen
->myNum
];
779 if (!start
->over
|| !dmxCursorDoMultiCursors
|| start
->cursorNotShared
)
780 return _dmxUnrealizeCursor(pScreen
, pCursor
);
782 for (pt
= start
->over
; /* condition at end of loop */; pt
= pt
->over
) {
783 if (pt
->cursorNotShared
)
785 _dmxUnrealizeCursor(screenInfo
.screens
[pt
->index
], pCursor
);
792 static CursorPtr
dmxFindCursor(DMXScreenInfo
*start
)
796 if (!start
|| !start
->over
)
797 return GetSpriteCursor();
798 for (pt
= start
->over
; /* condition at end of loop */; pt
= pt
->over
) {
804 return GetSpriteCursor();
807 /** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This
808 * function is usually called via #dmxPointerSpriteFuncs, except during
809 * reconfiguration when the cursor is repositioned to force an update on
810 * newley overlapping screens and on screens that no longer overlap.
812 * The coords (x,y) are in global coord space. We'll loop over the
813 * back-end screens and see if they contain the global coord. If so, call
814 * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen.
816 void dmxMoveCursor(ScreenPtr pScreen
, int x
, int y
)
818 DMXScreenInfo
*start
= &dmxScreens
[pScreen
->myNum
];
821 DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen
->myNum
, x
, y
);
823 if (!start
->over
|| !dmxCursorDoMultiCursors
|| start
->cursorNotShared
) {
824 _dmxMoveCursor(pScreen
, x
, y
);
828 for (pt
= start
->over
; /* condition at end of loop */; pt
= pt
->over
) {
829 if (pt
->cursorNotShared
)
831 if (dmxOnScreen(x
+ start
->rootXOrigin
, y
+ start
->rootYOrigin
, pt
)) {
832 if (/* pt != start && */ !pt
->cursorVisible
) {
834 /* This only happens during
835 * reconfiguration when a new overlap
839 if ((pCursor
= dmxFindCursor(start
)))
840 _dmxRealizeCursor(screenInfo
.screens
[pt
->index
],
841 pt
->cursor
= pCursor
);
844 _dmxSetCursor(screenInfo
.screens
[pt
->index
],
846 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
847 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
849 _dmxMoveCursor(screenInfo
.screens
[pt
->index
],
850 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
851 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
852 } else if (/* pt != start && */ pt
->cursorVisible
) {
853 _dmxSetCursor(screenInfo
.screens
[pt
->index
],
855 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
856 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
863 static void dmxSetCursor(ScreenPtr pScreen
, CursorPtr pCursor
, int x
, int y
)
865 DMXScreenInfo
*start
= &dmxScreens
[pScreen
->myNum
];
869 DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n",
870 pScreen
->myNum
, start
, pCursor
, x
, y
);
872 /* We do this check here because of two cases:
874 * 1) if a client calls XWarpPointer()
875 * and Xinerama is not running, we can
876 * have mi's notion of the pointer
877 * position out of phase with DMX's
880 * 2) if a down button is held while the
881 * cursor moves outside the root window,
882 * mi's notion of the pointer position
883 * is out of phase with DMX's notion and
884 * the cursor can remain visible when it
887 dmxGetGlobalPosition(&GX
, &GY
);
888 gx
= start
->rootXOrigin
+ x
;
889 gy
= start
->rootYOrigin
+ y
;
890 if (x
&& y
&& (GX
!= gx
|| GY
!= gy
))
891 dmxCoreMotion(NULL
, gx
, gy
, 0, DMX_NO_BLOCK
);
893 if (!start
->over
|| !dmxCursorDoMultiCursors
|| start
->cursorNotShared
) {
894 _dmxSetCursor(pScreen
, pCursor
, x
, y
);
898 for (pt
= start
->over
; /* condition at end of loop */; pt
= pt
->over
) {
899 if (pt
->cursorNotShared
)
901 if (dmxOnScreen(x
+ start
->rootXOrigin
, y
+ start
->rootYOrigin
, pt
)) {
902 _dmxSetCursor(screenInfo
.screens
[pt
->index
], pCursor
,
903 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
904 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
906 _dmxSetCursor(screenInfo
.screens
[pt
->index
], NULL
,
907 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
908 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
916 /** This routine is used by the backend input routines to hide the
917 * cursor on a screen that is being used for relative input. \see
919 void dmxHideCursor(DMXScreenInfo
*dmxScreen
)
922 ScreenPtr pScreen
= screenInfo
.screens
[dmxScreen
->index
];
924 dmxGetGlobalPosition(&x
, &y
);
925 _dmxSetCursor(pScreen
, NULL
, x
, y
);
928 /** This routine is called during reconfiguration to make sure the
929 * cursor is visible. */
930 void dmxCheckCursor(void)
935 DMXScreenInfo
*firstScreen
;
937 dmxGetGlobalPosition(&x
, &y
);
938 firstScreen
= dmxFindFirstScreen(x
, y
);
940 DMXDBG2("dmxCheckCursor %d %d\n", x
, y
);
941 for (i
= 0; i
< dmxNumScreens
; i
++) {
942 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
943 pScreen
= screenInfo
.screens
[dmxScreen
->index
];
945 if (!dmxOnScreen(x
, y
, dmxScreen
)) {
947 if (firstScreen
&& i
== miPointerCurrentScreen()->myNum
)
948 miPointerSetNewScreen(firstScreen
->index
, x
, y
);
950 if (firstScreen
&& i
== miPointerGetScreen(inputInfo
.pointer
)->myNum
)
951 miPointerSetScreen(inputInfo
.pointer
, firstScreen
->index
, x
, y
);
953 _dmxSetCursor(pScreen
, NULL
,
954 x
- dmxScreen
->rootXOrigin
,
955 y
- dmxScreen
->rootYOrigin
);
957 if (!dmxScreen
->cursor
) {
960 if ((pCursor
= dmxFindCursor(dmxScreen
))) {
961 _dmxRealizeCursor(pScreen
, dmxScreen
->cursor
= pCursor
);
964 _dmxSetCursor(pScreen
, dmxScreen
->cursor
,
965 x
- dmxScreen
->rootXOrigin
,
966 y
- dmxScreen
->rootYOrigin
);
969 DMXDBG2(" leave dmxCheckCursor %d %d\n", x
, y
);
972 miPointerSpriteFuncRec dmxPointerSpriteFuncs
=