xref: /OK3568_Linux_fs/external/xserver/hw/dmx/dmxcursor.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 
115 static int dmxCursorDoMultiCursors = 1;
116 
117 /** Turn off support for displaying multiple cursors on overlapped
118     back-end displays.  See #dmxCursorDoMultiCursors. */
119 void
dmxCursorNoMulti(void)120 dmxCursorNoMulti(void)
121 {
122     dmxCursorDoMultiCursors = 0;
123 }
124 
125 static Bool
dmxCursorOffScreen(ScreenPtr * ppScreen,int * x,int * y)126 dmxCursorOffScreen(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 
179 static void
dmxCrossScreen(ScreenPtr pScreen,Bool entering)180 dmxCrossScreen(ScreenPtr pScreen, Bool entering)
181 {
182 }
183 
184 static void
dmxWarpCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)185 dmxWarpCursor(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 
196 miPointerScreenFuncRec dmxPointerCursorFuncs = {
197     dmxCursorOffScreen,
198     dmxCrossScreen,
199     dmxWarpCursor,
200 };
201 
202 /** Create a list of screens that we'll manipulate. */
203 static int *
dmxSLCreate(void)204 dmxSLCreate(void)
205 {
206     int *list = xallocarray(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. */
215 static void
dmxSLFree(int * list)216 dmxSLFree(int *list)
217 {
218     free(list);
219 }
220 
221 /** Find next uninitialized entry in list. */
222 static int
dmxSLFindNext(int * list)223 dmxSLFindNext(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. */
234 static int
dmxTryComputeScreenOrigins(int * screensLeft)235 dmxTryComputeScreenOrigins(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 
305 static void
dmxComputeScreenOrigins(void)306 dmxComputeScreenOrigins(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. */
353 void
dmxReInitOrigins(void)354 dmxReInitOrigins(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. */
381 void
dmxInitOrigins(void)382 dmxInitOrigins(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. */
420 int
dmxOnScreen(int x,int y,DMXScreenInfo * dmxScreen)421 dmxOnScreen(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. */
442 static int
dmxDoesOverlap(DMXScreenInfo * a,DMXScreenInfo * b)443 dmxDoesOverlap(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. */
476 static void *
dmxPrintOverlap(DMXScreenInfo * dmxScreen,void * closure)477 dmxPrintOverlap(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. */
493 static void *
dmxIterateOverlap(DMXScreenInfo * start,void * (* f)(DMXScreenInfo * dmxScreen,void *),void * closure)494 dmxIterateOverlap(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. */
515 static void *
dmxTestSameDisplay(DMXScreenInfo * a,void * closure)516 dmxTestSameDisplay(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 . */
529 void
dmxInitOverlap(void)530 dmxInitOverlap(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. */
593 void
dmxBECreateCursor(ScreenPtr pScreen,CursorPtr pCursor)594 dmxBECreateCursor(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 
675 static Bool
_dmxRealizeCursor(ScreenPtr pScreen,CursorPtr pCursor)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. */
698 Bool
dmxBEFreeCursor(ScreenPtr pScreen,CursorPtr pCursor)699 dmxBEFreeCursor(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 
713 static Bool
_dmxUnrealizeCursor(ScreenPtr pScreen,CursorPtr pCursor)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 
729 static void
_dmxMoveCursor(ScreenPtr pScreen,int x,int y)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 
750 static void
_dmxSetCursor(ScreenPtr pScreen,CursorPtr pCursor,int x,int y)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 
782 static Bool
dmxRealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)783 dmxRealizeCursor(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 
801 static Bool
dmxUnrealizeCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)802 dmxUnrealizeCursor(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 
820 static CursorPtr
dmxFindCursor(DMXScreenInfo * start)821 dmxFindCursor(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  */
845 void
dmxMoveCursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)846 dmxMoveCursor(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 
894 static void
dmxSetCursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)895 dmxSetCursor(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 */
952 void
dmxHideCursor(DMXScreenInfo * dmxScreen)953 dmxHideCursor(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. */
964 void
dmxCheckCursor(void)965 dmxCheckCursor(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 
1005 static Bool
dmxDeviceCursorInitialize(DeviceIntPtr pDev,ScreenPtr pScr)1006 dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr)
1007 {
1008     return TRUE;
1009 }
1010 
1011 static void
dmxDeviceCursorCleanup(DeviceIntPtr pDev,ScreenPtr pScr)1012 dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr)
1013 {
1014 }
1015 
1016 miPointerSpriteFuncRec dmxPointerSpriteFuncs = {
1017     dmxRealizeCursor,
1018     dmxUnrealizeCursor,
1019     dmxSetCursor,
1020     dmxMoveCursor,
1021     dmxDeviceCursorInitialize,
1022     dmxDeviceCursorCleanup
1023 };
1024