Home | History | Annotate | Line # | Download | only in dmx
      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 (at) xfree86.org>
     31  *   Kevin E. Martin <kem (at) redhat.com>
     32  *   Rickard E. (Rik) Faith <faith (at) 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 {
    121     dmxCursorDoMultiCursors = 0;
    122 }
    123 
    124 static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
    125 {
    126     DMXScreenInfo *dmxScreen;
    127     int           i;
    128     int           localX = *x;
    129     int           localY = *y;
    130     int           globalX;
    131     int           globalY;
    132 
    133     if (screenInfo.numScreens == 1)
    134         return FALSE;
    135 
    136                                 /* On current screen? */
    137     dmxScreen = &dmxScreens[(*ppScreen)->myNum];
    138     if (localX >= 0
    139         && localX < dmxScreen->rootWidth
    140         && localY >= 0
    141         && localY < dmxScreen->rootHeight)
    142         return FALSE;
    143 
    144                                 /* Convert to global coordinate space */
    145     globalX = dmxScreen->rootXOrigin + localX;
    146     globalY = dmxScreen->rootYOrigin + localY;
    147 
    148                                 /* Is cursor on the current screen?
    149                                  * This efficiently exits this routine
    150                                  * for the most common case. */
    151     if (ppScreen && *ppScreen) {
    152         dmxScreen = &dmxScreens[(*ppScreen)->myNum];
    153         if (globalX >= dmxScreen->rootXOrigin
    154             && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
    155             && globalY >= dmxScreen->rootYOrigin
    156             && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight)
    157             return FALSE;
    158     }
    159 
    160                                 /* Find first screen cursor is on */
    161     for (i = 0; i < dmxNumScreens; i++) {
    162         dmxScreen = &dmxScreens[i];
    163         if (globalX >= dmxScreen->rootXOrigin
    164             && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
    165             && globalY >= dmxScreen->rootYOrigin
    166             && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) {
    167             if (dmxScreen->index == (*ppScreen)->myNum)
    168                 return FALSE;
    169             *ppScreen = screenInfo.screens[dmxScreen->index];
    170             *x        = globalX - dmxScreen->rootXOrigin;
    171             *y        = globalY - dmxScreen->rootYOrigin;
    172             return TRUE;
    173         }
    174     }
    175     return FALSE;
    176 }
    177 
    178 static void dmxCrossScreen(ScreenPtr pScreen, Bool entering)
    179 {
    180 }
    181 
    182 static void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
    183 {
    184     DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
    185 #if 11 /*BP*/
    186     /* This call is depracated.  Replace with???? */
    187     miPointerWarpCursor(pDev, pScreen, x, y);
    188 #else
    189     pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE);
    190 #endif
    191 }
    192 
    193 miPointerScreenFuncRec dmxPointerCursorFuncs =
    194 {
    195     dmxCursorOffScreen,
    196     dmxCrossScreen,
    197     dmxWarpCursor,
    198     NULL,
    199     NULL,
    200 };
    201 
    202 
    203 /** Create a list of screens that we'll manipulate. */
    204 static int *dmxSLCreate(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. */
    215 static void dmxSLFree(int *list)
    216 {
    217     free(list);
    218 }
    219 
    220 /** Find next uninitialized entry in list. */
    221 static int dmxSLFindNext(int *list)
    222 {
    223     int i;
    224     for (i = 0; i < dmxNumScreens; i++)
    225         if (list[i])
    226             return i;
    227     return -1;
    228 }
    229 
    230 /** Make one pass over all the screens and return the number updated. */
    231 static int dmxTryComputeScreenOrigins(int *screensLeft)
    232 {
    233     ScreenPtr       pScreen, refScreen;
    234     DMXScreenInfo   *screen;
    235     int             i, ref;
    236     int             changed = 0;
    237 
    238     for (i = 0; i < dmxNumScreens; i++) {
    239         if (!screensLeft[i])
    240             continue;
    241         screen  = &dmxScreens[i];
    242         pScreen = screenInfo.screens[i];
    243         switch (screen->where) {
    244         case PosAbsolute:
    245             pScreen->x = screen->whereX;
    246             pScreen->y = screen->whereY;
    247             ++changed, screensLeft[i] = 0;
    248             break;
    249         case PosRelative:
    250             ref = screen->whereRefScreen;
    251             if (screensLeft[ref])
    252                 break;
    253             refScreen = screenInfo.screens[ref];
    254             pScreen->x = refScreen->x + screen->whereX;
    255             pScreen->y = refScreen->y + screen->whereY;
    256             ++changed, screensLeft[i] = 0;
    257             break;
    258         case PosRightOf:
    259             ref = screen->whereRefScreen;
    260             if (screensLeft[ref])
    261                 break;
    262             refScreen = screenInfo.screens[ref];
    263             pScreen->x = refScreen->x + refScreen->width;
    264             pScreen->y = refScreen->y;
    265             ++changed, screensLeft[i] = 0;
    266             break;
    267         case PosLeftOf:
    268             ref = screen->whereRefScreen;
    269             if (screensLeft[ref])
    270                 break;
    271             refScreen = screenInfo.screens[ref];
    272             pScreen->x = refScreen->x - pScreen->width;
    273             pScreen->y = refScreen->y;
    274             ++changed, screensLeft[i] = 0;
    275             break;
    276         case PosBelow:
    277             ref = screen->whereRefScreen;
    278             if (screensLeft[ref])
    279                 break;
    280             refScreen = screenInfo.screens[ref];
    281             pScreen->x = refScreen->x;
    282             pScreen->y = refScreen->y + refScreen->height;
    283             ++changed, screensLeft[i] = 0;
    284             break;
    285         case PosAbove:
    286             ref = screen->whereRefScreen;
    287             if (screensLeft[ref])
    288                 break;
    289             refScreen = screenInfo.screens[ref];
    290             pScreen->x = refScreen->x;
    291             pScreen->y = refScreen->y - pScreen->height;
    292             ++changed, screensLeft[i] = 0;
    293             break;
    294         case PosNone:
    295             dmxLog(dmxFatal, "No position information for screen %d\n", i);
    296         }
    297     }
    298     return changed;
    299 }
    300 
    301 static void dmxComputeScreenOrigins(void)
    302 {
    303     ScreenPtr       pScreen;
    304     int             *screensLeft;
    305     int             i, ref;
    306     int             minX, minY;
    307 
    308                                 /* Compute origins based on
    309                                  * configuration information. */
    310     screensLeft = dmxSLCreate();
    311     while ((i = dmxSLFindNext(screensLeft)) >= 0) {
    312         while (dmxTryComputeScreenOrigins(screensLeft));
    313         if ((i = dmxSLFindNext(screensLeft)) >= 0) {
    314 	    /* All of the remaining screens are referencing each other.
    315 	     * Assign a value to one of them and go through again.  This
    316 	     * guarantees that we will eventually terminate.
    317 	     */
    318 	    ref                     = dmxScreens[i].whereRefScreen;
    319 	    pScreen                 = screenInfo.screens[ref];
    320 	    pScreen->x = pScreen->y = 0;
    321 	    screensLeft[ref]        = 0;
    322 	}
    323     }
    324     dmxSLFree(screensLeft);
    325 
    326 
    327                                 /* Justify the topmost and leftmost to
    328                                  * (0,0). */
    329     minX = screenInfo.screens[0]->x;
    330     minY = screenInfo.screens[0]->y;
    331     for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */
    332 	if (screenInfo.screens[i]->x < minX)
    333             minX = screenInfo.screens[i]->x;
    334 	if (screenInfo.screens[i]->y < minY)
    335             minY = screenInfo.screens[i]->y;
    336     }
    337     if (minX || minY) {
    338 	for (i = 0; i < dmxNumScreens; i++) {
    339 	    screenInfo.screens[i]->x -= minX;
    340 	    screenInfo.screens[i]->y -= minY;
    341 	}
    342     }
    343 }
    344 
    345 /** Recompute origin information in the #dmxScreens list.  This is
    346  * called from #dmxInitOrigins. */
    347 void dmxReInitOrigins(void)
    348 {
    349     int        i;
    350 
    351     if (dmxNumScreens > MAXSCREENS)
    352         dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
    353                dmxNumScreens, MAXSCREENS);
    354 
    355     for (i = 0; i < dmxNumScreens; i++) {
    356         DMXScreenInfo    *dmxScreen  = &dmxScreens[i];
    357         dmxLogOutput(dmxScreen,
    358                      "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d"
    359                      " (be=%dx%d depth=%d bpp=%d)\n",
    360                      dmxScreen->scrnWidth, dmxScreen->scrnHeight,
    361                      dmxScreen->scrnX, dmxScreen->scrnY,
    362 
    363                      dmxScreen->rootWidth, dmxScreen->rootHeight,
    364                      dmxScreen->rootX, dmxScreen->rootY,
    365 
    366                      dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
    367                      dmxScreen->beWidth, dmxScreen->beHeight,
    368                      dmxScreen->beDepth, dmxScreen->beBPP);
    369     }
    370 }
    371 
    372 /** Initialize screen origins (and relative position).  This is called
    373  * for each server generation.  For dynamic reconfiguration, use
    374  * #dmxReInitOrigins() instead. */
    375 void dmxInitOrigins(void)
    376 {
    377     int  i;
    378 
    379     if (dmxNumScreens > MAXSCREENS)
    380         dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
    381                dmxNumScreens, MAXSCREENS);
    382 
    383     for (i = 0; i < dmxNumScreens; i++) {
    384         DMXScreenInfo    *dmxScreen  = &dmxScreens[i];
    385         dmxLogOutput(dmxScreen,
    386                      "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)"
    387                      " (be=%dx%d depth=%d bpp=%d)\n",
    388                      dmxScreen->scrnWidth, dmxScreen->scrnHeight,
    389                      dmxScreen->scrnX, dmxScreen->scrnY,
    390 
    391                      dmxScreen->rootWidth, dmxScreen->rootHeight,
    392                      dmxScreen->rootX, dmxScreen->rootY,
    393 
    394                      dmxScreen->whereX, dmxScreen->whereY,
    395                      dmxScreen->where,
    396 
    397                      dmxScreen->beWidth, dmxScreen->beHeight,
    398                      dmxScreen->beDepth, dmxScreen->beBPP);
    399     }
    400 
    401     dmxComputeScreenOrigins();
    402 
    403     for (i = 0; i < dmxNumScreens; i++) {
    404         DMXScreenInfo  *dmxScreen = &dmxScreens[i];
    405         dmxScreen->rootXOrigin = screenInfo.screens[i]->x;
    406         dmxScreen->rootYOrigin = screenInfo.screens[i]->y;
    407     }
    408 
    409     dmxReInitOrigins();
    410 }
    411 
    412 /** Returns non-zero if the global \a x, \a y coordinate is on the
    413  * screen window of the \a dmxScreen. */
    414 int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen)
    415 {
    416 #if DMX_CURSOR_DEBUG > 1
    417     dmxLog(dmxDebug,
    418            "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n",
    419            dmxScreen->index, x, y,
    420            dmxScreen->rootWidth, dmxScreen->rootHeight,
    421            dmxScreen->rootX, dmxScreen->rootY,
    422            dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
    423            dmxScreen->scrnWidth, dmxScreen->scrnHeight,
    424            dmxScreen->scrnX, dmxScreen->scrnY);
    425 #endif
    426     if (x >= dmxScreen->rootXOrigin
    427         && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth
    428         && y >= dmxScreen->rootYOrigin
    429         && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1;
    430     return 0;
    431 }
    432 
    433 /** Returns non-zero if \a a overlaps \a b. */
    434 static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b)
    435 {
    436     if (dmxOnScreen(a->rootXOrigin,
    437                     a->rootYOrigin,                 b))
    438         return 1;
    439 
    440     if (dmxOnScreen(a->rootXOrigin,
    441                     a->rootYOrigin + a->scrnWidth,  b))
    442         return 1;
    443 
    444     if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
    445                     a->rootYOrigin,                 b))
    446         return 1;
    447 
    448     if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
    449                     a->rootYOrigin + a->scrnWidth,  b))
    450         return 1;
    451 
    452     if (dmxOnScreen(b->rootXOrigin,
    453                     b->rootYOrigin,                 a))
    454         return 1;
    455 
    456     if (dmxOnScreen(b->rootXOrigin,
    457                     b->rootYOrigin + b->scrnWidth,  a))
    458         return 1;
    459 
    460     if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
    461                     b->rootYOrigin,                 a))
    462         return 1;
    463 
    464     if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
    465                     b->rootYOrigin + b->scrnWidth,  a))
    466         return 1;
    467 
    468     return 0;
    469 }
    470 
    471 /** Used with \a dmxInterateOverlap to print out a list of screens which
    472  * overlap each other. */
    473 static void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure)
    474 {
    475     DMXScreenInfo *a = closure;
    476     if (dmxScreen != a) {
    477         if (dmxScreen->cursorNotShared)
    478             dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name);
    479         else
    480             dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name);
    481     }
    482     return NULL;
    483 }
    484 
    485 /** Iterate over the screens which overlap with the \a start screen,
    486  * calling \a f with the \a closure for each argument.  Often used with
    487  * #dmxPrintOverlap. */
    488 static void *dmxIterateOverlap(DMXScreenInfo *start,
    489                                void *(*f)(DMXScreenInfo *dmxScreen, void *),
    490                                void *closure)
    491 {
    492     DMXScreenInfo *pt;
    493 
    494     if (!start->over) return f(start, closure);
    495 
    496     for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
    497         void *retval;
    498         if ((retval = f(pt, closure))) return retval;
    499         if (pt == start) break;
    500     }
    501     return NULL;
    502 }
    503 
    504 /** Used with #dmxPropertyIterate to determine if screen \a a is the
    505  * same as the screen \a closure. */
    506 static void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure)
    507 {
    508     DMXScreenInfo *b = closure;
    509 
    510     if (a == b)
    511         return a;
    512     return NULL;
    513 }
    514 
    515 /** Detects overlapping dmxScreens and creates circular lists.  This
    516  * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and
    517  * the computation only needs to be performed for every server
    518  * generation or dynamic reconfiguration . */
    519 void dmxInitOverlap(void)
    520 {
    521     int           i, j;
    522     DMXScreenInfo *a, *b, *pt;
    523 
    524     for (i = 0; i < dmxNumScreens; i++)
    525         dmxScreens[i].over = NULL;
    526 
    527     for (i = 0; i < dmxNumScreens; i++) {
    528         a = &dmxScreens[i];
    529 
    530         for (j = i+1; j < dmxNumScreens; j++) {
    531             b = &dmxScreens[j];
    532             if (b->over)
    533                 continue;
    534 
    535             if (dmxDoesOverlap(a, b)) {
    536                 DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n",
    537                         a->index, b->index, a, a->over, b, b->over);
    538                 b->over = (a->over ? a->over : a);
    539                 a->over = b;
    540             }
    541         }
    542     }
    543 
    544     for (i = 0; i < dmxNumScreens; i++) {
    545         a = &dmxScreens[i];
    546 
    547         if (!a->over)
    548             continue;
    549 
    550                                 /* Flag all pairs that are on same display */
    551         for (pt = a->over; pt != a; pt = pt->over) {
    552             if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) {
    553                 /* The ->over sets contain the transitive set of screens
    554                  * that overlap.  For screens that are on the same
    555                  * backend display, we only want to exclude pairs of
    556                  * screens that mutually overlap on the backend display,
    557                  * so we call dmxDoesOverlap, which is stricter than the
    558                  * ->over set. */
    559                 if (!dmxDoesOverlap(a, pt))
    560                     continue;
    561                 a->cursorNotShared  = 1;
    562                 pt->cursorNotShared = 1;
    563                 dmxLog(dmxInfo,
    564                        "Screen %d and %d overlap on %s\n",
    565                        a->index, pt->index, a->name);
    566             }
    567         }
    568     }
    569 
    570     for (i = 0; i < dmxNumScreens; i++) {
    571         a = &dmxScreens[i];
    572 
    573         if (a->over) {
    574             dmxLogOutput(a, "Overlaps");
    575             dmxIterateOverlap(a, dmxPrintOverlap, a);
    576             dmxLogOutputCont(a, "\n");
    577         }
    578     }
    579 }
    580 
    581 /** Create \a pCursor on the back-end associated with \a pScreen. */
    582 void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor)
    583 {
    584     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
    585     dmxCursorPrivPtr  pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
    586     CursorBitsPtr     pBits = pCursor->bits;
    587     Pixmap            src, msk;
    588     XColor            fg, bg;
    589     XImage           *img;
    590     XlibGC            gc = NULL;
    591     XGCValues         v;
    592     unsigned long     m;
    593     int               i;
    594 
    595     if (!pCursorPriv)
    596 	return;
    597 
    598     m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask;
    599     v.function = GXcopy;
    600     v.plane_mask = AllPlanes;
    601     v.foreground = 1L;
    602     v.background = 0L;
    603     v.clip_mask = None;
    604 
    605     for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
    606 	if (dmxScreen->bePixmapFormats[i].depth == 1) {
    607 	    /* Create GC in the back-end servers */
    608 	    gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i],
    609 			   m, &v);
    610 	    break;
    611 	}
    612     }
    613     if (!gc)
    614         dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n");
    615 
    616     src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
    617 			pBits->width, pBits->height, 1);
    618     msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
    619 			pBits->width, pBits->height, 1);
    620 
    621     img = XCreateImage(dmxScreen->beDisplay,
    622 		       dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
    623 		       1, XYBitmap, 0, (char *)pBits->source,
    624 		       pBits->width, pBits->height,
    625 		       BitmapPad(dmxScreen->beDisplay), 0);
    626 
    627     XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0,
    628 	      pBits->width, pBits->height);
    629 
    630     XFree(img);
    631 
    632     img = XCreateImage(dmxScreen->beDisplay,
    633 		       dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
    634 		       1, XYBitmap, 0, (char *)pBits->mask,
    635 		       pBits->width, pBits->height,
    636 		       BitmapPad(dmxScreen->beDisplay), 0);
    637 
    638     XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0,
    639 	      pBits->width, pBits->height);
    640 
    641     XFree(img);
    642 
    643     fg.red   = pCursor->foreRed;
    644     fg.green = pCursor->foreGreen;
    645     fg.blue  = pCursor->foreBlue;
    646 
    647     bg.red   = pCursor->backRed;
    648     bg.green = pCursor->backGreen;
    649     bg.blue  = pCursor->backBlue;
    650 
    651     pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay,
    652 					      src, msk,
    653 					      &fg, &bg,
    654 					      pBits->xhot, pBits->yhot);
    655 
    656     XFreePixmap(dmxScreen->beDisplay, src);
    657     XFreePixmap(dmxScreen->beDisplay, msk);
    658     XFreeGC(dmxScreen->beDisplay, gc);
    659 
    660     dmxSync(dmxScreen, FALSE);
    661 }
    662 
    663 static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
    664 {
    665     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
    666     dmxCursorPrivPtr  pCursorPriv;
    667 
    668     DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
    669 
    670     DMX_SET_CURSOR_PRIV(pCursor, pScreen, malloc(sizeof(*pCursorPriv)));
    671     if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen))
    672 	return FALSE;
    673 
    674     pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
    675     pCursorPriv->cursor = (Cursor)0;
    676 
    677     if (!dmxScreen->beDisplay)
    678 	return TRUE;
    679 
    680     dmxBECreateCursor(pScreen, pCursor);
    681     return TRUE;
    682 }
    683 
    684 /** Free \a pCursor on the back-end associated with \a pScreen. */
    685 Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor)
    686 {
    687     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
    688     dmxCursorPrivPtr  pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
    689 
    690     if (pCursorPriv) {
    691 	XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor);
    692 	pCursorPriv->cursor = (Cursor)0;
    693 	return TRUE;
    694     }
    695 
    696     return FALSE;
    697 }
    698 
    699 static Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
    700 {
    701     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
    702 
    703     DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n",
    704             pScreen->myNum, pCursor);
    705 
    706     if (dmxScreen->beDisplay) {
    707 	if (dmxBEFreeCursor(pScreen, pCursor))
    708 	    free(DMX_GET_CURSOR_PRIV(pCursor, pScreen));
    709     }
    710     DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL);
    711 
    712     return TRUE;
    713 }
    714 
    715 static void _dmxMoveCursor(ScreenPtr pScreen, int x, int y)
    716 {
    717     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
    718     int           newX       = x + dmxScreen->rootX;
    719     int           newY       = y + dmxScreen->rootY;
    720 
    721     if (newX < 0) newX = 0;
    722     if (newY < 0) newY = 0;
    723 
    724     DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n",
    725             pScreen->myNum, x, y, newX, newY);
    726     if (dmxScreen->beDisplay) {
    727 	XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin,
    728 		     0, 0, 0, 0, newX, newY);
    729 	dmxSync(dmxScreen, TRUE);
    730     }
    731 }
    732 
    733 static void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
    734 {
    735     DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
    736 
    737     DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y);
    738 
    739     if (pCursor) {
    740 	dmxCursorPrivPtr  pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
    741 	if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) {
    742 	    if (dmxScreen->beDisplay)
    743 		XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
    744 			      pCursorPriv->cursor);
    745             dmxScreen->cursor        = pCursor;
    746 	    dmxScreen->curCursor     = pCursorPriv->cursor;
    747             dmxScreen->cursorVisible = 1;
    748 	}
    749 	_dmxMoveCursor(pScreen, x, y);
    750     } else {
    751 	if (dmxScreen->beDisplay)
    752 	    XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
    753 			  dmxScreen->noCursor);
    754         dmxScreen->cursor        = NULL;
    755 	dmxScreen->curCursor     = (Cursor)0;
    756         dmxScreen->cursorVisible = 0;
    757     }
    758     if (dmxScreen->beDisplay) dmxSync(dmxScreen, TRUE);
    759 }
    760 
    761 static Bool dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
    762 {
    763     DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
    764     DMXScreenInfo *pt;
    765 
    766     if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
    767         return _dmxRealizeCursor(pScreen, pCursor);
    768 
    769     for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
    770         if (pt->cursorNotShared)
    771             continue;
    772         _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor);
    773         if (pt == start)
    774             break;
    775     }
    776     return TRUE;
    777 }
    778 
    779 static Bool dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
    780 {
    781     DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
    782     DMXScreenInfo *pt;
    783 
    784     if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
    785         return _dmxUnrealizeCursor(pScreen, pCursor);
    786 
    787     for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
    788         if (pt->cursorNotShared)
    789             continue;
    790         _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor);
    791         if (pt == start)
    792             break;
    793     }
    794     return TRUE;
    795 }
    796 
    797 static CursorPtr dmxFindCursor(DMXScreenInfo *start)
    798 {
    799     DMXScreenInfo *pt;
    800 
    801     if (!start || !start->over)
    802         return GetSpriteCursor(inputInfo.pointer);
    803     for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
    804         if (pt->cursor)
    805             return pt->cursor;
    806         if (pt == start)
    807             break;
    808     }
    809     return GetSpriteCursor(inputInfo.pointer);
    810 }
    811 
    812 /** Move the cursor to coordinates (\a x, \a y)on \a pScreen.  This
    813  * function is usually called via #dmxPointerSpriteFuncs, except during
    814  * reconfiguration when the cursor is repositioned to force an update on
    815  * newley overlapping screens and on screens that no longer overlap.
    816  *
    817  * The coords (x,y) are in global coord space.  We'll loop over the
    818  * back-end screens and see if they contain the global coord.  If so, call
    819  * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen.
    820  */
    821 void dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
    822 {
    823     DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
    824     DMXScreenInfo *pt;
    825 
    826     DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
    827 
    828     if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
    829         _dmxMoveCursor(pScreen, x, y);
    830         return;
    831     }
    832 
    833     for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
    834         if (pt->cursorNotShared)
    835             continue;
    836         if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
    837             if (/* pt != start && */ !pt->cursorVisible) {
    838                 if (!pt->cursor) {
    839                                 /* This only happens during
    840                                  * reconfiguration when a new overlap
    841                                  * occurs. */
    842                     CursorPtr pCursor;
    843 
    844                     if ((pCursor = dmxFindCursor(start)))
    845                         _dmxRealizeCursor(screenInfo.screens[pt->index],
    846                                           pt->cursor = pCursor);
    847 
    848                 }
    849                 _dmxSetCursor(screenInfo.screens[pt->index],
    850                               pt->cursor,
    851                               x + start->rootXOrigin - pt->rootXOrigin,
    852                               y + start->rootYOrigin - pt->rootYOrigin);
    853             }
    854             _dmxMoveCursor(screenInfo.screens[pt->index],
    855                            x + start->rootXOrigin - pt->rootXOrigin,
    856                            y + start->rootYOrigin - pt->rootYOrigin);
    857         } else if (/* pt != start && */ pt->cursorVisible) {
    858             _dmxSetCursor(screenInfo.screens[pt->index],
    859                           NULL,
    860                           x + start->rootXOrigin - pt->rootXOrigin,
    861                           y + start->rootYOrigin - pt->rootYOrigin);
    862         }
    863         if (pt == start)
    864             break;
    865     }
    866 }
    867 
    868 static void dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
    869 {
    870     DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
    871     DMXScreenInfo *pt;
    872     int           GX, GY, gx, gy;
    873 
    874     DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n",
    875             pScreen->myNum, start, pCursor, x, y);
    876 
    877                                 /* We do this check here because of two cases:
    878                                  *
    879                                  * 1) if a client calls XWarpPointer()
    880                                  * and Xinerama is not running, we can
    881                                  * have mi's notion of the pointer
    882                                  * position out of phase with DMX's
    883                                  * notion.
    884                                  *
    885                                  * 2) if a down button is held while the
    886                                  * cursor moves outside the root window,
    887                                  * mi's notion of the pointer position
    888                                  * is out of phase with DMX's notion and
    889                                  * the cursor can remain visible when it
    890                                  * shouldn't be. */
    891 
    892     dmxGetGlobalPosition(&GX, &GY);
    893     gx = start->rootXOrigin + x;
    894     gy = start->rootYOrigin + y;
    895     if (x && y && (GX != gx || GY != gy))
    896         dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK);
    897 
    898     if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
    899         _dmxSetCursor(pScreen, pCursor, x, y);
    900         return;
    901     }
    902 
    903     for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
    904         if (pt->cursorNotShared)
    905             continue;
    906         if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
    907             _dmxSetCursor(screenInfo.screens[pt->index], pCursor,
    908                           x + start->rootXOrigin - pt->rootXOrigin,
    909                           y + start->rootYOrigin - pt->rootYOrigin);
    910         } else {
    911             _dmxSetCursor(screenInfo.screens[pt->index], NULL,
    912                           x + start->rootXOrigin - pt->rootXOrigin,
    913                           y + start->rootYOrigin - pt->rootYOrigin);
    914         }
    915         if (pt == start)
    916             break;
    917     }
    918 }
    919 
    920 
    921 /** This routine is used by the backend input routines to hide the
    922  * cursor on a screen that is being used for relative input.  \see
    923  * dmxbackend.c */
    924 void dmxHideCursor(DMXScreenInfo *dmxScreen)
    925 {
    926     int       x, y;
    927     ScreenPtr pScreen = screenInfo.screens[dmxScreen->index];
    928 
    929     dmxGetGlobalPosition(&x, &y);
    930     _dmxSetCursor(pScreen, NULL, x, y);
    931 }
    932 
    933 /** This routine is called during reconfiguration to make sure the
    934  * cursor is visible. */
    935 void dmxCheckCursor(void)
    936 {
    937     int           i;
    938     int           x, y;
    939     ScreenPtr     pScreen;
    940     DMXScreenInfo *firstScreen;
    941 
    942     dmxGetGlobalPosition(&x, &y);
    943     firstScreen = dmxFindFirstScreen(x, y);
    944 
    945     DMXDBG2("dmxCheckCursor %d %d\n", x, y);
    946     for (i = 0; i < dmxNumScreens; i++) {
    947         DMXScreenInfo *dmxScreen = &dmxScreens[i];
    948         pScreen                  = screenInfo.screens[dmxScreen->index];
    949 
    950         if (!dmxOnScreen(x, y, dmxScreen)) {
    951             if (firstScreen && i == miPointerGetScreen(inputInfo.pointer)->myNum)
    952                 miPointerSetScreen(inputInfo.pointer, firstScreen->index, x, y);
    953             _dmxSetCursor(pScreen, NULL,
    954                           x - dmxScreen->rootXOrigin,
    955                           y - dmxScreen->rootYOrigin);
    956         } else {
    957             if (!dmxScreen->cursor) {
    958                 CursorPtr pCursor;
    959 
    960                 if ((pCursor = dmxFindCursor(dmxScreen))) {
    961                     _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor);
    962                 }
    963             }
    964             _dmxSetCursor(pScreen, dmxScreen->cursor,
    965                           x - dmxScreen->rootXOrigin,
    966                           y - dmxScreen->rootYOrigin);
    967         }
    968     }
    969     DMXDBG2("   leave dmxCheckCursor %d %d\n", x, y);
    970 }
    971 
    972 static Bool dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr)
    973 {
    974     return TRUE;
    975 }
    976 
    977 static void dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr)
    978 {
    979 }
    980 
    981 miPointerSpriteFuncRec dmxPointerSpriteFuncs =
    982 {
    983     dmxRealizeCursor,
    984     dmxUnrealizeCursor,
    985     dmxSetCursor,
    986     dmxMoveCursor,
    987     dmxDeviceCursorInitialize,
    988     dmxDeviceCursorCleanup
    989 };
    990