1706f2543Smrg/*
2706f2543Smrg * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
3706f2543Smrg *
4706f2543Smrg * All Rights Reserved.
5706f2543Smrg *
6706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining
7706f2543Smrg * a copy of this software and associated documentation files (the
8706f2543Smrg * "Software"), to deal in the Software without restriction, including
9706f2543Smrg * without limitation on the rights to use, copy, modify, merge,
10706f2543Smrg * publish, distribute, sublicense, and/or sell copies of the Software,
11706f2543Smrg * and to permit persons to whom the Software is furnished to do so,
12706f2543Smrg * subject to the following conditions:
13706f2543Smrg *
14706f2543Smrg * The above copyright notice and this permission notice (including the
15706f2543Smrg * next paragraph) shall be included in all copies or substantial
16706f2543Smrg * portions of the Software.
17706f2543Smrg *
18706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19706f2543Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20706f2543Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21706f2543Smrg * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22706f2543Smrg * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23706f2543Smrg * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24706f2543Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25706f2543Smrg * SOFTWARE.
26706f2543Smrg */
27706f2543Smrg
28706f2543Smrg/*
29706f2543Smrg * Authors:
30706f2543Smrg *   David H. Dawes <dawes@xfree86.org>
31706f2543Smrg *   Kevin E. Martin <kem@redhat.com>
32706f2543Smrg *   Rickard E. (Rik) Faith <faith@redhat.com>
33706f2543Smrg *
34706f2543Smrg */
35706f2543Smrg
36706f2543Smrg/** \file
37706f2543Smrg * This file contains code than supports cursor movement, including the
38706f2543Smrg * code that initializes and reinitializes the screen positions and
39706f2543Smrg * computes screen overlap.
40706f2543Smrg *
41706f2543Smrg * "This code is based very closely on the XFree86 equivalent
42706f2543Smrg * (xfree86/common/xf86Cursor.c)."  --David Dawes.
43706f2543Smrg *
44706f2543Smrg * "This code was then extensively re-written, as explained here."
45706f2543Smrg * --Rik Faith
46706f2543Smrg *
47706f2543Smrg * The code in xf86Cursor.c used edge lists to implement the
48706f2543Smrg * CursorOffScreen function.  The edge list computation was complex
49706f2543Smrg * (especially in the face of arbitrarily overlapping screens) compared
50706f2543Smrg * with the speed savings in the CursorOffScreen function.  The new
51706f2543Smrg * implementation has erred on the side of correctness, readability, and
52706f2543Smrg * maintainability over efficiency.  For the common (non-edge) case, the
53706f2543Smrg * dmxCursorOffScreen function does avoid a loop over all the screens.
54706f2543Smrg * When the cursor has left the screen, all the screens are searched,
55706f2543Smrg * and the first screen (in dmxScreens order) containing the cursor will
56706f2543Smrg * be returned.  If run-time profiling shows that this routing is a
57706f2543Smrg * performance bottle-neck, then an edge list may have to be
58706f2543Smrg * reimplemented.  An edge list algorithm is O(edges) whereas the new
59706f2543Smrg * algorithm is O(dmxNumScreens).  Since edges is usually 1-3 and
60706f2543Smrg * dmxNumScreens may be 30-60 for large backend walls, this trade off
61706f2543Smrg * may be compelling.
62706f2543Smrg *
63706f2543Smrg * The xf86InitOrigins routine uses bit masks during the computation and
64706f2543Smrg * is therefore limited to the length of a word (e.g., 32 or 64 bits)
65706f2543Smrg * screens.  Because Xdmx is expected to be used with a large number of
66706f2543Smrg * backend displays, this limitation was removed.  The new
67706f2543Smrg * implementation has erred on the side of readability over efficiency,
68706f2543Smrg * using the dmxSL* routines to manage a screen list instead of a
69706f2543Smrg * bitmap, and a function call to decrease the length of the main
70706f2543Smrg * routine.  Both algorithms are of the same order, and both are called
71706f2543Smrg * only at server generation time, so trading clarity and long-term
72706f2543Smrg * maintainability for efficiency does not seem justified in this case.
73706f2543Smrg */
74706f2543Smrg
75706f2543Smrg#ifdef HAVE_DMX_CONFIG_H
76706f2543Smrg#include <dmx-config.h>
77706f2543Smrg#endif
78706f2543Smrg
79706f2543Smrg#define DMX_CURSOR_DEBUG 0
80706f2543Smrg
81706f2543Smrg#include "dmx.h"
82706f2543Smrg#include "dmxsync.h"
83706f2543Smrg#include "dmxcursor.h"
84706f2543Smrg#include "dmxlog.h"
85706f2543Smrg#include "dmxprop.h"
86706f2543Smrg#include "dmxinput.h"
87706f2543Smrg
88706f2543Smrg#include "mipointer.h"
89706f2543Smrg#include "windowstr.h"
90706f2543Smrg#include "globals.h"
91706f2543Smrg#include "cursorstr.h"
92706f2543Smrg#include "dixevents.h"          /* For GetSpriteCursor() */
93706f2543Smrg#include "inputstr.h"           /* for inputInfo.pointer */
94706f2543Smrg
95706f2543Smrg#if DMX_CURSOR_DEBUG
96706f2543Smrg#define DMXDBG0(f)               dmxLog(dmxDebug,f)
97706f2543Smrg#define DMXDBG1(f,a)             dmxLog(dmxDebug,f,a)
98706f2543Smrg#define DMXDBG2(f,a,b)           dmxLog(dmxDebug,f,a,b)
99706f2543Smrg#define DMXDBG3(f,a,b,c)         dmxLog(dmxDebug,f,a,b,c)
100706f2543Smrg#define DMXDBG4(f,a,b,c,d)       dmxLog(dmxDebug,f,a,b,c,d)
101706f2543Smrg#define DMXDBG5(f,a,b,c,d,e)     dmxLog(dmxDebug,f,a,b,c,d,e)
102706f2543Smrg#define DMXDBG6(f,a,b,c,d,e,g)   dmxLog(dmxDebug,f,a,b,c,d,e,g)
103706f2543Smrg#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
104706f2543Smrg#else
105706f2543Smrg#define DMXDBG0(f)
106706f2543Smrg#define DMXDBG1(f,a)
107706f2543Smrg#define DMXDBG2(f,a,b)
108706f2543Smrg#define DMXDBG3(f,a,b,c)
109706f2543Smrg#define DMXDBG4(f,a,b,c,d)
110706f2543Smrg#define DMXDBG5(f,a,b,c,d,e)
111706f2543Smrg#define DMXDBG6(f,a,b,c,d,e,g)
112706f2543Smrg#define DMXDBG7(f,a,b,c,d,e,g,h)
113706f2543Smrg#endif
114706f2543Smrg
115706f2543Smrgstatic int dmxCursorDoMultiCursors = 1;
116706f2543Smrg
117706f2543Smrg/** Turn off support for displaying multiple cursors on overlapped
118706f2543Smrg    back-end displays.  See #dmxCursorDoMultiCursors. */
119706f2543Smrgvoid dmxCursorNoMulti(void)
120706f2543Smrg{
121706f2543Smrg    dmxCursorDoMultiCursors = 0;
122706f2543Smrg}
123706f2543Smrg
124706f2543Smrgstatic Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
125706f2543Smrg{
126706f2543Smrg    DMXScreenInfo *dmxScreen;
127706f2543Smrg    int           i;
128706f2543Smrg    int           localX = *x;
129706f2543Smrg    int           localY = *y;
130706f2543Smrg    int           globalX;
131706f2543Smrg    int           globalY;
132706f2543Smrg
133706f2543Smrg    if (screenInfo.numScreens == 1)
134706f2543Smrg        return FALSE;
135706f2543Smrg
136706f2543Smrg                                /* On current screen? */
137706f2543Smrg    dmxScreen = &dmxScreens[(*ppScreen)->myNum];
138706f2543Smrg    if (localX >= 0
139706f2543Smrg        && localX < dmxScreen->rootWidth
140706f2543Smrg        && localY >= 0
141706f2543Smrg        && localY < dmxScreen->rootHeight)
142706f2543Smrg        return FALSE;
143706f2543Smrg
144706f2543Smrg                                /* Convert to global coordinate space */
145706f2543Smrg    globalX = dmxScreen->rootXOrigin + localX;
146706f2543Smrg    globalY = dmxScreen->rootYOrigin + localY;
147706f2543Smrg
148706f2543Smrg                                /* Is cursor on the current screen?
149706f2543Smrg                                 * This efficiently exits this routine
150706f2543Smrg                                 * for the most common case. */
151706f2543Smrg    if (ppScreen && *ppScreen) {
152706f2543Smrg        dmxScreen = &dmxScreens[(*ppScreen)->myNum];
153706f2543Smrg        if (globalX >= dmxScreen->rootXOrigin
154706f2543Smrg            && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
155706f2543Smrg            && globalY >= dmxScreen->rootYOrigin
156706f2543Smrg            && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight)
157706f2543Smrg            return FALSE;
158706f2543Smrg    }
159706f2543Smrg
160706f2543Smrg                                /* Find first screen cursor is on */
161706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
162706f2543Smrg        dmxScreen = &dmxScreens[i];
163706f2543Smrg        if (globalX >= dmxScreen->rootXOrigin
164706f2543Smrg            && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
165706f2543Smrg            && globalY >= dmxScreen->rootYOrigin
166706f2543Smrg            && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) {
167706f2543Smrg            if (dmxScreen->index == (*ppScreen)->myNum)
168706f2543Smrg                return FALSE;
169706f2543Smrg            *ppScreen = screenInfo.screens[dmxScreen->index];
170706f2543Smrg            *x        = globalX - dmxScreen->rootXOrigin;
171706f2543Smrg            *y        = globalY - dmxScreen->rootYOrigin;
172706f2543Smrg            return TRUE;
173706f2543Smrg        }
174706f2543Smrg    }
175706f2543Smrg    return FALSE;
176706f2543Smrg}
177706f2543Smrg
178706f2543Smrgstatic void dmxCrossScreen(ScreenPtr pScreen, Bool entering)
179706f2543Smrg{
180706f2543Smrg}
181706f2543Smrg
182706f2543Smrgstatic void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
183706f2543Smrg{
184706f2543Smrg    DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
185706f2543Smrg#if 11 /*BP*/
186706f2543Smrg    /* This call is depracated.  Replace with???? */
187706f2543Smrg    miPointerWarpCursor(pDev, pScreen, x, y);
188706f2543Smrg#else
189706f2543Smrg    pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE);
190706f2543Smrg#endif
191706f2543Smrg}
192706f2543Smrg
193706f2543SmrgmiPointerScreenFuncRec dmxPointerCursorFuncs =
194706f2543Smrg{
195706f2543Smrg    dmxCursorOffScreen,
196706f2543Smrg    dmxCrossScreen,
197706f2543Smrg    dmxWarpCursor,
198706f2543Smrg    NULL,
199706f2543Smrg    NULL,
200706f2543Smrg};
201706f2543Smrg
202706f2543Smrg
203706f2543Smrg/** Create a list of screens that we'll manipulate. */
204706f2543Smrgstatic int *dmxSLCreate(void)
205706f2543Smrg{
206706f2543Smrg    int *list = malloc(dmxNumScreens * sizeof(*list));
207706f2543Smrg    int i;
208706f2543Smrg
209706f2543Smrg    for (i = 0; i < dmxNumScreens; i++)
210706f2543Smrg        list[i] = 1;
211706f2543Smrg    return list;
212706f2543Smrg}
213706f2543Smrg
214706f2543Smrg/** Free list. */
215706f2543Smrgstatic void dmxSLFree(int *list)
216706f2543Smrg{
217706f2543Smrg    free(list);
218706f2543Smrg}
219706f2543Smrg
220706f2543Smrg/** Find next uninitialized entry in list. */
221706f2543Smrgstatic int dmxSLFindNext(int *list)
222706f2543Smrg{
223706f2543Smrg    int i;
224706f2543Smrg    for (i = 0; i < dmxNumScreens; i++)
225706f2543Smrg        if (list[i])
226706f2543Smrg            return i;
227706f2543Smrg    return -1;
228706f2543Smrg}
229706f2543Smrg
230706f2543Smrg/** Make one pass over all the screens and return the number updated. */
231706f2543Smrgstatic int dmxTryComputeScreenOrigins(int *screensLeft)
232706f2543Smrg{
233706f2543Smrg    ScreenPtr       pScreen, refScreen;
234706f2543Smrg    DMXScreenInfo   *screen;
235706f2543Smrg    int             i, ref;
236706f2543Smrg    int             changed = 0;
237706f2543Smrg
238706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
239706f2543Smrg        if (!screensLeft[i])
240706f2543Smrg            continue;
241706f2543Smrg        screen  = &dmxScreens[i];
242706f2543Smrg        pScreen = screenInfo.screens[i];
243706f2543Smrg        switch (screen->where) {
244706f2543Smrg        case PosAbsolute:
245706f2543Smrg            pScreen->x = screen->whereX;
246706f2543Smrg            pScreen->y = screen->whereY;
247706f2543Smrg            ++changed, screensLeft[i] = 0;
248706f2543Smrg            break;
249706f2543Smrg        case PosRelative:
250706f2543Smrg            ref = screen->whereRefScreen;
251706f2543Smrg            if (screensLeft[ref])
252706f2543Smrg                break;
253706f2543Smrg            refScreen = screenInfo.screens[ref];
254706f2543Smrg            pScreen->x = refScreen->x + screen->whereX;
255706f2543Smrg            pScreen->y = refScreen->y + screen->whereY;
256706f2543Smrg            ++changed, screensLeft[i] = 0;
257706f2543Smrg            break;
258706f2543Smrg        case PosRightOf:
259706f2543Smrg            ref = screen->whereRefScreen;
260706f2543Smrg            if (screensLeft[ref])
261706f2543Smrg                break;
262706f2543Smrg            refScreen = screenInfo.screens[ref];
263706f2543Smrg            pScreen->x = refScreen->x + refScreen->width;
264706f2543Smrg            pScreen->y = refScreen->y;
265706f2543Smrg            ++changed, screensLeft[i] = 0;
266706f2543Smrg            break;
267706f2543Smrg        case PosLeftOf:
268706f2543Smrg            ref = screen->whereRefScreen;
269706f2543Smrg            if (screensLeft[ref])
270706f2543Smrg                break;
271706f2543Smrg            refScreen = screenInfo.screens[ref];
272706f2543Smrg            pScreen->x = refScreen->x - pScreen->width;
273706f2543Smrg            pScreen->y = refScreen->y;
274706f2543Smrg            ++changed, screensLeft[i] = 0;
275706f2543Smrg            break;
276706f2543Smrg        case PosBelow:
277706f2543Smrg            ref = screen->whereRefScreen;
278706f2543Smrg            if (screensLeft[ref])
279706f2543Smrg                break;
280706f2543Smrg            refScreen = screenInfo.screens[ref];
281706f2543Smrg            pScreen->x = refScreen->x;
282706f2543Smrg            pScreen->y = refScreen->y + refScreen->height;
283706f2543Smrg            ++changed, screensLeft[i] = 0;
284706f2543Smrg            break;
285706f2543Smrg        case PosAbove:
286706f2543Smrg            ref = screen->whereRefScreen;
287706f2543Smrg            if (screensLeft[ref])
288706f2543Smrg                break;
289706f2543Smrg            refScreen = screenInfo.screens[ref];
290706f2543Smrg            pScreen->x = refScreen->x;
291706f2543Smrg            pScreen->y = refScreen->y - pScreen->height;
292706f2543Smrg            ++changed, screensLeft[i] = 0;
293706f2543Smrg            break;
294706f2543Smrg        case PosNone:
295706f2543Smrg            dmxLog(dmxFatal, "No position information for screen %d\n", i);
296706f2543Smrg        }
297706f2543Smrg    }
298706f2543Smrg    return changed;
299706f2543Smrg}
300706f2543Smrg
301706f2543Smrgstatic void dmxComputeScreenOrigins(void)
302706f2543Smrg{
303706f2543Smrg    ScreenPtr       pScreen;
304706f2543Smrg    int             *screensLeft;
305706f2543Smrg    int             i, ref;
306706f2543Smrg    int             minX, minY;
307706f2543Smrg
308706f2543Smrg                                /* Compute origins based on
309706f2543Smrg                                 * configuration information. */
310706f2543Smrg    screensLeft = dmxSLCreate();
311706f2543Smrg    while ((i = dmxSLFindNext(screensLeft)) >= 0) {
312706f2543Smrg        while (dmxTryComputeScreenOrigins(screensLeft));
313706f2543Smrg        if ((i = dmxSLFindNext(screensLeft)) >= 0) {
314706f2543Smrg	    /* All of the remaining screens are referencing each other.
315706f2543Smrg	     * Assign a value to one of them and go through again.  This
316706f2543Smrg	     * guarantees that we will eventually terminate.
317706f2543Smrg	     */
318706f2543Smrg	    ref                     = dmxScreens[i].whereRefScreen;
319706f2543Smrg	    pScreen                 = screenInfo.screens[ref];
320706f2543Smrg	    pScreen->x = pScreen->y = 0;
321706f2543Smrg	    screensLeft[ref]        = 0;
322706f2543Smrg	}
323706f2543Smrg    }
324706f2543Smrg    dmxSLFree(screensLeft);
325706f2543Smrg
326706f2543Smrg
327706f2543Smrg                                /* Justify the topmost and leftmost to
328706f2543Smrg                                 * (0,0). */
329706f2543Smrg    minX = screenInfo.screens[0]->x;
330706f2543Smrg    minY = screenInfo.screens[0]->y;
331706f2543Smrg    for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */
332706f2543Smrg	if (screenInfo.screens[i]->x < minX)
333706f2543Smrg            minX = screenInfo.screens[i]->x;
334706f2543Smrg	if (screenInfo.screens[i]->y < minY)
335706f2543Smrg            minY = screenInfo.screens[i]->y;
336706f2543Smrg    }
337706f2543Smrg    if (minX || minY) {
338706f2543Smrg	for (i = 0; i < dmxNumScreens; i++) {
339706f2543Smrg	    screenInfo.screens[i]->x -= minX;
340706f2543Smrg	    screenInfo.screens[i]->y -= minY;
341706f2543Smrg	}
342706f2543Smrg    }
343706f2543Smrg}
344706f2543Smrg
345706f2543Smrg/** Recompute origin information in the #dmxScreens list.  This is
346706f2543Smrg * called from #dmxInitOrigins. */
347706f2543Smrgvoid dmxReInitOrigins(void)
348706f2543Smrg{
349706f2543Smrg    int        i;
350706f2543Smrg
351706f2543Smrg    if (dmxNumScreens > MAXSCREENS)
352706f2543Smrg        dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
353706f2543Smrg               dmxNumScreens, MAXSCREENS);
354706f2543Smrg
355706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
356706f2543Smrg        DMXScreenInfo    *dmxScreen  = &dmxScreens[i];
357706f2543Smrg        dmxLogOutput(dmxScreen,
358706f2543Smrg                     "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d"
359706f2543Smrg                     " (be=%dx%d depth=%d bpp=%d)\n",
360706f2543Smrg                     dmxScreen->scrnWidth, dmxScreen->scrnHeight,
361706f2543Smrg                     dmxScreen->scrnX, dmxScreen->scrnY,
362706f2543Smrg
363706f2543Smrg                     dmxScreen->rootWidth, dmxScreen->rootHeight,
364706f2543Smrg                     dmxScreen->rootX, dmxScreen->rootY,
365706f2543Smrg
366706f2543Smrg                     dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
367706f2543Smrg                     dmxScreen->beWidth, dmxScreen->beHeight,
368706f2543Smrg                     dmxScreen->beDepth, dmxScreen->beBPP);
369706f2543Smrg    }
370706f2543Smrg}
371706f2543Smrg
372706f2543Smrg/** Initialize screen origins (and relative position).  This is called
373706f2543Smrg * for each server generation.  For dynamic reconfiguration, use
374706f2543Smrg * #dmxReInitOrigins() instead. */
375706f2543Smrgvoid dmxInitOrigins(void)
376706f2543Smrg{
377706f2543Smrg    int  i;
378706f2543Smrg
379706f2543Smrg    if (dmxNumScreens > MAXSCREENS)
380706f2543Smrg        dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
381706f2543Smrg               dmxNumScreens, MAXSCREENS);
382706f2543Smrg
383706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
384706f2543Smrg        DMXScreenInfo    *dmxScreen  = &dmxScreens[i];
385706f2543Smrg        dmxLogOutput(dmxScreen,
386706f2543Smrg                     "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)"
387706f2543Smrg                     " (be=%dx%d depth=%d bpp=%d)\n",
388706f2543Smrg                     dmxScreen->scrnWidth, dmxScreen->scrnHeight,
389706f2543Smrg                     dmxScreen->scrnX, dmxScreen->scrnY,
390706f2543Smrg
391706f2543Smrg                     dmxScreen->rootWidth, dmxScreen->rootHeight,
392706f2543Smrg                     dmxScreen->rootX, dmxScreen->rootY,
393706f2543Smrg
394706f2543Smrg                     dmxScreen->whereX, dmxScreen->whereY,
395706f2543Smrg                     dmxScreen->where,
396706f2543Smrg
397706f2543Smrg                     dmxScreen->beWidth, dmxScreen->beHeight,
398706f2543Smrg                     dmxScreen->beDepth, dmxScreen->beBPP);
399706f2543Smrg    }
400706f2543Smrg
401706f2543Smrg    dmxComputeScreenOrigins();
402706f2543Smrg
403706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
404706f2543Smrg        DMXScreenInfo  *dmxScreen = &dmxScreens[i];
405706f2543Smrg        dmxScreen->rootXOrigin = screenInfo.screens[i]->x;
406706f2543Smrg        dmxScreen->rootYOrigin = screenInfo.screens[i]->y;
407706f2543Smrg    }
408706f2543Smrg
409706f2543Smrg    dmxReInitOrigins();
410706f2543Smrg}
411706f2543Smrg
412706f2543Smrg/** Returns non-zero if the global \a x, \a y coordinate is on the
413706f2543Smrg * screen window of the \a dmxScreen. */
414706f2543Smrgint dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen)
415706f2543Smrg{
416706f2543Smrg#if DMX_CURSOR_DEBUG > 1
417706f2543Smrg    dmxLog(dmxDebug,
418706f2543Smrg           "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n",
419706f2543Smrg           dmxScreen->index, x, y,
420706f2543Smrg           dmxScreen->rootWidth, dmxScreen->rootHeight,
421706f2543Smrg           dmxScreen->rootX, dmxScreen->rootY,
422706f2543Smrg           dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
423706f2543Smrg           dmxScreen->scrnWidth, dmxScreen->scrnHeight,
424706f2543Smrg           dmxScreen->scrnX, dmxScreen->scrnY);
425706f2543Smrg#endif
426706f2543Smrg    if (x >= dmxScreen->rootXOrigin
427706f2543Smrg        && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth
428706f2543Smrg        && y >= dmxScreen->rootYOrigin
429706f2543Smrg        && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1;
430706f2543Smrg    return 0;
431706f2543Smrg}
432706f2543Smrg
433706f2543Smrg/** Returns non-zero if \a a overlaps \a b. */
434706f2543Smrgstatic int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b)
435706f2543Smrg{
436706f2543Smrg    if (dmxOnScreen(a->rootXOrigin,
437706f2543Smrg                    a->rootYOrigin,                 b))
438706f2543Smrg        return 1;
439706f2543Smrg
440706f2543Smrg    if (dmxOnScreen(a->rootXOrigin,
441706f2543Smrg                    a->rootYOrigin + a->scrnWidth,  b))
442706f2543Smrg        return 1;
443706f2543Smrg
444706f2543Smrg    if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
445706f2543Smrg                    a->rootYOrigin,                 b))
446706f2543Smrg        return 1;
447706f2543Smrg
448706f2543Smrg    if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
449706f2543Smrg                    a->rootYOrigin + a->scrnWidth,  b))
450706f2543Smrg        return 1;
451706f2543Smrg
452706f2543Smrg    if (dmxOnScreen(b->rootXOrigin,
453706f2543Smrg                    b->rootYOrigin,                 a))
454706f2543Smrg        return 1;
455706f2543Smrg
456706f2543Smrg    if (dmxOnScreen(b->rootXOrigin,
457706f2543Smrg                    b->rootYOrigin + b->scrnWidth,  a))
458706f2543Smrg        return 1;
459706f2543Smrg
460706f2543Smrg    if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
461706f2543Smrg                    b->rootYOrigin,                 a))
462706f2543Smrg        return 1;
463706f2543Smrg
464706f2543Smrg    if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
465706f2543Smrg                    b->rootYOrigin + b->scrnWidth,  a))
466706f2543Smrg        return 1;
467706f2543Smrg
468706f2543Smrg    return 0;
469706f2543Smrg}
470706f2543Smrg
471706f2543Smrg/** Used with \a dmxInterateOverlap to print out a list of screens which
472706f2543Smrg * overlap each other. */
473706f2543Smrgstatic void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure)
474706f2543Smrg{
475706f2543Smrg    DMXScreenInfo *a = closure;
476706f2543Smrg    if (dmxScreen != a) {
477706f2543Smrg        if (dmxScreen->cursorNotShared)
478706f2543Smrg            dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name);
479706f2543Smrg        else
480706f2543Smrg            dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name);
481706f2543Smrg    }
482706f2543Smrg    return NULL;
483706f2543Smrg}
484706f2543Smrg
485706f2543Smrg/** Iterate over the screens which overlap with the \a start screen,
486706f2543Smrg * calling \a f with the \a closure for each argument.  Often used with
487706f2543Smrg * #dmxPrintOverlap. */
488706f2543Smrgstatic void *dmxIterateOverlap(DMXScreenInfo *start,
489706f2543Smrg                               void *(*f)(DMXScreenInfo *dmxScreen, void *),
490706f2543Smrg                               void *closure)
491706f2543Smrg{
492706f2543Smrg    DMXScreenInfo *pt;
493706f2543Smrg
494706f2543Smrg    if (!start->over) return f(start, closure);
495706f2543Smrg
496706f2543Smrg    for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
497706f2543Smrg        void *retval;
498706f2543Smrg        if ((retval = f(pt, closure))) return retval;
499706f2543Smrg        if (pt == start) break;
500706f2543Smrg    }
501706f2543Smrg    return NULL;
502706f2543Smrg}
503706f2543Smrg
504706f2543Smrg/** Used with #dmxPropertyIterate to determine if screen \a a is the
505706f2543Smrg * same as the screen \a closure. */
506706f2543Smrgstatic void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure)
507706f2543Smrg{
508706f2543Smrg    DMXScreenInfo *b = closure;
509706f2543Smrg
510706f2543Smrg    if (a == b)
511706f2543Smrg        return a;
512706f2543Smrg    return NULL;
513706f2543Smrg}
514706f2543Smrg
515706f2543Smrg/** Detects overlapping dmxScreens and creates circular lists.  This
516706f2543Smrg * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and
517706f2543Smrg * the computation only needs to be performed for every server
518706f2543Smrg * generation or dynamic reconfiguration . */
519706f2543Smrgvoid dmxInitOverlap(void)
520706f2543Smrg{
521706f2543Smrg    int           i, j;
522706f2543Smrg    DMXScreenInfo *a, *b, *pt;
523706f2543Smrg
524706f2543Smrg    for (i = 0; i < dmxNumScreens; i++)
525706f2543Smrg        dmxScreens[i].over = NULL;
526706f2543Smrg
527706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
528706f2543Smrg        a = &dmxScreens[i];
529706f2543Smrg
530706f2543Smrg        for (j = i+1; j < dmxNumScreens; j++) {
531706f2543Smrg            b = &dmxScreens[j];
532706f2543Smrg            if (b->over)
533706f2543Smrg                continue;
534706f2543Smrg
535706f2543Smrg            if (dmxDoesOverlap(a, b)) {
536706f2543Smrg                DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n",
537706f2543Smrg                        a->index, b->index, a, a->over, b, b->over);
538706f2543Smrg                b->over = (a->over ? a->over : a);
539706f2543Smrg                a->over = b;
540706f2543Smrg            }
541706f2543Smrg        }
542706f2543Smrg    }
543706f2543Smrg
544706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
545706f2543Smrg        a = &dmxScreens[i];
546706f2543Smrg
547706f2543Smrg        if (!a->over)
548706f2543Smrg            continue;
549706f2543Smrg
550706f2543Smrg                                /* Flag all pairs that are on same display */
551706f2543Smrg        for (pt = a->over; pt != a; pt = pt->over) {
552706f2543Smrg            if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) {
553706f2543Smrg                /* The ->over sets contain the transitive set of screens
554706f2543Smrg                 * that overlap.  For screens that are on the same
555706f2543Smrg                 * backend display, we only want to exclude pairs of
556706f2543Smrg                 * screens that mutually overlap on the backend display,
557706f2543Smrg                 * so we call dmxDoesOverlap, which is stricter than the
558706f2543Smrg                 * ->over set. */
559706f2543Smrg                if (!dmxDoesOverlap(a, pt))
560706f2543Smrg                    continue;
561706f2543Smrg                a->cursorNotShared  = 1;
562706f2543Smrg                pt->cursorNotShared = 1;
563706f2543Smrg                dmxLog(dmxInfo,
564706f2543Smrg                       "Screen %d and %d overlap on %s\n",
565706f2543Smrg                       a->index, pt->index, a->name);
566706f2543Smrg            }
567706f2543Smrg        }
568706f2543Smrg    }
569706f2543Smrg
570706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
571706f2543Smrg        a = &dmxScreens[i];
572706f2543Smrg
573706f2543Smrg        if (a->over) {
574706f2543Smrg            dmxLogOutput(a, "Overlaps");
575706f2543Smrg            dmxIterateOverlap(a, dmxPrintOverlap, a);
576706f2543Smrg            dmxLogOutputCont(a, "\n");
577706f2543Smrg        }
578706f2543Smrg    }
579706f2543Smrg}
580706f2543Smrg
581706f2543Smrg/** Create \a pCursor on the back-end associated with \a pScreen. */
582706f2543Smrgvoid dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor)
583706f2543Smrg{
584706f2543Smrg    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
585706f2543Smrg    dmxCursorPrivPtr  pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
586706f2543Smrg    CursorBitsPtr     pBits = pCursor->bits;
587706f2543Smrg    Pixmap            src, msk;
588706f2543Smrg    XColor            fg, bg;
589706f2543Smrg    XImage           *img;
590706f2543Smrg    XlibGC            gc = NULL;
591706f2543Smrg    XGCValues         v;
592706f2543Smrg    unsigned long     m;
593706f2543Smrg    int               i;
594706f2543Smrg
595706f2543Smrg    if (!pCursorPriv)
596706f2543Smrg	return;
597706f2543Smrg
598706f2543Smrg    m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask;
599706f2543Smrg    v.function = GXcopy;
600706f2543Smrg    v.plane_mask = AllPlanes;
601706f2543Smrg    v.foreground = 1L;
602706f2543Smrg    v.background = 0L;
603706f2543Smrg    v.clip_mask = None;
604706f2543Smrg
605706f2543Smrg    for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
606706f2543Smrg	if (dmxScreen->bePixmapFormats[i].depth == 1) {
607706f2543Smrg	    /* Create GC in the back-end servers */
608706f2543Smrg	    gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i],
609706f2543Smrg			   m, &v);
610706f2543Smrg	    break;
611706f2543Smrg	}
612706f2543Smrg    }
613706f2543Smrg    if (!gc)
614706f2543Smrg        dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n");
615706f2543Smrg
616706f2543Smrg    src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
617706f2543Smrg			pBits->width, pBits->height, 1);
618706f2543Smrg    msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
619706f2543Smrg			pBits->width, pBits->height, 1);
620706f2543Smrg
621706f2543Smrg    img = XCreateImage(dmxScreen->beDisplay,
622706f2543Smrg		       dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
623706f2543Smrg		       1, XYBitmap, 0, (char *)pBits->source,
624706f2543Smrg		       pBits->width, pBits->height,
625706f2543Smrg		       BitmapPad(dmxScreen->beDisplay), 0);
626706f2543Smrg
627706f2543Smrg    XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0,
628706f2543Smrg	      pBits->width, pBits->height);
629706f2543Smrg
630706f2543Smrg    XFree(img);
631706f2543Smrg
632706f2543Smrg    img = XCreateImage(dmxScreen->beDisplay,
633706f2543Smrg		       dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
634706f2543Smrg		       1, XYBitmap, 0, (char *)pBits->mask,
635706f2543Smrg		       pBits->width, pBits->height,
636706f2543Smrg		       BitmapPad(dmxScreen->beDisplay), 0);
637706f2543Smrg
638706f2543Smrg    XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0,
639706f2543Smrg	      pBits->width, pBits->height);
640706f2543Smrg
641706f2543Smrg    XFree(img);
642706f2543Smrg
643706f2543Smrg    fg.red   = pCursor->foreRed;
644706f2543Smrg    fg.green = pCursor->foreGreen;
645706f2543Smrg    fg.blue  = pCursor->foreBlue;
646706f2543Smrg
647706f2543Smrg    bg.red   = pCursor->backRed;
648706f2543Smrg    bg.green = pCursor->backGreen;
649706f2543Smrg    bg.blue  = pCursor->backBlue;
650706f2543Smrg
651706f2543Smrg    pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay,
652706f2543Smrg					      src, msk,
653706f2543Smrg					      &fg, &bg,
654706f2543Smrg					      pBits->xhot, pBits->yhot);
655706f2543Smrg
656706f2543Smrg    XFreePixmap(dmxScreen->beDisplay, src);
657706f2543Smrg    XFreePixmap(dmxScreen->beDisplay, msk);
658706f2543Smrg    XFreeGC(dmxScreen->beDisplay, gc);
659706f2543Smrg
660706f2543Smrg    dmxSync(dmxScreen, FALSE);
661706f2543Smrg}
662706f2543Smrg
663706f2543Smrgstatic Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
664706f2543Smrg{
665706f2543Smrg    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
666706f2543Smrg    dmxCursorPrivPtr  pCursorPriv;
667706f2543Smrg
668706f2543Smrg    DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
669706f2543Smrg
670706f2543Smrg    DMX_SET_CURSOR_PRIV(pCursor, pScreen, malloc(sizeof(*pCursorPriv)));
671706f2543Smrg    if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen))
672706f2543Smrg	return FALSE;
673706f2543Smrg
674706f2543Smrg    pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
675706f2543Smrg    pCursorPriv->cursor = (Cursor)0;
676706f2543Smrg
677706f2543Smrg    if (!dmxScreen->beDisplay)
678706f2543Smrg	return TRUE;
679706f2543Smrg
680706f2543Smrg    dmxBECreateCursor(pScreen, pCursor);
681706f2543Smrg    return TRUE;
682706f2543Smrg}
683706f2543Smrg
684706f2543Smrg/** Free \a pCursor on the back-end associated with \a pScreen. */
685706f2543SmrgBool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor)
686706f2543Smrg{
687706f2543Smrg    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
688706f2543Smrg    dmxCursorPrivPtr  pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
689706f2543Smrg
690706f2543Smrg    if (pCursorPriv) {
691706f2543Smrg	XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor);
692706f2543Smrg	pCursorPriv->cursor = (Cursor)0;
693706f2543Smrg	return TRUE;
694706f2543Smrg    }
695706f2543Smrg
696706f2543Smrg    return FALSE;
697706f2543Smrg}
698706f2543Smrg
699706f2543Smrgstatic Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
700706f2543Smrg{
701706f2543Smrg    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
702706f2543Smrg
703706f2543Smrg    DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n",
704706f2543Smrg            pScreen->myNum, pCursor);
705706f2543Smrg
706706f2543Smrg    if (dmxScreen->beDisplay) {
707706f2543Smrg	if (dmxBEFreeCursor(pScreen, pCursor))
708706f2543Smrg	    free(DMX_GET_CURSOR_PRIV(pCursor, pScreen));
709706f2543Smrg    }
710706f2543Smrg    DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL);
711706f2543Smrg
712706f2543Smrg    return TRUE;
713706f2543Smrg}
714706f2543Smrg
715706f2543Smrgstatic void _dmxMoveCursor(ScreenPtr pScreen, int x, int y)
716706f2543Smrg{
717706f2543Smrg    DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
718706f2543Smrg    int           newX       = x + dmxScreen->rootX;
719706f2543Smrg    int           newY       = y + dmxScreen->rootY;
720706f2543Smrg
721706f2543Smrg    if (newX < 0) newX = 0;
722706f2543Smrg    if (newY < 0) newY = 0;
723706f2543Smrg
724706f2543Smrg    DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n",
725706f2543Smrg            pScreen->myNum, x, y, newX, newY);
726706f2543Smrg    if (dmxScreen->beDisplay) {
727706f2543Smrg	XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin,
728706f2543Smrg		     0, 0, 0, 0, newX, newY);
729706f2543Smrg	dmxSync(dmxScreen, TRUE);
730706f2543Smrg    }
731706f2543Smrg}
732706f2543Smrg
733706f2543Smrgstatic void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
734706f2543Smrg{
735706f2543Smrg    DMXScreenInfo    *dmxScreen = &dmxScreens[pScreen->myNum];
736706f2543Smrg
737706f2543Smrg    DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y);
738706f2543Smrg
739706f2543Smrg    if (pCursor) {
740706f2543Smrg	dmxCursorPrivPtr  pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
741706f2543Smrg	if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) {
742706f2543Smrg	    if (dmxScreen->beDisplay)
743706f2543Smrg		XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
744706f2543Smrg			      pCursorPriv->cursor);
745706f2543Smrg            dmxScreen->cursor        = pCursor;
746706f2543Smrg	    dmxScreen->curCursor     = pCursorPriv->cursor;
747706f2543Smrg            dmxScreen->cursorVisible = 1;
748706f2543Smrg	}
749706f2543Smrg	_dmxMoveCursor(pScreen, x, y);
750706f2543Smrg    } else {
751706f2543Smrg	if (dmxScreen->beDisplay)
752706f2543Smrg	    XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
753706f2543Smrg			  dmxScreen->noCursor);
754706f2543Smrg        dmxScreen->cursor        = NULL;
755706f2543Smrg	dmxScreen->curCursor     = (Cursor)0;
756706f2543Smrg        dmxScreen->cursorVisible = 0;
757706f2543Smrg    }
758706f2543Smrg    if (dmxScreen->beDisplay) dmxSync(dmxScreen, TRUE);
759706f2543Smrg}
760706f2543Smrg
761706f2543Smrgstatic Bool dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
762706f2543Smrg{
763706f2543Smrg    DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
764706f2543Smrg    DMXScreenInfo *pt;
765706f2543Smrg
766706f2543Smrg    if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
767706f2543Smrg        return _dmxRealizeCursor(pScreen, pCursor);
768706f2543Smrg
769706f2543Smrg    for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
770706f2543Smrg        if (pt->cursorNotShared)
771706f2543Smrg            continue;
772706f2543Smrg        _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor);
773706f2543Smrg        if (pt == start)
774706f2543Smrg            break;
775706f2543Smrg    }
776706f2543Smrg    return TRUE;
777706f2543Smrg}
778706f2543Smrg
779706f2543Smrgstatic Bool dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
780706f2543Smrg{
781706f2543Smrg    DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
782706f2543Smrg    DMXScreenInfo *pt;
783706f2543Smrg
784706f2543Smrg    if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
785706f2543Smrg        return _dmxUnrealizeCursor(pScreen, pCursor);
786706f2543Smrg
787706f2543Smrg    for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
788706f2543Smrg        if (pt->cursorNotShared)
789706f2543Smrg            continue;
790706f2543Smrg        _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor);
791706f2543Smrg        if (pt == start)
792706f2543Smrg            break;
793706f2543Smrg    }
794706f2543Smrg    return TRUE;
795706f2543Smrg}
796706f2543Smrg
797706f2543Smrgstatic CursorPtr dmxFindCursor(DMXScreenInfo *start)
798706f2543Smrg{
799706f2543Smrg    DMXScreenInfo *pt;
800706f2543Smrg
801706f2543Smrg    if (!start || !start->over)
802706f2543Smrg        return GetSpriteCursor(inputInfo.pointer);
803706f2543Smrg    for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
804706f2543Smrg        if (pt->cursor)
805706f2543Smrg            return pt->cursor;
806706f2543Smrg        if (pt == start)
807706f2543Smrg            break;
808706f2543Smrg    }
809706f2543Smrg    return GetSpriteCursor(inputInfo.pointer);
810706f2543Smrg}
811706f2543Smrg
812706f2543Smrg/** Move the cursor to coordinates (\a x, \a y)on \a pScreen.  This
813706f2543Smrg * function is usually called via #dmxPointerSpriteFuncs, except during
814706f2543Smrg * reconfiguration when the cursor is repositioned to force an update on
815706f2543Smrg * newley overlapping screens and on screens that no longer overlap.
816706f2543Smrg *
817706f2543Smrg * The coords (x,y) are in global coord space.  We'll loop over the
818706f2543Smrg * back-end screens and see if they contain the global coord.  If so, call
819706f2543Smrg * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen.
820706f2543Smrg */
821706f2543Smrgvoid dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
822706f2543Smrg{
823706f2543Smrg    DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
824706f2543Smrg    DMXScreenInfo *pt;
825706f2543Smrg
826706f2543Smrg    DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
827706f2543Smrg
828706f2543Smrg    if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
829706f2543Smrg        _dmxMoveCursor(pScreen, x, y);
830706f2543Smrg        return;
831706f2543Smrg    }
832706f2543Smrg
833706f2543Smrg    for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
834706f2543Smrg        if (pt->cursorNotShared)
835706f2543Smrg            continue;
836706f2543Smrg        if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
837706f2543Smrg            if (/* pt != start && */ !pt->cursorVisible) {
838706f2543Smrg                if (!pt->cursor) {
839706f2543Smrg                                /* This only happens during
840706f2543Smrg                                 * reconfiguration when a new overlap
841706f2543Smrg                                 * occurs. */
842706f2543Smrg                    CursorPtr pCursor;
843706f2543Smrg
844706f2543Smrg                    if ((pCursor = dmxFindCursor(start)))
845706f2543Smrg                        _dmxRealizeCursor(screenInfo.screens[pt->index],
846706f2543Smrg                                          pt->cursor = pCursor);
847706f2543Smrg
848706f2543Smrg                }
849706f2543Smrg                _dmxSetCursor(screenInfo.screens[pt->index],
850706f2543Smrg                              pt->cursor,
851706f2543Smrg                              x + start->rootXOrigin - pt->rootXOrigin,
852706f2543Smrg                              y + start->rootYOrigin - pt->rootYOrigin);
853706f2543Smrg            }
854706f2543Smrg            _dmxMoveCursor(screenInfo.screens[pt->index],
855706f2543Smrg                           x + start->rootXOrigin - pt->rootXOrigin,
856706f2543Smrg                           y + start->rootYOrigin - pt->rootYOrigin);
857706f2543Smrg        } else if (/* pt != start && */ pt->cursorVisible) {
858706f2543Smrg            _dmxSetCursor(screenInfo.screens[pt->index],
859706f2543Smrg                          NULL,
860706f2543Smrg                          x + start->rootXOrigin - pt->rootXOrigin,
861706f2543Smrg                          y + start->rootYOrigin - pt->rootYOrigin);
862706f2543Smrg        }
863706f2543Smrg        if (pt == start)
864706f2543Smrg            break;
865706f2543Smrg    }
866706f2543Smrg}
867706f2543Smrg
868706f2543Smrgstatic void dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
869706f2543Smrg{
870706f2543Smrg    DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
871706f2543Smrg    DMXScreenInfo *pt;
872706f2543Smrg    int           GX, GY, gx, gy;
873706f2543Smrg
874706f2543Smrg    DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n",
875706f2543Smrg            pScreen->myNum, start, pCursor, x, y);
876706f2543Smrg
877706f2543Smrg                                /* We do this check here because of two cases:
878706f2543Smrg                                 *
879706f2543Smrg                                 * 1) if a client calls XWarpPointer()
880706f2543Smrg                                 * and Xinerama is not running, we can
881706f2543Smrg                                 * have mi's notion of the pointer
882706f2543Smrg                                 * position out of phase with DMX's
883706f2543Smrg                                 * notion.
884706f2543Smrg                                 *
885706f2543Smrg                                 * 2) if a down button is held while the
886706f2543Smrg                                 * cursor moves outside the root window,
887706f2543Smrg                                 * mi's notion of the pointer position
888706f2543Smrg                                 * is out of phase with DMX's notion and
889706f2543Smrg                                 * the cursor can remain visible when it
890706f2543Smrg                                 * shouldn't be. */
891706f2543Smrg
892706f2543Smrg    dmxGetGlobalPosition(&GX, &GY);
893706f2543Smrg    gx = start->rootXOrigin + x;
894706f2543Smrg    gy = start->rootYOrigin + y;
895706f2543Smrg    if (x && y && (GX != gx || GY != gy))
896706f2543Smrg        dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK);
897706f2543Smrg
898706f2543Smrg    if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
899706f2543Smrg        _dmxSetCursor(pScreen, pCursor, x, y);
900706f2543Smrg        return;
901706f2543Smrg    }
902706f2543Smrg
903706f2543Smrg    for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
904706f2543Smrg        if (pt->cursorNotShared)
905706f2543Smrg            continue;
906706f2543Smrg        if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
907706f2543Smrg            _dmxSetCursor(screenInfo.screens[pt->index], pCursor,
908706f2543Smrg                          x + start->rootXOrigin - pt->rootXOrigin,
909706f2543Smrg                          y + start->rootYOrigin - pt->rootYOrigin);
910706f2543Smrg        } else {
911706f2543Smrg            _dmxSetCursor(screenInfo.screens[pt->index], NULL,
912706f2543Smrg                          x + start->rootXOrigin - pt->rootXOrigin,
913706f2543Smrg                          y + start->rootYOrigin - pt->rootYOrigin);
914706f2543Smrg        }
915706f2543Smrg        if (pt == start)
916706f2543Smrg            break;
917706f2543Smrg    }
918706f2543Smrg}
919706f2543Smrg
920706f2543Smrg
921706f2543Smrg/** This routine is used by the backend input routines to hide the
922706f2543Smrg * cursor on a screen that is being used for relative input.  \see
923706f2543Smrg * dmxbackend.c */
924706f2543Smrgvoid dmxHideCursor(DMXScreenInfo *dmxScreen)
925706f2543Smrg{
926706f2543Smrg    int       x, y;
927706f2543Smrg    ScreenPtr pScreen = screenInfo.screens[dmxScreen->index];
928706f2543Smrg
929706f2543Smrg    dmxGetGlobalPosition(&x, &y);
930706f2543Smrg    _dmxSetCursor(pScreen, NULL, x, y);
931706f2543Smrg}
932706f2543Smrg
933706f2543Smrg/** This routine is called during reconfiguration to make sure the
934706f2543Smrg * cursor is visible. */
935706f2543Smrgvoid dmxCheckCursor(void)
936706f2543Smrg{
937706f2543Smrg    int           i;
938706f2543Smrg    int           x, y;
939706f2543Smrg    ScreenPtr     pScreen;
940706f2543Smrg    DMXScreenInfo *firstScreen;
941706f2543Smrg
942706f2543Smrg    dmxGetGlobalPosition(&x, &y);
943706f2543Smrg    firstScreen = dmxFindFirstScreen(x, y);
944706f2543Smrg
945706f2543Smrg    DMXDBG2("dmxCheckCursor %d %d\n", x, y);
946706f2543Smrg    for (i = 0; i < dmxNumScreens; i++) {
947706f2543Smrg        DMXScreenInfo *dmxScreen = &dmxScreens[i];
948706f2543Smrg        pScreen                  = screenInfo.screens[dmxScreen->index];
949706f2543Smrg
950706f2543Smrg        if (!dmxOnScreen(x, y, dmxScreen)) {
951706f2543Smrg            if (firstScreen && i == miPointerGetScreen(inputInfo.pointer)->myNum)
952706f2543Smrg                miPointerSetScreen(inputInfo.pointer, firstScreen->index, x, y);
953706f2543Smrg            _dmxSetCursor(pScreen, NULL,
954706f2543Smrg                          x - dmxScreen->rootXOrigin,
955706f2543Smrg                          y - dmxScreen->rootYOrigin);
956706f2543Smrg        } else {
957706f2543Smrg            if (!dmxScreen->cursor) {
958706f2543Smrg                CursorPtr pCursor;
959706f2543Smrg
960706f2543Smrg                if ((pCursor = dmxFindCursor(dmxScreen))) {
961706f2543Smrg                    _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor);
962706f2543Smrg                }
963706f2543Smrg            }
964706f2543Smrg            _dmxSetCursor(pScreen, dmxScreen->cursor,
965706f2543Smrg                          x - dmxScreen->rootXOrigin,
966706f2543Smrg                          y - dmxScreen->rootYOrigin);
967706f2543Smrg        }
968706f2543Smrg    }
969706f2543Smrg    DMXDBG2("   leave dmxCheckCursor %d %d\n", x, y);
970706f2543Smrg}
971706f2543Smrg
972706f2543Smrgstatic Bool dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr)
973706f2543Smrg{
974706f2543Smrg    return TRUE;
975706f2543Smrg}
976706f2543Smrg
977706f2543Smrgstatic void dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr)
978706f2543Smrg{
979706f2543Smrg}
980706f2543Smrg
981706f2543SmrgmiPointerSpriteFuncRec dmxPointerSpriteFuncs =
982706f2543Smrg{
983706f2543Smrg    dmxRealizeCursor,
984706f2543Smrg    dmxUnrealizeCursor,
985706f2543Smrg    dmxSetCursor,
986706f2543Smrg    dmxMoveCursor,
987706f2543Smrg    dmxDeviceCursorInitialize,
988706f2543Smrg    dmxDeviceCursorCleanup
989706f2543Smrg};
990