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() */
93 #include "inputstr.h" /* for inputInfo.pointer */
96 #define DMXDBG0(f) dmxLog(dmxDebug,f)
97 #define DMXDBG1(f,a) dmxLog(dmxDebug,f,a)
98 #define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b)
99 #define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
100 #define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d)
101 #define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e)
102 #define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g)
103 #define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
107 #define DMXDBG2(f,a,b)
108 #define DMXDBG3(f,a,b,c)
109 #define DMXDBG4(f,a,b,c,d)
110 #define DMXDBG5(f,a,b,c,d,e)
111 #define DMXDBG6(f,a,b,c,d,e,g)
112 #define DMXDBG7(f,a,b,c,d,e,g,h)
115 static int dmxCursorDoMultiCursors
= 1;
117 /** Turn off support for displaying multiple cursors on overlapped
118 back-end displays. See #dmxCursorDoMultiCursors. */
120 dmxCursorNoMulti(void)
122 dmxCursorDoMultiCursors
= 0;
126 dmxCursorOffScreen(ScreenPtr
*ppScreen
, int *x
, int *y
)
128 DMXScreenInfo
*dmxScreen
;
135 if (screenInfo
.numScreens
== 1)
138 /* On current screen? */
139 dmxScreen
= &dmxScreens
[(*ppScreen
)->myNum
];
141 && localX
< dmxScreen
->rootWidth
142 && localY
>= 0 && localY
< dmxScreen
->rootHeight
)
145 /* Convert to global coordinate space */
146 globalX
= dmxScreen
->rootXOrigin
+ localX
;
147 globalY
= dmxScreen
->rootYOrigin
+ localY
;
149 /* Is cursor on the current screen?
150 * This efficiently exits this routine
151 * for the most common case. */
152 if (ppScreen
&& *ppScreen
) {
153 dmxScreen
= &dmxScreens
[(*ppScreen
)->myNum
];
154 if (globalX
>= dmxScreen
->rootXOrigin
155 && globalX
< dmxScreen
->rootXOrigin
+ dmxScreen
->rootWidth
156 && globalY
>= dmxScreen
->rootYOrigin
157 && globalY
< dmxScreen
->rootYOrigin
+ dmxScreen
->rootHeight
)
161 /* Find first screen cursor is on */
162 for (i
= 0; i
< dmxNumScreens
; i
++) {
163 dmxScreen
= &dmxScreens
[i
];
164 if (globalX
>= dmxScreen
->rootXOrigin
165 && globalX
< dmxScreen
->rootXOrigin
+ dmxScreen
->rootWidth
166 && globalY
>= dmxScreen
->rootYOrigin
167 && globalY
< dmxScreen
->rootYOrigin
+ dmxScreen
->rootHeight
) {
168 if (dmxScreen
->index
== (*ppScreen
)->myNum
)
170 *ppScreen
= screenInfo
.screens
[dmxScreen
->index
];
171 *x
= globalX
- dmxScreen
->rootXOrigin
;
172 *y
= globalY
- dmxScreen
->rootYOrigin
;
180 dmxCrossScreen(ScreenPtr pScreen
, Bool entering
)
185 dmxWarpCursor(DeviceIntPtr pDev
, ScreenPtr pScreen
, int x
, int y
)
187 DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen
->myNum
, x
, y
);
189 /* This call is depracated. Replace with???? */
190 miPointerWarpCursor(pDev
, pScreen
, x
, y
);
192 pScreen
->SetCursorPosition(pDev
, pScreen
, x
, y
, FALSE
);
196 miPointerScreenFuncRec dmxPointerCursorFuncs
= {
202 /** Create a list of screens that we'll manipulate. */
206 int *list
= malloc(dmxNumScreens
* sizeof(*list
));
209 for (i
= 0; i
< dmxNumScreens
; i
++)
221 /** Find next uninitialized entry in list. */
223 dmxSLFindNext(int *list
)
227 for (i
= 0; i
< dmxNumScreens
; i
++)
233 /** Make one pass over all the screens and return the number updated. */
235 dmxTryComputeScreenOrigins(int *screensLeft
)
237 ScreenPtr pScreen
, refScreen
;
238 DMXScreenInfo
*screen
;
242 for (i
= 0; i
< dmxNumScreens
; i
++) {
245 screen
= &dmxScreens
[i
];
246 pScreen
= screenInfo
.screens
[i
];
247 switch (screen
->where
) {
249 pScreen
->x
= screen
->whereX
;
250 pScreen
->y
= screen
->whereY
;
251 ++changed
, screensLeft
[i
] = 0;
254 ref
= screen
->whereRefScreen
;
255 if (screensLeft
[ref
])
257 refScreen
= screenInfo
.screens
[ref
];
258 pScreen
->x
= refScreen
->x
+ screen
->whereX
;
259 pScreen
->y
= refScreen
->y
+ screen
->whereY
;
260 ++changed
, screensLeft
[i
] = 0;
263 ref
= screen
->whereRefScreen
;
264 if (screensLeft
[ref
])
266 refScreen
= screenInfo
.screens
[ref
];
267 pScreen
->x
= refScreen
->x
+ refScreen
->width
;
268 pScreen
->y
= refScreen
->y
;
269 ++changed
, screensLeft
[i
] = 0;
272 ref
= screen
->whereRefScreen
;
273 if (screensLeft
[ref
])
275 refScreen
= screenInfo
.screens
[ref
];
276 pScreen
->x
= refScreen
->x
- pScreen
->width
;
277 pScreen
->y
= refScreen
->y
;
278 ++changed
, screensLeft
[i
] = 0;
281 ref
= screen
->whereRefScreen
;
282 if (screensLeft
[ref
])
284 refScreen
= screenInfo
.screens
[ref
];
285 pScreen
->x
= refScreen
->x
;
286 pScreen
->y
= refScreen
->y
+ refScreen
->height
;
287 ++changed
, screensLeft
[i
] = 0;
290 ref
= screen
->whereRefScreen
;
291 if (screensLeft
[ref
])
293 refScreen
= screenInfo
.screens
[ref
];
294 pScreen
->x
= refScreen
->x
;
295 pScreen
->y
= refScreen
->y
- pScreen
->height
;
296 ++changed
, screensLeft
[i
] = 0;
299 dmxLog(dmxFatal
, "No position information for screen %d\n", i
);
306 dmxComputeScreenOrigins(void)
313 /* Compute origins based on
314 * configuration information. */
315 screensLeft
= dmxSLCreate();
316 while ((i
= dmxSLFindNext(screensLeft
)) >= 0) {
317 while (dmxTryComputeScreenOrigins(screensLeft
));
318 if ((i
= dmxSLFindNext(screensLeft
)) >= 0) {
319 /* All of the remaining screens are referencing each other.
320 * Assign a value to one of them and go through again. This
321 * guarantees that we will eventually terminate.
323 ref
= dmxScreens
[i
].whereRefScreen
;
324 pScreen
= screenInfo
.screens
[ref
];
325 pScreen
->x
= pScreen
->y
= 0;
326 screensLeft
[ref
] = 0;
329 dmxSLFree(screensLeft
);
331 /* Justify the topmost and leftmost to
333 minX
= screenInfo
.screens
[0]->x
;
334 minY
= screenInfo
.screens
[0]->y
;
335 for (i
= 1; i
< dmxNumScreens
; i
++) { /* Compute minX, minY */
336 if (screenInfo
.screens
[i
]->x
< minX
)
337 minX
= screenInfo
.screens
[i
]->x
;
338 if (screenInfo
.screens
[i
]->y
< minY
)
339 minY
= screenInfo
.screens
[i
]->y
;
342 for (i
= 0; i
< dmxNumScreens
; i
++) {
343 screenInfo
.screens
[i
]->x
-= minX
;
344 screenInfo
.screens
[i
]->y
-= minY
;
348 update_desktop_dimensions();
351 /** Recompute origin information in the #dmxScreens list. This is
352 * called from #dmxInitOrigins. */
354 dmxReInitOrigins(void)
358 if (dmxNumScreens
> MAXSCREENS
)
359 dmxLog(dmxFatal
, "dmxNumScreens = %d > MAXSCREENS = %d\n",
360 dmxNumScreens
, MAXSCREENS
);
362 for (i
= 0; i
< dmxNumScreens
; i
++) {
363 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
365 dmxLogOutput(dmxScreen
,
366 "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d"
367 " (be=%dx%d depth=%d bpp=%d)\n",
368 dmxScreen
->scrnWidth
, dmxScreen
->scrnHeight
,
369 dmxScreen
->scrnX
, dmxScreen
->scrnY
,
370 dmxScreen
->rootWidth
, dmxScreen
->rootHeight
,
371 dmxScreen
->rootX
, dmxScreen
->rootY
,
372 dmxScreen
->rootXOrigin
, dmxScreen
->rootYOrigin
,
373 dmxScreen
->beWidth
, dmxScreen
->beHeight
,
374 dmxScreen
->beDepth
, dmxScreen
->beBPP
);
378 /** Initialize screen origins (and relative position). This is called
379 * for each server generation. For dynamic reconfiguration, use
380 * #dmxReInitOrigins() instead. */
386 if (dmxNumScreens
> MAXSCREENS
)
387 dmxLog(dmxFatal
, "dmxNumScreens = %d > MAXSCREENS = %d\n",
388 dmxNumScreens
, MAXSCREENS
);
390 for (i
= 0; i
< dmxNumScreens
; i
++) {
391 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
393 dmxLogOutput(dmxScreen
,
394 "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)"
395 " (be=%dx%d depth=%d bpp=%d)\n",
396 dmxScreen
->scrnWidth
, dmxScreen
->scrnHeight
,
397 dmxScreen
->scrnX
, dmxScreen
->scrnY
,
398 dmxScreen
->rootWidth
, dmxScreen
->rootHeight
,
399 dmxScreen
->rootX
, dmxScreen
->rootY
,
400 dmxScreen
->whereX
, dmxScreen
->whereY
,
402 dmxScreen
->beWidth
, dmxScreen
->beHeight
,
403 dmxScreen
->beDepth
, dmxScreen
->beBPP
);
406 dmxComputeScreenOrigins();
408 for (i
= 0; i
< dmxNumScreens
; i
++) {
409 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
411 dmxScreen
->rootXOrigin
= screenInfo
.screens
[i
]->x
;
412 dmxScreen
->rootYOrigin
= screenInfo
.screens
[i
]->y
;
418 /** Returns non-zero if the global \a x, \a y coordinate is on the
419 * screen window of the \a dmxScreen. */
421 dmxOnScreen(int x
, int y
, DMXScreenInfo
* dmxScreen
)
423 #if DMX_CURSOR_DEBUG > 1
425 "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n",
426 dmxScreen
->index
, x
, y
,
427 dmxScreen
->rootWidth
, dmxScreen
->rootHeight
,
428 dmxScreen
->rootX
, dmxScreen
->rootY
,
429 dmxScreen
->rootXOrigin
, dmxScreen
->rootYOrigin
,
430 dmxScreen
->scrnWidth
, dmxScreen
->scrnHeight
,
431 dmxScreen
->scrnX
, dmxScreen
->scrnY
);
433 if (x
>= dmxScreen
->rootXOrigin
434 && x
< dmxScreen
->rootXOrigin
+ dmxScreen
->rootWidth
435 && y
>= dmxScreen
->rootYOrigin
436 && y
< dmxScreen
->rootYOrigin
+ dmxScreen
->rootHeight
)
441 /** Returns non-zero if \a a overlaps \a b. */
443 dmxDoesOverlap(DMXScreenInfo
* a
, DMXScreenInfo
* b
)
445 if (dmxOnScreen(a
->rootXOrigin
, a
->rootYOrigin
, b
))
448 if (dmxOnScreen(a
->rootXOrigin
, a
->rootYOrigin
+ a
->scrnWidth
, b
))
451 if (dmxOnScreen(a
->rootXOrigin
+ a
->scrnHeight
, a
->rootYOrigin
, b
))
454 if (dmxOnScreen(a
->rootXOrigin
+ a
->scrnHeight
,
455 a
->rootYOrigin
+ a
->scrnWidth
, b
))
458 if (dmxOnScreen(b
->rootXOrigin
, b
->rootYOrigin
, a
))
461 if (dmxOnScreen(b
->rootXOrigin
, b
->rootYOrigin
+ b
->scrnWidth
, a
))
464 if (dmxOnScreen(b
->rootXOrigin
+ b
->scrnHeight
, b
->rootYOrigin
, a
))
467 if (dmxOnScreen(b
->rootXOrigin
+ b
->scrnHeight
,
468 b
->rootYOrigin
+ b
->scrnWidth
, a
))
474 /** Used with \a dmxInterateOverlap to print out a list of screens which
475 * overlap each other. */
477 dmxPrintOverlap(DMXScreenInfo
* dmxScreen
, void *closure
)
479 DMXScreenInfo
*a
= closure
;
481 if (dmxScreen
!= a
) {
482 if (dmxScreen
->cursorNotShared
)
483 dmxLogOutputCont(a
, " [%d/%s]", dmxScreen
->index
, dmxScreen
->name
);
485 dmxLogOutputCont(a
, " %d/%s", dmxScreen
->index
, dmxScreen
->name
);
490 /** Iterate over the screens which overlap with the \a start screen,
491 * calling \a f with the \a closure for each argument. Often used with
492 * #dmxPrintOverlap. */
494 dmxIterateOverlap(DMXScreenInfo
* start
,
495 void *(*f
) (DMXScreenInfo
* dmxScreen
, void *), void *closure
)
500 return f(start
, closure
);
502 for (pt
= start
->over
; /* condition at end of loop */ ; pt
= pt
->over
) {
505 if ((retval
= f(pt
, closure
)))
513 /** Used with #dmxPropertyIterate to determine if screen \a a is the
514 * same as the screen \a closure. */
516 dmxTestSameDisplay(DMXScreenInfo
* a
, void *closure
)
518 DMXScreenInfo
*b
= closure
;
525 /** Detects overlapping dmxScreens and creates circular lists. This
526 * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and
527 * the computation only needs to be performed for every server
528 * generation or dynamic reconfiguration . */
533 DMXScreenInfo
*a
, *b
, *pt
;
535 for (i
= 0; i
< dmxNumScreens
; i
++)
536 dmxScreens
[i
].over
= NULL
;
538 for (i
= 0; i
< dmxNumScreens
; i
++) {
541 for (j
= i
+ 1; j
< dmxNumScreens
; j
++) {
546 if (dmxDoesOverlap(a
, b
)) {
547 DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n",
548 a
->index
, b
->index
, a
, a
->over
, b
, b
->over
);
549 b
->over
= (a
->over
? a
->over
: a
);
555 for (i
= 0; i
< dmxNumScreens
; i
++) {
561 /* Flag all pairs that are on same display */
562 for (pt
= a
->over
; pt
!= a
; pt
= pt
->over
) {
563 if (dmxPropertyIterate(a
, dmxTestSameDisplay
, pt
)) {
564 /* The ->over sets contain the transitive set of screens
565 * that overlap. For screens that are on the same
566 * backend display, we only want to exclude pairs of
567 * screens that mutually overlap on the backend display,
568 * so we call dmxDoesOverlap, which is stricter than the
570 if (!dmxDoesOverlap(a
, pt
))
572 a
->cursorNotShared
= 1;
573 pt
->cursorNotShared
= 1;
575 "Screen %d and %d overlap on %s\n",
576 a
->index
, pt
->index
, a
->name
);
581 for (i
= 0; i
< dmxNumScreens
; i
++) {
585 dmxLogOutput(a
, "Overlaps");
586 dmxIterateOverlap(a
, dmxPrintOverlap
, a
);
587 dmxLogOutputCont(a
, "\n");
592 /** Create \a pCursor on the back-end associated with \a pScreen. */
594 dmxBECreateCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
596 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
597 dmxCursorPrivPtr pCursorPriv
= DMX_GET_CURSOR_PRIV(pCursor
, pScreen
);
598 CursorBitsPtr pBits
= pCursor
->bits
;
610 m
= GCFunction
| GCPlaneMask
| GCForeground
| GCBackground
| GCClipMask
;
612 v
.plane_mask
= AllPlanes
;
617 for (i
= 0; i
< dmxScreen
->beNumPixmapFormats
; i
++) {
618 if (dmxScreen
->bePixmapFormats
[i
].depth
== 1) {
619 /* Create GC in the back-end servers */
620 gc
= XCreateGC(dmxScreen
->beDisplay
, dmxScreen
->scrnDefDrawables
[i
],
626 dmxLog(dmxFatal
, "dmxRealizeCursor: gc not initialized\n");
628 src
= XCreatePixmap(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
,
629 pBits
->width
, pBits
->height
, 1);
630 msk
= XCreatePixmap(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
,
631 pBits
->width
, pBits
->height
, 1);
633 img
= XCreateImage(dmxScreen
->beDisplay
,
634 dmxScreen
->beVisuals
[dmxScreen
->beDefVisualIndex
].visual
,
635 1, XYBitmap
, 0, (char *) pBits
->source
,
636 pBits
->width
, pBits
->height
,
637 BitmapPad(dmxScreen
->beDisplay
), 0);
639 XPutImage(dmxScreen
->beDisplay
, src
, gc
, img
, 0, 0, 0, 0,
640 pBits
->width
, pBits
->height
);
644 img
= XCreateImage(dmxScreen
->beDisplay
,
645 dmxScreen
->beVisuals
[dmxScreen
->beDefVisualIndex
].visual
,
646 1, XYBitmap
, 0, (char *) pBits
->mask
,
647 pBits
->width
, pBits
->height
,
648 BitmapPad(dmxScreen
->beDisplay
), 0);
650 XPutImage(dmxScreen
->beDisplay
, msk
, gc
, img
, 0, 0, 0, 0,
651 pBits
->width
, pBits
->height
);
655 fg
.red
= pCursor
->foreRed
;
656 fg
.green
= pCursor
->foreGreen
;
657 fg
.blue
= pCursor
->foreBlue
;
659 bg
.red
= pCursor
->backRed
;
660 bg
.green
= pCursor
->backGreen
;
661 bg
.blue
= pCursor
->backBlue
;
663 pCursorPriv
->cursor
= XCreatePixmapCursor(dmxScreen
->beDisplay
,
666 pBits
->xhot
, pBits
->yhot
);
668 XFreePixmap(dmxScreen
->beDisplay
, src
);
669 XFreePixmap(dmxScreen
->beDisplay
, msk
);
670 XFreeGC(dmxScreen
->beDisplay
, gc
);
672 dmxSync(dmxScreen
, FALSE
);
676 _dmxRealizeCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
678 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
679 dmxCursorPrivPtr pCursorPriv
;
681 DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen
->myNum
, pCursor
);
683 DMX_SET_CURSOR_PRIV(pCursor
, pScreen
, malloc(sizeof(*pCursorPriv
)));
684 if (!DMX_GET_CURSOR_PRIV(pCursor
, pScreen
))
687 pCursorPriv
= DMX_GET_CURSOR_PRIV(pCursor
, pScreen
);
688 pCursorPriv
->cursor
= (Cursor
) 0;
690 if (!dmxScreen
->beDisplay
)
693 dmxBECreateCursor(pScreen
, pCursor
);
697 /** Free \a pCursor on the back-end associated with \a pScreen. */
699 dmxBEFreeCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
701 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
702 dmxCursorPrivPtr pCursorPriv
= DMX_GET_CURSOR_PRIV(pCursor
, pScreen
);
705 XFreeCursor(dmxScreen
->beDisplay
, pCursorPriv
->cursor
);
706 pCursorPriv
->cursor
= (Cursor
) 0;
714 _dmxUnrealizeCursor(ScreenPtr pScreen
, CursorPtr pCursor
)
716 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
718 DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", pScreen
->myNum
, pCursor
);
720 if (dmxScreen
->beDisplay
) {
721 if (dmxBEFreeCursor(pScreen
, pCursor
))
722 free(DMX_GET_CURSOR_PRIV(pCursor
, pScreen
));
724 DMX_SET_CURSOR_PRIV(pCursor
, pScreen
, NULL
);
730 _dmxMoveCursor(ScreenPtr pScreen
, int x
, int y
)
732 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
733 int newX
= x
+ dmxScreen
->rootX
;
734 int newY
= y
+ dmxScreen
->rootY
;
741 DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n",
742 pScreen
->myNum
, x
, y
, newX
, newY
);
743 if (dmxScreen
->beDisplay
) {
744 XWarpPointer(dmxScreen
->beDisplay
, None
, dmxScreen
->scrnWin
,
745 0, 0, 0, 0, newX
, newY
);
746 dmxSync(dmxScreen
, TRUE
);
751 _dmxSetCursor(ScreenPtr pScreen
, CursorPtr pCursor
, int x
, int y
)
753 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
755 DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen
->myNum
, pCursor
, x
, y
);
758 dmxCursorPrivPtr pCursorPriv
= DMX_GET_CURSOR_PRIV(pCursor
, pScreen
);
760 if (pCursorPriv
&& dmxScreen
->curCursor
!= pCursorPriv
->cursor
) {
761 if (dmxScreen
->beDisplay
)
762 XDefineCursor(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
,
763 pCursorPriv
->cursor
);
764 dmxScreen
->cursor
= pCursor
;
765 dmxScreen
->curCursor
= pCursorPriv
->cursor
;
766 dmxScreen
->cursorVisible
= 1;
768 _dmxMoveCursor(pScreen
, x
, y
);
771 if (dmxScreen
->beDisplay
)
772 XDefineCursor(dmxScreen
->beDisplay
, dmxScreen
->scrnWin
,
773 dmxScreen
->noCursor
);
774 dmxScreen
->cursor
= NULL
;
775 dmxScreen
->curCursor
= (Cursor
) 0;
776 dmxScreen
->cursorVisible
= 0;
778 if (dmxScreen
->beDisplay
)
779 dmxSync(dmxScreen
, TRUE
);
783 dmxRealizeCursor(DeviceIntPtr pDev
, ScreenPtr pScreen
, CursorPtr pCursor
)
785 DMXScreenInfo
*start
= &dmxScreens
[pScreen
->myNum
];
788 if (!start
->over
|| !dmxCursorDoMultiCursors
|| start
->cursorNotShared
)
789 return _dmxRealizeCursor(pScreen
, pCursor
);
791 for (pt
= start
->over
; /* condition at end of loop */ ; pt
= pt
->over
) {
792 if (pt
->cursorNotShared
)
794 _dmxRealizeCursor(screenInfo
.screens
[pt
->index
], pCursor
);
802 dmxUnrealizeCursor(DeviceIntPtr pDev
, ScreenPtr pScreen
, CursorPtr pCursor
)
804 DMXScreenInfo
*start
= &dmxScreens
[pScreen
->myNum
];
807 if (!start
->over
|| !dmxCursorDoMultiCursors
|| start
->cursorNotShared
)
808 return _dmxUnrealizeCursor(pScreen
, pCursor
);
810 for (pt
= start
->over
; /* condition at end of loop */ ; pt
= pt
->over
) {
811 if (pt
->cursorNotShared
)
813 _dmxUnrealizeCursor(screenInfo
.screens
[pt
->index
], pCursor
);
821 dmxFindCursor(DMXScreenInfo
* start
)
825 if (!start
|| !start
->over
)
826 return GetSpriteCursor(inputInfo
.pointer
);
827 for (pt
= start
->over
; /* condition at end of loop */ ; pt
= pt
->over
) {
833 return GetSpriteCursor(inputInfo
.pointer
);
836 /** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This
837 * function is usually called via #dmxPointerSpriteFuncs, except during
838 * reconfiguration when the cursor is repositioned to force an update on
839 * newley overlapping screens and on screens that no longer overlap.
841 * The coords (x,y) are in global coord space. We'll loop over the
842 * back-end screens and see if they contain the global coord. If so, call
843 * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen.
846 dmxMoveCursor(DeviceIntPtr pDev
, ScreenPtr pScreen
, int x
, int y
)
848 DMXScreenInfo
*start
= &dmxScreens
[pScreen
->myNum
];
851 DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen
->myNum
, x
, y
);
853 if (!start
->over
|| !dmxCursorDoMultiCursors
|| start
->cursorNotShared
) {
854 _dmxMoveCursor(pScreen
, x
, y
);
858 for (pt
= start
->over
; /* condition at end of loop */ ; pt
= pt
->over
) {
859 if (pt
->cursorNotShared
)
861 if (dmxOnScreen(x
+ start
->rootXOrigin
, y
+ start
->rootYOrigin
, pt
)) {
862 if ( /* pt != start && */ !pt
->cursorVisible
) {
864 /* This only happens during
865 * reconfiguration when a new overlap
869 if ((pCursor
= dmxFindCursor(start
)))
870 _dmxRealizeCursor(screenInfo
.screens
[pt
->index
],
871 pt
->cursor
= pCursor
);
874 _dmxSetCursor(screenInfo
.screens
[pt
->index
],
876 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
877 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
879 _dmxMoveCursor(screenInfo
.screens
[pt
->index
],
880 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
881 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
883 else if ( /* pt != start && */ pt
->cursorVisible
) {
884 _dmxSetCursor(screenInfo
.screens
[pt
->index
],
886 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
887 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
895 dmxSetCursor(DeviceIntPtr pDev
, ScreenPtr pScreen
, CursorPtr pCursor
, int x
,
898 DMXScreenInfo
*start
= &dmxScreens
[pScreen
->myNum
];
902 DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n",
903 pScreen
->myNum
, start
, pCursor
, x
, y
);
905 /* We do this check here because of two cases:
907 * 1) if a client calls XWarpPointer()
908 * and Xinerama is not running, we can
909 * have mi's notion of the pointer
910 * position out of phase with DMX's
913 * 2) if a down button is held while the
914 * cursor moves outside the root window,
915 * mi's notion of the pointer position
916 * is out of phase with DMX's notion and
917 * the cursor can remain visible when it
920 dmxGetGlobalPosition(&GX
, &GY
);
921 gx
= start
->rootXOrigin
+ x
;
922 gy
= start
->rootYOrigin
+ y
;
923 if (x
&& y
&& (GX
!= gx
|| GY
!= gy
))
924 dmxCoreMotion(NULL
, gx
, gy
, 0, DMX_NO_BLOCK
);
926 if (!start
->over
|| !dmxCursorDoMultiCursors
|| start
->cursorNotShared
) {
927 _dmxSetCursor(pScreen
, pCursor
, x
, y
);
931 for (pt
= start
->over
; /* condition at end of loop */ ; pt
= pt
->over
) {
932 if (pt
->cursorNotShared
)
934 if (dmxOnScreen(x
+ start
->rootXOrigin
, y
+ start
->rootYOrigin
, pt
)) {
935 _dmxSetCursor(screenInfo
.screens
[pt
->index
], pCursor
,
936 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
937 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
940 _dmxSetCursor(screenInfo
.screens
[pt
->index
], NULL
,
941 x
+ start
->rootXOrigin
- pt
->rootXOrigin
,
942 y
+ start
->rootYOrigin
- pt
->rootYOrigin
);
949 /** This routine is used by the backend input routines to hide the
950 * cursor on a screen that is being used for relative input. \see
953 dmxHideCursor(DMXScreenInfo
* dmxScreen
)
956 ScreenPtr pScreen
= screenInfo
.screens
[dmxScreen
->index
];
958 dmxGetGlobalPosition(&x
, &y
);
959 _dmxSetCursor(pScreen
, NULL
, x
, y
);
962 /** This routine is called during reconfiguration to make sure the
963 * cursor is visible. */
970 DMXScreenInfo
*firstScreen
;
972 dmxGetGlobalPosition(&x
, &y
);
973 firstScreen
= dmxFindFirstScreen(x
, y
);
975 DMXDBG2("dmxCheckCursor %d %d\n", x
, y
);
976 for (i
= 0; i
< dmxNumScreens
; i
++) {
977 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
979 pScreen
= screenInfo
.screens
[dmxScreen
->index
];
981 if (!dmxOnScreen(x
, y
, dmxScreen
)) {
983 i
== miPointerGetScreen(inputInfo
.pointer
)->myNum
)
984 miPointerSetScreen(inputInfo
.pointer
, firstScreen
->index
, x
,
986 _dmxSetCursor(pScreen
, NULL
, x
- dmxScreen
->rootXOrigin
,
987 y
- dmxScreen
->rootYOrigin
);
990 if (!dmxScreen
->cursor
) {
993 if ((pCursor
= dmxFindCursor(dmxScreen
))) {
994 _dmxRealizeCursor(pScreen
, dmxScreen
->cursor
= pCursor
);
997 _dmxSetCursor(pScreen
, dmxScreen
->cursor
,
998 x
- dmxScreen
->rootXOrigin
,
999 y
- dmxScreen
->rootYOrigin
);
1002 DMXDBG2(" leave dmxCheckCursor %d %d\n", x
, y
);
1006 dmxDeviceCursorInitialize(DeviceIntPtr pDev
, ScreenPtr pScr
)
1012 dmxDeviceCursorCleanup(DeviceIntPtr pDev
, ScreenPtr pScr
)
1016 miPointerSpriteFuncRec dmxPointerSpriteFuncs
= {
1021 dmxDeviceCursorInitialize
,
1022 dmxDeviceCursorCleanup