First import
[xorg_rtime.git] / xorg-server-1.4 / hw / dmx / dmxcursor.c
blob1ad199d5859e20a5cb3b0c01a7d1e03dcf9e989c
1 /*
2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
4 * All Rights Reserved.
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
25 * SOFTWARE.
29 * Authors:
30 * David H. Dawes <dawes@xfree86.org>
31 * Kevin E. Martin <kem@redhat.com>
32 * Rickard E. (Rik) Faith <faith@redhat.com>
36 /** \file
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."
45 * --Rik Faith
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
61 * may be compelling.
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>
77 #endif
79 #define DMX_CURSOR_DEBUG 0
81 #include "dmx.h"
82 #include "dmxsync.h"
83 #include "dmxcursor.h"
84 #include "dmxlog.h"
85 #include "dmxprop.h"
86 #include "dmxinput.h"
88 #include "mipointer.h"
89 #include "windowstr.h"
90 #include "globals.h"
91 #include "cursorstr.h"
92 #include "dixevents.h" /* For GetSpriteCursor() */
94 #if DMX_CURSOR_DEBUG
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)
103 #else
104 #define DMXDBG0(f)
105 #define DMXDBG1(f,a)
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)
112 #endif
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;
126 int i;
127 int localX = *x;
128 int localY = *y;
129 int globalX;
130 int globalY;
132 if (screenInfo.numScreens == 1)
133 return FALSE;
135 /* On current screen? */
136 dmxScreen = &dmxScreens[(*ppScreen)->myNum];
137 if (localX >= 0
138 && localX < dmxScreen->rootWidth
139 && localY >= 0
140 && localY < dmxScreen->rootHeight)
141 return FALSE;
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)
156 return FALSE;
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)
167 return FALSE;
168 *ppScreen = screenInfo.screens[dmxScreen->index];
169 *x = globalX - dmxScreen->rootXOrigin;
170 *y = globalY - dmxScreen->rootYOrigin;
171 return TRUE;
174 return FALSE;
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);
184 #if 11 /*BP*/
185 /* This call is depracated. Replace with???? */
186 miPointerWarpCursor(pScreen, x, y);
187 #else
188 pScreen->SetCursorPosition(pScreen, x, y, FALSE);
189 #endif
192 miPointerScreenFuncRec dmxPointerCursorFuncs =
194 dmxCursorOffScreen,
195 dmxCrossScreen,
196 dmxWarpCursor,
197 dmxeqEnqueue, /*XXX incompatible type/function! */
198 dmxeqSwitchScreen
202 /** Create a list of screens that we'll manipulate. */
203 static int *dmxSLCreate(void)
205 int *list = malloc(dmxNumScreens * sizeof(*list));
206 int i;
208 for (i = 0; i < dmxNumScreens; i++)
209 list[i] = 1;
210 return list;
213 /** Free list. */
214 static void dmxSLFree(int *list)
216 free(list);
219 /** Find next uninitialized entry in list. */
220 static int dmxSLFindNext(int *list)
222 int i;
223 for (i = 0; i < dmxNumScreens; i++)
224 if (list[i])
225 return i;
226 return -1;
229 /** Make one pass over all the screens and return the number updated. */
230 static int dmxTryComputeScreenOrigins(int *screensLeft)
232 ScreenPtr pScreen;
233 DMXScreenInfo *screen;
234 int i, ref;
235 int changed = 0;
237 for (i = 0; i < dmxNumScreens; i++) {
238 if (!screensLeft[i])
239 continue;
240 screen = &dmxScreens[i];
241 switch (screen->where) {
242 case PosAbsolute:
243 dixScreenOrigins[i].x = screen->whereX;
244 dixScreenOrigins[i].y = screen->whereY;
245 ++changed, screensLeft[i] = 0;
246 break;
247 case PosRelative:
248 ref = screen->whereRefScreen;
249 if (screensLeft[ref])
250 break;
251 dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->whereX;
252 dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->whereY;
253 ++changed, screensLeft[i] = 0;
254 break;
255 case PosRightOf:
256 ref = screen->whereRefScreen;
257 if (screensLeft[ref])
258 break;
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;
263 break;
264 case PosLeftOf:
265 ref = screen->whereRefScreen;
266 if (screensLeft[ref])
267 break;
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;
272 break;
273 case PosBelow:
274 ref = screen->whereRefScreen;
275 if (screensLeft[ref])
276 break;
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;
281 break;
282 case PosAbove:
283 ref = screen->whereRefScreen;
284 if (screensLeft[ref])
285 break;
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;
290 break;
291 case PosNone:
292 dmxLog(dmxFatal, "No position information for screen %d\n", i);
295 return changed;
298 static void dmxComputeScreenOrigins(void)
300 int *screensLeft;
301 int i, ref;
302 int minX, minY;
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
323 * (0,0). */
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;
332 if (minX || minY) {
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)
344 int i;
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)
372 int i;
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,
390 dmxScreen->where,
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;
404 dmxReInitOrigins();
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
412 dmxLog(dmxDebug,
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);
420 #endif
421 if (x >= dmxScreen->rootXOrigin
422 && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth
423 && y >= dmxScreen->rootYOrigin
424 && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1;
425 return 0;
428 /** Returns non-zero if \a a overlaps \a b. */
429 static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b)
431 if (dmxOnScreen(a->rootXOrigin,
432 a->rootYOrigin, b))
433 return 1;
435 if (dmxOnScreen(a->rootXOrigin,
436 a->rootYOrigin + a->scrnWidth, b))
437 return 1;
439 if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
440 a->rootYOrigin, b))
441 return 1;
443 if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
444 a->rootYOrigin + a->scrnWidth, b))
445 return 1;
447 if (dmxOnScreen(b->rootXOrigin,
448 b->rootYOrigin, a))
449 return 1;
451 if (dmxOnScreen(b->rootXOrigin,
452 b->rootYOrigin + b->scrnWidth, a))
453 return 1;
455 if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
456 b->rootYOrigin, a))
457 return 1;
459 if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
460 b->rootYOrigin + b->scrnWidth, a))
461 return 1;
463 return 0;
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);
474 else
475 dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name);
477 return NULL;
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 *),
485 void *closure)
487 DMXScreenInfo *pt;
489 if (!start->over) return f(start, closure);
491 for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
492 void *retval;
493 if ((retval = f(pt, closure))) return retval;
494 if (pt == start) break;
496 return NULL;
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;
505 if (a == b)
506 return a;
507 return NULL;
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)
516 int i, j;
517 DMXScreenInfo *a, *b, *pt;
519 for (i = 0; i < dmxNumScreens; i++)
520 dmxScreens[i].over = NULL;
522 for (i = 0; i < dmxNumScreens; i++) {
523 a = &dmxScreens[i];
525 for (j = i+1; j < dmxNumScreens; j++) {
526 b = &dmxScreens[j];
527 if (b->over)
528 continue;
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);
534 a->over = b;
539 for (i = 0; i < dmxNumScreens; i++) {
540 a = &dmxScreens[i];
542 if (!a->over)
543 continue;
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
553 * ->over set. */
554 if (!dmxDoesOverlap(a, pt))
555 continue;
556 a->cursorNotShared = 1;
557 pt->cursorNotShared = 1;
558 dmxLog(dmxInfo,
559 "Screen %d and %d overlap on %s\n",
560 a->index, pt->index, a->name);
565 for (i = 0; i < dmxNumScreens; i++) {
566 a = &dmxScreens[i];
568 if (a->over) {
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;
582 Pixmap src, msk;
583 XColor fg, bg;
584 XImage *img;
585 XlibGC gc = NULL;
586 XGCValues v;
587 unsigned long m;
588 int i;
590 if (!pCursorPriv)
591 return;
593 m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask;
594 v.function = GXcopy;
595 v.plane_mask = AllPlanes;
596 v.foreground = 1L;
597 v.background = 0L;
598 v.clip_mask = None;
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],
604 m, &v);
605 break;
608 if (!gc)
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);
625 XFree(img);
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);
636 XFree(img);
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,
647 src, msk,
648 &fg, &bg,
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])
667 return FALSE;
669 pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
670 pCursorPriv->cursor = (Cursor)0;
672 if (!dmxScreen->beDisplay)
673 return TRUE;
675 dmxBECreateCursor(pScreen, pCursor);
676 return TRUE;
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);
685 if (pCursorPriv) {
686 XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor);
687 pCursorPriv->cursor = (Cursor)0;
688 return TRUE;
691 return FALSE;
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;
707 return TRUE;
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);
734 if (pCursor) {
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);
745 } else {
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];
759 DMXScreenInfo *pt;
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)
766 continue;
767 _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor);
768 if (pt == start)
769 break;
771 return TRUE;
774 static Bool dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
776 DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
777 DMXScreenInfo *pt;
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)
784 continue;
785 _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor);
786 if (pt == start)
787 break;
789 return TRUE;
792 static CursorPtr dmxFindCursor(DMXScreenInfo *start)
794 DMXScreenInfo *pt;
796 if (!start || !start->over)
797 return GetSpriteCursor();
798 for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
799 if (pt->cursor)
800 return pt->cursor;
801 if (pt == start)
802 break;
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];
819 DMXScreenInfo *pt;
821 DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
823 if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
824 _dmxMoveCursor(pScreen, x, y);
825 return;
828 for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
829 if (pt->cursorNotShared)
830 continue;
831 if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
832 if (/* pt != start && */ !pt->cursorVisible) {
833 if (!pt->cursor) {
834 /* This only happens during
835 * reconfiguration when a new overlap
836 * occurs. */
837 CursorPtr pCursor;
839 if ((pCursor = dmxFindCursor(start)))
840 _dmxRealizeCursor(screenInfo.screens[pt->index],
841 pt->cursor = pCursor);
844 _dmxSetCursor(screenInfo.screens[pt->index],
845 pt->cursor,
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],
854 NULL,
855 x + start->rootXOrigin - pt->rootXOrigin,
856 y + start->rootYOrigin - pt->rootYOrigin);
858 if (pt == start)
859 break;
863 static void dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
865 DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
866 DMXScreenInfo *pt;
867 int GX, GY, gx, gy;
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
878 * notion.
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
885 * shouldn't be. */
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);
895 return;
898 for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
899 if (pt->cursorNotShared)
900 continue;
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);
905 } else {
906 _dmxSetCursor(screenInfo.screens[pt->index], NULL,
907 x + start->rootXOrigin - pt->rootXOrigin,
908 y + start->rootYOrigin - pt->rootYOrigin);
910 if (pt == start)
911 break;
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
918 * dmxbackend.c */
919 void dmxHideCursor(DMXScreenInfo *dmxScreen)
921 int x, y;
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)
932 int i;
933 int x, y;
934 ScreenPtr pScreen;
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)) {
946 #if 00
947 if (firstScreen && i == miPointerCurrentScreen()->myNum)
948 miPointerSetNewScreen(firstScreen->index, x, y);
949 #else
950 if (firstScreen && i == miPointerGetScreen(inputInfo.pointer)->myNum)
951 miPointerSetScreen(inputInfo.pointer, firstScreen->index, x, y);
952 #endif
953 _dmxSetCursor(pScreen, NULL,
954 x - dmxScreen->rootXOrigin,
955 y - dmxScreen->rootYOrigin);
956 } else {
957 if (!dmxScreen->cursor) {
958 CursorPtr pCursor;
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 =
974 dmxRealizeCursor,
975 dmxUnrealizeCursor,
976 dmxSetCursor,
977 dmxMoveCursor,