Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / dmxcursor.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
3 *
4 * All Rights Reserved.
5 *
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:
13 *
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.
17 *
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.
26 */
27
28/*
29 * Authors:
30 * David H. Dawes <dawes@xfree86.org>
31 * Kevin E. Martin <kem@redhat.com>
32 * Rickard E. (Rik) Faith <faith@redhat.com>
33 *
34 */
35
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.
40 *
41 * "This code is based very closely on the XFree86 equivalent
42 * (xfree86/common/xf86Cursor.c)." --David Dawes.
43 *
44 * "This code was then extensively re-written, as explained here."
45 * --Rik Faith
46 *
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.
62 *
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.
73 */
74
75#ifdef HAVE_DMX_CONFIG_H
76#include <dmx-config.h>
77#endif
78
79#define DMX_CURSOR_DEBUG 0
80
81#include "dmx.h"
82#include "dmxsync.h"
83#include "dmxcursor.h"
84#include "dmxlog.h"
85#include "dmxprop.h"
86#include "dmxinput.h"
87
88#include "mipointer.h"
89#include "windowstr.h"
90#include "globals.h"
91#include "cursorstr.h"
92#include "dixevents.h" /* For GetSpriteCursor() */
93#include "inputstr.h" /* for inputInfo.pointer */
94
95#if DMX_CURSOR_DEBUG
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)
104#else
105#define DMXDBG0(f)
106#define DMXDBG1(f,a)
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)
113#endif
114
115static int dmxCursorDoMultiCursors = 1;
116
117/** Turn off support for displaying multiple cursors on overlapped
118 back-end displays. See #dmxCursorDoMultiCursors. */
119void
120dmxCursorNoMulti(void)
121{
122 dmxCursorDoMultiCursors = 0;
123}
124
125static Bool
126dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
127{
128 DMXScreenInfo *dmxScreen;
129 int i;
130 int localX = *x;
131 int localY = *y;
132 int globalX;
133 int globalY;
134
135 if (screenInfo.numScreens == 1)
136 return FALSE;
137
138 /* On current screen? */
139 dmxScreen = &dmxScreens[(*ppScreen)->myNum];
140 if (localX >= 0
141 && localX < dmxScreen->rootWidth
142 && localY >= 0 && localY < dmxScreen->rootHeight)
143 return FALSE;
144
145 /* Convert to global coordinate space */
146 globalX = dmxScreen->rootXOrigin + localX;
147 globalY = dmxScreen->rootYOrigin + localY;
148
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)
158 return FALSE;
159 }
160
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)
169 return FALSE;
170 *ppScreen = screenInfo.screens[dmxScreen->index];
171 *x = globalX - dmxScreen->rootXOrigin;
172 *y = globalY - dmxScreen->rootYOrigin;
173 return TRUE;
174 }
175 }
176 return FALSE;
177}
178
179static void
180dmxCrossScreen(ScreenPtr pScreen, Bool entering)
181{
182}
183
184static void
185dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
186{
187 DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
188#if 11 /*BP*/
189 /* This call is depracated. Replace with???? */
190 miPointerWarpCursor(pDev, pScreen, x, y);
191#else
192 pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE);
193#endif
194}
195
196miPointerScreenFuncRec dmxPointerCursorFuncs = {
197 dmxCursorOffScreen,
198 dmxCrossScreen,
199 dmxWarpCursor,
200};
201
202/** Create a list of screens that we'll manipulate. */
203static int *
204dmxSLCreate(void)
205{
206 int *list = malloc(dmxNumScreens * sizeof(*list));
207 int i;
208
209 for (i = 0; i < dmxNumScreens; i++)
210 list[i] = 1;
211 return list;
212}
213
214/** Free list. */
215static void
216dmxSLFree(int *list)
217{
218 free(list);
219}
220
221/** Find next uninitialized entry in list. */
222static int
223dmxSLFindNext(int *list)
224{
225 int i;
226
227 for (i = 0; i < dmxNumScreens; i++)
228 if (list[i])
229 return i;
230 return -1;
231}
232
233/** Make one pass over all the screens and return the number updated. */
234static int
235dmxTryComputeScreenOrigins(int *screensLeft)
236{
237 ScreenPtr pScreen, refScreen;
238 DMXScreenInfo *screen;
239 int i, ref;
240 int changed = 0;
241
242 for (i = 0; i < dmxNumScreens; i++) {
243 if (!screensLeft[i])
244 continue;
245 screen = &dmxScreens[i];
246 pScreen = screenInfo.screens[i];
247 switch (screen->where) {
248 case PosAbsolute:
249 pScreen->x = screen->whereX;
250 pScreen->y = screen->whereY;
251 ++changed, screensLeft[i] = 0;
252 break;
253 case PosRelative:
254 ref = screen->whereRefScreen;
255 if (screensLeft[ref])
256 break;
257 refScreen = screenInfo.screens[ref];
258 pScreen->x = refScreen->x + screen->whereX;
259 pScreen->y = refScreen->y + screen->whereY;
260 ++changed, screensLeft[i] = 0;
261 break;
262 case PosRightOf:
263 ref = screen->whereRefScreen;
264 if (screensLeft[ref])
265 break;
266 refScreen = screenInfo.screens[ref];
267 pScreen->x = refScreen->x + refScreen->width;
268 pScreen->y = refScreen->y;
269 ++changed, screensLeft[i] = 0;
270 break;
271 case PosLeftOf:
272 ref = screen->whereRefScreen;
273 if (screensLeft[ref])
274 break;
275 refScreen = screenInfo.screens[ref];
276 pScreen->x = refScreen->x - pScreen->width;
277 pScreen->y = refScreen->y;
278 ++changed, screensLeft[i] = 0;
279 break;
280 case PosBelow:
281 ref = screen->whereRefScreen;
282 if (screensLeft[ref])
283 break;
284 refScreen = screenInfo.screens[ref];
285 pScreen->x = refScreen->x;
286 pScreen->y = refScreen->y + refScreen->height;
287 ++changed, screensLeft[i] = 0;
288 break;
289 case PosAbove:
290 ref = screen->whereRefScreen;
291 if (screensLeft[ref])
292 break;
293 refScreen = screenInfo.screens[ref];
294 pScreen->x = refScreen->x;
295 pScreen->y = refScreen->y - pScreen->height;
296 ++changed, screensLeft[i] = 0;
297 break;
298 case PosNone:
299 dmxLog(dmxFatal, "No position information for screen %d\n", i);
300 }
301 }
302 return changed;
303}
304
305static void
306dmxComputeScreenOrigins(void)
307{
308 ScreenPtr pScreen;
309 int *screensLeft;
310 int i, ref;
311 int minX, minY;
312
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.
322 */
323 ref = dmxScreens[i].whereRefScreen;
324 pScreen = screenInfo.screens[ref];
325 pScreen->x = pScreen->y = 0;
326 screensLeft[ref] = 0;
327 }
328 }
329 dmxSLFree(screensLeft);
330
331 /* Justify the topmost and leftmost to
332 * (0,0). */
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;
340 }
341 if (minX || minY) {
342 for (i = 0; i < dmxNumScreens; i++) {
343 screenInfo.screens[i]->x -= minX;
344 screenInfo.screens[i]->y -= minY;
345 }
346 }
347
348 update_desktop_dimensions();
349}
350
351/** Recompute origin information in the #dmxScreens list. This is
352 * called from #dmxInitOrigins. */
353void
354dmxReInitOrigins(void)
355{
356 int i;
357
358 if (dmxNumScreens > MAXSCREENS)
359 dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
360 dmxNumScreens, MAXSCREENS);
361
362 for (i = 0; i < dmxNumScreens; i++) {
363 DMXScreenInfo *dmxScreen = &dmxScreens[i];
364
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);
375 }
376}
377
378/** Initialize screen origins (and relative position). This is called
379 * for each server generation. For dynamic reconfiguration, use
380 * #dmxReInitOrigins() instead. */
381void
382dmxInitOrigins(void)
383{
384 int i;
385
386 if (dmxNumScreens > MAXSCREENS)
387 dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
388 dmxNumScreens, MAXSCREENS);
389
390 for (i = 0; i < dmxNumScreens; i++) {
391 DMXScreenInfo *dmxScreen = &dmxScreens[i];
392
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,
401 dmxScreen->where,
402 dmxScreen->beWidth, dmxScreen->beHeight,
403 dmxScreen->beDepth, dmxScreen->beBPP);
404 }
405
406 dmxComputeScreenOrigins();
407
408 for (i = 0; i < dmxNumScreens; i++) {
409 DMXScreenInfo *dmxScreen = &dmxScreens[i];
410
411 dmxScreen->rootXOrigin = screenInfo.screens[i]->x;
412 dmxScreen->rootYOrigin = screenInfo.screens[i]->y;
413 }
414
415 dmxReInitOrigins();
416}
417
418/** Returns non-zero if the global \a x, \a y coordinate is on the
419 * screen window of the \a dmxScreen. */
420int
421dmxOnScreen(int x, int y, DMXScreenInfo * dmxScreen)
422{
423#if DMX_CURSOR_DEBUG > 1
424 dmxLog(dmxDebug,
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);
432#endif
433 if (x >= dmxScreen->rootXOrigin
434 && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth
435 && y >= dmxScreen->rootYOrigin
436 && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight)
437 return 1;
438 return 0;
439}
440
441/** Returns non-zero if \a a overlaps \a b. */
442static int
443dmxDoesOverlap(DMXScreenInfo * a, DMXScreenInfo * b)
444{
445 if (dmxOnScreen(a->rootXOrigin, a->rootYOrigin, b))
446 return 1;
447
448 if (dmxOnScreen(a->rootXOrigin, a->rootYOrigin + a->scrnWidth, b))
449 return 1;
450
451 if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, a->rootYOrigin, b))
452 return 1;
453
454 if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
455 a->rootYOrigin + a->scrnWidth, b))
456 return 1;
457
458 if (dmxOnScreen(b->rootXOrigin, b->rootYOrigin, a))
459 return 1;
460
461 if (dmxOnScreen(b->rootXOrigin, b->rootYOrigin + b->scrnWidth, a))
462 return 1;
463
464 if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, b->rootYOrigin, a))
465 return 1;
466
467 if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
468 b->rootYOrigin + b->scrnWidth, a))
469 return 1;
470
471 return 0;
472}
473
474/** Used with \a dmxInterateOverlap to print out a list of screens which
475 * overlap each other. */
476static void *
477dmxPrintOverlap(DMXScreenInfo * dmxScreen, void *closure)
478{
479 DMXScreenInfo *a = closure;
480
481 if (dmxScreen != a) {
482 if (dmxScreen->cursorNotShared)
483 dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name);
484 else
485 dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name);
486 }
487 return NULL;
488}
489
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. */
493static void *
494dmxIterateOverlap(DMXScreenInfo * start,
495 void *(*f) (DMXScreenInfo * dmxScreen, void *), void *closure)
496{
497 DMXScreenInfo *pt;
498
499 if (!start->over)
500 return f(start, closure);
501
502 for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
503 void *retval;
504
505 if ((retval = f(pt, closure)))
506 return retval;
507 if (pt == start)
508 break;
509 }
510 return NULL;
511}
512
513/** Used with #dmxPropertyIterate to determine if screen \a a is the
514 * same as the screen \a closure. */
515static void *
516dmxTestSameDisplay(DMXScreenInfo * a, void *closure)
517{
518 DMXScreenInfo *b = closure;
519
520 if (a == b)
521 return a;
522 return NULL;
523}
524
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 . */
529void
530dmxInitOverlap(void)
531{
532 int i, j;
533 DMXScreenInfo *a, *b, *pt;
534
535 for (i = 0; i < dmxNumScreens; i++)
536 dmxScreens[i].over = NULL;
537
538 for (i = 0; i < dmxNumScreens; i++) {
539 a = &dmxScreens[i];
540
541 for (j = i + 1; j < dmxNumScreens; j++) {
542 b = &dmxScreens[j];
543 if (b->over)
544 continue;
545
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);
550 a->over = b;
551 }
552 }
553 }
554
555 for (i = 0; i < dmxNumScreens; i++) {
556 a = &dmxScreens[i];
557
558 if (!a->over)
559 continue;
560
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
569 * ->over set. */
570 if (!dmxDoesOverlap(a, pt))
571 continue;
572 a->cursorNotShared = 1;
573 pt->cursorNotShared = 1;
574 dmxLog(dmxInfo,
575 "Screen %d and %d overlap on %s\n",
576 a->index, pt->index, a->name);
577 }
578 }
579 }
580
581 for (i = 0; i < dmxNumScreens; i++) {
582 a = &dmxScreens[i];
583
584 if (a->over) {
585 dmxLogOutput(a, "Overlaps");
586 dmxIterateOverlap(a, dmxPrintOverlap, a);
587 dmxLogOutputCont(a, "\n");
588 }
589 }
590}
591
592/** Create \a pCursor on the back-end associated with \a pScreen. */
593void
594dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor)
595{
596 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
597 dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
598 CursorBitsPtr pBits = pCursor->bits;
599 Pixmap src, msk;
600 XColor fg, bg;
601 XImage *img;
602 XlibGC gc = NULL;
603 XGCValues v;
604 unsigned long m;
605 int i;
606
607 if (!pCursorPriv)
608 return;
609
610 m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask;
611 v.function = GXcopy;
612 v.plane_mask = AllPlanes;
613 v.foreground = 1L;
614 v.background = 0L;
615 v.clip_mask = None;
616
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],
621 m, &v);
622 break;
623 }
624 }
625 if (!gc)
626 dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n");
627
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);
632
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);
638
639 XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0,
640 pBits->width, pBits->height);
641
642 XFree(img);
643
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);
649
650 XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0,
651 pBits->width, pBits->height);
652
653 XFree(img);
654
655 fg.red = pCursor->foreRed;
656 fg.green = pCursor->foreGreen;
657 fg.blue = pCursor->foreBlue;
658
659 bg.red = pCursor->backRed;
660 bg.green = pCursor->backGreen;
661 bg.blue = pCursor->backBlue;
662
663 pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay,
664 src, msk,
665 &fg, &bg,
666 pBits->xhot, pBits->yhot);
667
668 XFreePixmap(dmxScreen->beDisplay, src);
669 XFreePixmap(dmxScreen->beDisplay, msk);
670 XFreeGC(dmxScreen->beDisplay, gc);
671
672 dmxSync(dmxScreen, FALSE);
673}
674
675static Bool
676_dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
677{
678 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
679 dmxCursorPrivPtr pCursorPriv;
680
681 DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
682
683 DMX_SET_CURSOR_PRIV(pCursor, pScreen, malloc(sizeof(*pCursorPriv)));
684 if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen))
685 return FALSE;
686
687 pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
688 pCursorPriv->cursor = (Cursor) 0;
689
690 if (!dmxScreen->beDisplay)
691 return TRUE;
692
693 dmxBECreateCursor(pScreen, pCursor);
694 return TRUE;
695}
696
697/** Free \a pCursor on the back-end associated with \a pScreen. */
698Bool
699dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor)
700{
701 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
702 dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
703
704 if (pCursorPriv) {
705 XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor);
706 pCursorPriv->cursor = (Cursor) 0;
707 return TRUE;
708 }
709
710 return FALSE;
711}
712
713static Bool
714_dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
715{
716 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
717
718 DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
719
720 if (dmxScreen->beDisplay) {
721 if (dmxBEFreeCursor(pScreen, pCursor))
722 free(DMX_GET_CURSOR_PRIV(pCursor, pScreen));
723 }
724 DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL);
725
726 return TRUE;
727}
728
729static void
730_dmxMoveCursor(ScreenPtr pScreen, int x, int y)
731{
732 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
733 int newX = x + dmxScreen->rootX;
734 int newY = y + dmxScreen->rootY;
735
736 if (newX < 0)
737 newX = 0;
738 if (newY < 0)
739 newY = 0;
740
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);
747 }
748}
749
750static void
751_dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
752{
753 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
754
755 DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y);
756
757 if (pCursor) {
758 dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
759
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;
767 }
768 _dmxMoveCursor(pScreen, x, y);
769 }
770 else {
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;
777 }
778 if (dmxScreen->beDisplay)
779 dmxSync(dmxScreen, TRUE);
780}
781
782static Bool
783dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
784{
785 DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
786 DMXScreenInfo *pt;
787
788 if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
789 return _dmxRealizeCursor(pScreen, pCursor);
790
791 for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
792 if (pt->cursorNotShared)
793 continue;
794 _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor);
795 if (pt == start)
796 break;
797 }
798 return TRUE;
799}
800
801static Bool
802dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
803{
804 DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
805 DMXScreenInfo *pt;
806
807 if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
808 return _dmxUnrealizeCursor(pScreen, pCursor);
809
810 for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
811 if (pt->cursorNotShared)
812 continue;
813 _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor);
814 if (pt == start)
815 break;
816 }
817 return TRUE;
818}
819
820static CursorPtr
821dmxFindCursor(DMXScreenInfo * start)
822{
823 DMXScreenInfo *pt;
824
825 if (!start || !start->over)
826 return GetSpriteCursor(inputInfo.pointer);
827 for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
828 if (pt->cursor)
829 return pt->cursor;
830 if (pt == start)
831 break;
832 }
833 return GetSpriteCursor(inputInfo.pointer);
834}
835
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.
840 *
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.
844 */
845void
846dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
847{
848 DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
849 DMXScreenInfo *pt;
850
851 DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
852
853 if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
854 _dmxMoveCursor(pScreen, x, y);
855 return;
856 }
857
858 for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
859 if (pt->cursorNotShared)
860 continue;
861 if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
862 if ( /* pt != start && */ !pt->cursorVisible) {
863 if (!pt->cursor) {
864 /* This only happens during
865 * reconfiguration when a new overlap
866 * occurs. */
867 CursorPtr pCursor;
868
869 if ((pCursor = dmxFindCursor(start)))
870 _dmxRealizeCursor(screenInfo.screens[pt->index],
871 pt->cursor = pCursor);
872
873 }
874 _dmxSetCursor(screenInfo.screens[pt->index],
875 pt->cursor,
876 x + start->rootXOrigin - pt->rootXOrigin,
877 y + start->rootYOrigin - pt->rootYOrigin);
878 }
879 _dmxMoveCursor(screenInfo.screens[pt->index],
880 x + start->rootXOrigin - pt->rootXOrigin,
881 y + start->rootYOrigin - pt->rootYOrigin);
882 }
883 else if ( /* pt != start && */ pt->cursorVisible) {
884 _dmxSetCursor(screenInfo.screens[pt->index],
885 NULL,
886 x + start->rootXOrigin - pt->rootXOrigin,
887 y + start->rootYOrigin - pt->rootYOrigin);
888 }
889 if (pt == start)
890 break;
891 }
892}
893
894static void
895dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x,
896 int y)
897{
898 DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
899 DMXScreenInfo *pt;
900 int GX, GY, gx, gy;
901
902 DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n",
903 pScreen->myNum, start, pCursor, x, y);
904
905 /* We do this check here because of two cases:
906 *
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
911 * notion.
912 *
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
918 * shouldn't be. */
919
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);
925
926 if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
927 _dmxSetCursor(pScreen, pCursor, x, y);
928 return;
929 }
930
931 for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
932 if (pt->cursorNotShared)
933 continue;
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);
938 }
939 else {
940 _dmxSetCursor(screenInfo.screens[pt->index], NULL,
941 x + start->rootXOrigin - pt->rootXOrigin,
942 y + start->rootYOrigin - pt->rootYOrigin);
943 }
944 if (pt == start)
945 break;
946 }
947}
948
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
951 * dmxbackend.c */
952void
953dmxHideCursor(DMXScreenInfo * dmxScreen)
954{
955 int x, y;
956 ScreenPtr pScreen = screenInfo.screens[dmxScreen->index];
957
958 dmxGetGlobalPosition(&x, &y);
959 _dmxSetCursor(pScreen, NULL, x, y);
960}
961
962/** This routine is called during reconfiguration to make sure the
963 * cursor is visible. */
964void
965dmxCheckCursor(void)
966{
967 int i;
968 int x, y;
969 ScreenPtr pScreen;
970 DMXScreenInfo *firstScreen;
971
972 dmxGetGlobalPosition(&x, &y);
973 firstScreen = dmxFindFirstScreen(x, y);
974
975 DMXDBG2("dmxCheckCursor %d %d\n", x, y);
976 for (i = 0; i < dmxNumScreens; i++) {
977 DMXScreenInfo *dmxScreen = &dmxScreens[i];
978
979 pScreen = screenInfo.screens[dmxScreen->index];
980
981 if (!dmxOnScreen(x, y, dmxScreen)) {
982 if (firstScreen &&
983 i == miPointerGetScreen(inputInfo.pointer)->myNum)
984 miPointerSetScreen(inputInfo.pointer, firstScreen->index, x,
985 y);
986 _dmxSetCursor(pScreen, NULL, x - dmxScreen->rootXOrigin,
987 y - dmxScreen->rootYOrigin);
988 }
989 else {
990 if (!dmxScreen->cursor) {
991 CursorPtr pCursor;
992
993 if ((pCursor = dmxFindCursor(dmxScreen))) {
994 _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor);
995 }
996 }
997 _dmxSetCursor(pScreen, dmxScreen->cursor,
998 x - dmxScreen->rootXOrigin,
999 y - dmxScreen->rootYOrigin);
1000 }
1001 }
1002 DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y);
1003}
1004
1005static Bool
1006dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr)
1007{
1008 return TRUE;
1009}
1010
1011static void
1012dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr)
1013{
1014}
1015
1016miPointerSpriteFuncRec dmxPointerSpriteFuncs = {
1017 dmxRealizeCursor,
1018 dmxUnrealizeCursor,
1019 dmxSetCursor,
1020 dmxMoveCursor,
1021 dmxDeviceCursorInitialize,
1022 dmxDeviceCursorCleanup
1023};