3
* Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
7
* Permission is hereby granted, free of charge, to any person obtaining
8
* a copy of this software and associated documentation files (the
9
* "Software"), to deal in the Software without restriction, including
10
* without limitation on the rights to use, copy, modify, merge,
11
* publish, distribute, sublicense, and/or sell copies of the Software,
12
* and to permit persons to whom the Software is furnished to do so,
13
* subject to the following conditions:
15
* The above copyright notice and this permission notice (including the
16
* next paragraph) shall be included in all copies or substantial
17
* portions of the Software.
19
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
23
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
* David H. Dawes <dawes@xfree86.org>
32
* Kevin E. Martin <kem@redhat.com>
33
* Rickard E. (Rik) Faith <faith@redhat.com>
38
* This file contains code than supports cursor movement, including the
39
* code that initializes and reinitializes the screen positions and
40
* computes screen overlap.
42
* "This code is based very closely on the XFree86 equivalent
43
* (xfree86/common/xf86Cursor.c)." --David Dawes.
45
* "This code was then extensively re-written, as explained here."
48
* The code in xf86Cursor.c used edge lists to implement the
49
* CursorOffScreen function. The edge list computation was complex
50
* (especially in the face of arbitrarily overlapping screens) compared
51
* with the speed savings in the CursorOffScreen function. The new
52
* implementation has erred on the side of correctness, readability, and
53
* maintainability over efficiency. For the common (non-edge) case, the
54
* dmxCursorOffScreen function does avoid a loop over all the screens.
55
* When the cursor has left the screen, all the screens are searched,
56
* and the first screen (in dmxScreens order) containing the cursor will
57
* be returned. If run-time profiling shows that this routing is a
58
* performance bottle-neck, then an edge list may have to be
59
* reimplemented. An edge list algorithm is O(edges) whereas the new
60
* algorithm is O(dmxNumScreens). Since edges is usually 1-3 and
61
* dmxNumScreens may be 30-60 for large backend walls, this trade off
64
* The xf86InitOrigins routine uses bit masks during the computation and
65
* is therefore limited to the length of a word (e.g., 32 or 64 bits)
66
* screens. Because Xdmx is expected to be used with a large number of
67
* backend displays, this limitation was removed. The new
68
* implementation has erred on the side of readability over efficiency,
69
* using the dmxSL* routines to manage a screen list instead of a
70
* bitmap, and a function call to decrease the length of the main
71
* routine. Both algorithms are of the same order, and both are called
72
* only at server generation time, so trading clarity and long-term
73
* maintainability for efficiency does not seem justified in this case.
76
#ifdef HAVE_DMX_CONFIG_H
77
#include <dmx-config.h>
80
#define DMX_CURSOR_DEBUG 0
84
#include "dmxcursor.h"
89
#include "mipointer.h"
90
#include "windowstr.h"
92
#include "cursorstr.h"
93
#include "dixevents.h" /* For GetSpriteCursor() */
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)
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)
115
static int dmxCursorDoMultiCursors = 1;
117
/** Turn off support for displaying multiple cursors on overlapped
118
back-end displays. See #dmxCursorDoMultiCursors. */
119
void dmxCursorNoMulti(void)
121
dmxCursorDoMultiCursors = 0;
124
static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
126
DMXScreenInfo *dmxScreen;
133
if (screenInfo.numScreens == 1) return FALSE;
135
/* On current screen? */
136
dmxScreen = &dmxScreens[(*ppScreen)->myNum];
138
&& localX < dmxScreen->rootWidth
140
&& localY < dmxScreen->rootHeight) return FALSE;
142
/* Convert to global coordinate space */
143
globalX = dmxScreen->rootXOrigin + localX;
144
globalY = dmxScreen->rootYOrigin + localY;
146
/* Is cursor on the current screen?
147
* This efficiently exits this routine
148
* for the most common case. */
149
if (ppScreen && *ppScreen) {
150
dmxScreen = &dmxScreens[(*ppScreen)->myNum];
151
if (globalX >= dmxScreen->rootXOrigin
152
&& globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
153
&& globalY >= dmxScreen->rootYOrigin
154
&& globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight)
158
/* Find first screen cursor is on */
159
for (i = 0; i < dmxNumScreens; i++) {
160
dmxScreen = &dmxScreens[i];
161
if (globalX >= dmxScreen->rootXOrigin
162
&& globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth
163
&& globalY >= dmxScreen->rootYOrigin
164
&& globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) {
165
if (dmxScreen->index == (*ppScreen)->myNum) return FALSE;
166
*ppScreen = screenInfo.screens[dmxScreen->index];
167
*x = globalX - dmxScreen->rootXOrigin;
168
*y = globalY - dmxScreen->rootYOrigin;
175
static void dmxCrossScreen(ScreenPtr pScreen, Bool entering)
179
static void dmxWarpCursor(ScreenPtr pScreen, int x, int y)
181
DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
182
miPointerWarpCursor(pScreen, x, y);
185
miPointerScreenFuncRec dmxPointerCursorFuncs =
195
/** Create a list of screens that we'll manipulate. */
196
static int *dmxSLCreate(void)
198
int *list = malloc(dmxNumScreens * sizeof(*list));
201
for (i = 0; i < dmxNumScreens; i++) list[i] = 1;
206
static void dmxSLFree(int *list)
211
/** Find next uninitialized entry in list. */
212
static int dmxSLFindNext(int *list)
215
for (i = 0; i < dmxNumScreens; i++) if (list[i]) return i;
219
/** Make one pass over all the screens and return the number updated. */
220
static int dmxTryComputeScreenOrigins(int *screensLeft)
223
DMXScreenInfo *screen;
227
for (i = 0; i < dmxNumScreens; i++) {
228
if (!screensLeft[i]) continue;
229
screen = &dmxScreens[i];
230
switch (screen->where) {
232
dixScreenOrigins[i].x = screen->whereX;
233
dixScreenOrigins[i].y = screen->whereY;
234
++changed, screensLeft[i] = 0;
237
ref = screen->whereRefScreen;
238
if (screensLeft[ref]) break;
239
dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->whereX;
240
dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->whereY;
241
++changed, screensLeft[i] = 0;
244
ref = screen->whereRefScreen;
245
if (screensLeft[ref]) break;
246
pScreen = screenInfo.screens[ref];
247
dixScreenOrigins[i].x = dixScreenOrigins[ref].x + pScreen->width;
248
dixScreenOrigins[i].y = dixScreenOrigins[ref].y;
249
++changed, screensLeft[i] = 0;
252
ref = screen->whereRefScreen;
253
if (screensLeft[ref]) break;
254
pScreen = screenInfo.screens[i];
255
dixScreenOrigins[i].x = dixScreenOrigins[ref].x - pScreen->width;
256
dixScreenOrigins[i].y = dixScreenOrigins[ref].y;
257
++changed, screensLeft[i] = 0;
260
ref = screen->whereRefScreen;
261
if (screensLeft[ref]) break;
262
pScreen = screenInfo.screens[ref];
263
dixScreenOrigins[i].x = dixScreenOrigins[ref].x;
264
dixScreenOrigins[i].y = dixScreenOrigins[ref].y + pScreen->height;
265
++changed, screensLeft[i] = 0;
268
ref = screen->whereRefScreen;
269
if (screensLeft[ref]) break;
270
pScreen = screenInfo.screens[i];
271
dixScreenOrigins[i].x = dixScreenOrigins[ref].x;
272
dixScreenOrigins[i].y = dixScreenOrigins[ref].y - pScreen->height;
273
++changed, screensLeft[i] = 0;
276
dmxLog(dmxFatal, "No position information for screen %d\n", i);
282
static void dmxComputeScreenOrigins(void)
288
/* Compute origins based on
289
* configuration information. */
290
screensLeft = dmxSLCreate();
291
while ((i = dmxSLFindNext(screensLeft)) >= 0) {
292
while (dmxTryComputeScreenOrigins(screensLeft));
293
if ((i = dmxSLFindNext(screensLeft)) >= 0) {
294
/* All of the remaining screens are referencing each other.
295
* Assign a value to one of them and go through again. This
296
* guarantees that we will eventually terminate.
298
ref = dmxScreens[i].whereRefScreen;
299
dixScreenOrigins[ref].x = dixScreenOrigins[ref].y = 0;
300
screensLeft[ref] = 0;
303
dmxSLFree(screensLeft);
306
/* Justify the topmost and leftmost to
308
minX = dixScreenOrigins[0].x;
309
minY = dixScreenOrigins[0].y;
310
for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */
311
if (dixScreenOrigins[i].x < minX) minX = dixScreenOrigins[i].x;
312
if (dixScreenOrigins[i].y < minY) minY = dixScreenOrigins[i].y;
315
for (i = 0; i < dmxNumScreens; i++) {
316
dixScreenOrigins[i].x -= minX;
317
dixScreenOrigins[i].y -= minY;
322
/** Recompute origin information in the #dmxScreens list. This is
323
* either called from #dmxInitOrigins() or from #dmxReconfig(). */
324
void dmxReInitOrigins(void)
328
if (dmxNumScreens > MAXSCREENS)
329
dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
330
dmxNumScreens, MAXSCREENS);
332
for (i = 0; i < dmxNumScreens; i++) {
333
DMXScreenInfo *dmxScreen = &dmxScreens[i];
334
dmxLogOutput(dmxScreen,
335
"s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d"
336
" (be=%dx%d depth=%d bpp=%d)\n",
337
dmxScreen->scrnWidth, dmxScreen->scrnHeight,
338
dmxScreen->scrnX, dmxScreen->scrnY,
340
dmxScreen->rootWidth, dmxScreen->rootHeight,
341
dmxScreen->rootX, dmxScreen->rootY,
343
dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
344
dmxScreen->beWidth, dmxScreen->beHeight,
345
dmxScreen->beDepth, dmxScreen->beBPP);
349
/** Initialize screen origins (and relative position). This is called
350
* for each server generation. For dynamic reconfiguration, use
351
* #dmxReInitOrigins() instead. */
352
void dmxInitOrigins(void)
356
if (dmxNumScreens > MAXSCREENS)
357
dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n",
358
dmxNumScreens, MAXSCREENS);
360
for (i = 0; i < dmxNumScreens; i++) {
361
DMXScreenInfo *dmxScreen = &dmxScreens[i];
362
dmxLogOutput(dmxScreen,
363
"(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)"
364
" (be=%dx%d depth=%d bpp=%d)\n",
365
dmxScreen->scrnWidth, dmxScreen->scrnHeight,
366
dmxScreen->scrnX, dmxScreen->scrnY,
368
dmxScreen->rootWidth, dmxScreen->rootHeight,
369
dmxScreen->rootX, dmxScreen->rootY,
371
dmxScreen->whereX, dmxScreen->whereY,
374
dmxScreen->beWidth, dmxScreen->beHeight,
375
dmxScreen->beDepth, dmxScreen->beBPP);
378
dmxComputeScreenOrigins();
380
for (i = 0; i < dmxNumScreens; i++) {
381
DMXScreenInfo *dmxScreen = &dmxScreens[i];
382
dmxScreen->rootXOrigin = dixScreenOrigins[i].x;
383
dmxScreen->rootYOrigin = dixScreenOrigins[i].y;
389
/** Returns non-zero if the global \a x, \a y coordinate is on the
390
* screen window of the \a dmxScreen. */
391
int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen)
393
#if DMX_CURSOR_DEBUG > 1
395
"dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n",
396
dmxScreen->index, x, y,
397
dmxScreen->rootWidth, dmxScreen->rootHeight,
398
dmxScreen->rootX, dmxScreen->rootY,
399
dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
400
dmxScreen->scrnWidth, dmxScreen->scrnHeight,
401
dmxScreen->scrnX, dmxScreen->scrnY);
403
if (x >= dmxScreen->rootXOrigin
404
&& x < dmxScreen->rootXOrigin + dmxScreen->rootWidth
405
&& y >= dmxScreen->rootYOrigin
406
&& y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1;
410
/** Returns non-zero if \a a overlaps \a b. */
411
static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b)
413
if (dmxOnScreen(a->rootXOrigin,
414
a->rootYOrigin, b)) return 1;
416
if (dmxOnScreen(a->rootXOrigin,
417
a->rootYOrigin + a->scrnWidth, b)) return 1;
419
if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
420
a->rootYOrigin, b)) return 1;
422
if (dmxOnScreen(a->rootXOrigin + a->scrnHeight,
423
a->rootYOrigin + a->scrnWidth, b)) return 1;
425
if (dmxOnScreen(b->rootXOrigin,
426
b->rootYOrigin, a)) return 1;
428
if (dmxOnScreen(b->rootXOrigin,
429
b->rootYOrigin + b->scrnWidth, a)) return 1;
431
if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
432
b->rootYOrigin, a)) return 1;
434
if (dmxOnScreen(b->rootXOrigin + b->scrnHeight,
435
b->rootYOrigin + b->scrnWidth, a)) return 1;
440
/** Used with #dmxInterateOverlap to print out a list of screens which
441
* overlap each other. */
442
static void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure)
444
DMXScreenInfo *a = closure;
445
if (dmxScreen != a) {
446
if (dmxScreen->cursorNotShared)
447
dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name);
449
dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name);
454
/** Iterate over the screens which overlap with the \a start screen,
455
* calling \a f with the \a closure for each argument. Often used with
456
* #dmxPrintOverlap. */
457
static void *dmxIterateOverlap(DMXScreenInfo *start,
458
void *(*f)(DMXScreenInfo *dmxScreen, void *),
463
if (!start->over) return f(start, closure);
465
for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
467
if ((retval = f(pt, closure))) return retval;
468
if (pt == start) break;
473
/** Used with #dmxPropertyIterate to determine if screen \a a is the
474
* same as the screen \a closure. */
475
static void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure)
477
DMXScreenInfo *b = closure;
479
if (a == b) return a;
483
/** Detects overlapping dmxScreens and creates circular lists. This
484
* uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and
485
* the computation only needs to be performed for every server
486
* generation or dynamic reconfiguration . */
487
void dmxInitOverlap(void)
490
DMXScreenInfo *a, *b, *pt;
492
for (i = 0; i < dmxNumScreens; i++) dmxScreens[i].over = NULL;
494
for (i = 0; i < dmxNumScreens; i++) {
497
for (j = i+1; j < dmxNumScreens; j++) {
499
if (b->over) continue;
501
if (dmxDoesOverlap(a, b)) {
502
DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n",
503
a->index, b->index, a, a->over, b, b->over);
504
b->over = (a->over ? a->over : a);
510
for (i = 0; i < dmxNumScreens; i++) {
513
if (!a->over) continue;
515
/* Flag all pairs that are on same display */
516
for (pt = a->over; pt != a; pt = pt->over) {
517
if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) {
518
/* The ->over sets contain the transitive set of screens
519
* that overlap. For screens that are on the same
520
* backend display, we only want to exclude pairs of
521
* screens that mutually overlap on the backend display,
522
* so we call dmxDoesOverlap, which is stricter than the
524
if (!dmxDoesOverlap(a, pt)) continue;
525
a->cursorNotShared = 1;
526
pt->cursorNotShared = 1;
528
"Screen %d and %d overlap on %s\n",
529
a->index, pt->index, a->name);
534
for (i = 0; i < dmxNumScreens; i++) {
538
dmxLogOutput(a, "Overlaps");
539
dmxIterateOverlap(a, dmxPrintOverlap, a);
540
dmxLogOutputCont(a, "\n");
545
/** Create \a pCursor on the back-end associated with \a pScreen. */
546
void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor)
548
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
549
dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
550
CursorBitsPtr pBits = pCursor->bits;
562
m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask;
564
v.plane_mask = AllPlanes;
569
for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
570
if (dmxScreen->bePixmapFormats[i].depth == 1) {
571
/* Create GC in the back-end servers */
572
gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i],
578
dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n");
580
src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
581
pBits->width, pBits->height, 1);
582
msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin,
583
pBits->width, pBits->height, 1);
585
img = XCreateImage(dmxScreen->beDisplay,
586
dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
587
1, XYBitmap, 0, (char *)pBits->source,
588
pBits->width, pBits->height,
589
BitmapPad(dmxScreen->beDisplay), 0);
591
XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0,
592
pBits->width, pBits->height);
596
img = XCreateImage(dmxScreen->beDisplay,
597
dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
598
1, XYBitmap, 0, (char *)pBits->mask,
599
pBits->width, pBits->height,
600
BitmapPad(dmxScreen->beDisplay), 0);
602
XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0,
603
pBits->width, pBits->height);
607
fg.red = pCursor->foreRed;
608
fg.green = pCursor->foreGreen;
609
fg.blue = pCursor->foreBlue;
611
bg.red = pCursor->backRed;
612
bg.green = pCursor->backGreen;
613
bg.blue = pCursor->backBlue;
615
pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay,
618
pBits->xhot, pBits->yhot);
620
XFreePixmap(dmxScreen->beDisplay, src);
621
XFreePixmap(dmxScreen->beDisplay, msk);
622
XFreeGC(dmxScreen->beDisplay, gc);
624
dmxSync(dmxScreen, FALSE);
627
static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
629
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
630
dmxCursorPrivPtr pCursorPriv;
632
DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor);
634
pCursor->devPriv[pScreen->myNum] = xalloc(sizeof(*pCursorPriv));
635
if (!pCursor->devPriv[pScreen->myNum])
638
pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
639
pCursorPriv->cursor = (Cursor)0;
641
if (!dmxScreen->beDisplay)
644
dmxBECreateCursor(pScreen, pCursor);
648
/** Free \a pCursor on the back-end associated with \a pScreen. */
649
Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor)
651
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
652
dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
655
XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor);
656
pCursorPriv->cursor = (Cursor)0;
663
static Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
665
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
667
DMXDBG3("_dmxUnrealizeCursor(%d,%p) %p\n",
668
pScreen->myNum, pCursor, pCursorPriv);
670
if (dmxScreen->beDisplay) {
671
if (dmxBEFreeCursor(pScreen, pCursor))
672
xfree(pCursor->devPriv[pScreen->myNum]);
674
pCursor->devPriv[pScreen->myNum] = NULL;
679
static void _dmxMoveCursor(ScreenPtr pScreen, int x, int y)
681
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
682
int newX = x + dmxScreen->rootX;
683
int newY = y + dmxScreen->rootY;
685
if (newX < 0) newX = 0;
686
if (newY < 0) newY = 0;
688
DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n",
689
pScreen->myNum, x, y, newX, newY);
690
if (dmxScreen->beDisplay) {
691
XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin,
692
0, 0, 0, 0, newX, newY);
693
dmxSync(dmxScreen, TRUE);
697
static void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
699
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
701
DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y);
704
dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen);
705
if (dmxScreen->curCursor != pCursorPriv->cursor) {
706
if (dmxScreen->beDisplay)
707
XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
708
pCursorPriv->cursor);
709
dmxScreen->cursor = pCursor;
710
dmxScreen->curCursor = pCursorPriv->cursor;
711
dmxScreen->cursorVisible = 1;
713
_dmxMoveCursor(pScreen, x, y);
715
if (dmxScreen->beDisplay)
716
XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin,
717
dmxScreen->noCursor);
718
dmxScreen->cursor = NULL;
719
dmxScreen->curCursor = (Cursor)0;
720
dmxScreen->cursorVisible = 0;
722
if (dmxScreen->beDisplay) dmxSync(dmxScreen, TRUE);
725
static Bool dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
727
DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
730
if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
731
return _dmxRealizeCursor(pScreen, pCursor);
733
for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
734
if (pt->cursorNotShared) continue;
735
_dmxRealizeCursor(screenInfo.screens[pt->index], pCursor);
736
if (pt == start) break;
741
static Bool dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
743
DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
746
if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared)
747
return _dmxUnrealizeCursor(pScreen, pCursor);
749
for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
750
if (pt->cursorNotShared) continue;
751
_dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor);
752
if (pt == start) break;
757
static CursorPtr dmxFindCursor(DMXScreenInfo *start)
761
if (!start || !start->over) return GetSpriteCursor();
762
for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
763
if (pt->cursor) return pt->cursor;
764
if (pt == start) break;
766
return GetSpriteCursor();
769
/** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This
770
* function is usually called via #dmxPointerSpriteFuncs, except during
771
* reconfiguration when the cursor is repositioned to force an update on
772
* newley overlapping screens and on screens that no longer overlap. */
773
void dmxMoveCursor(ScreenPtr pScreen, int x, int y)
775
DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
778
DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y);
780
if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
781
_dmxMoveCursor(pScreen, x, y);
785
for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
786
if (pt->cursorNotShared) continue;
787
if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
788
if (/* pt != start && */ !pt->cursorVisible) {
790
/* This only happens during
791
* reconfiguration when a new overlap
795
if ((pCursor = dmxFindCursor(start)))
796
_dmxRealizeCursor(screenInfo.screens[pt->index],
797
pt->cursor = pCursor);
800
_dmxSetCursor(screenInfo.screens[pt->index],
802
x + start->rootXOrigin - pt->rootXOrigin,
803
y + start->rootYOrigin - pt->rootYOrigin);
805
_dmxMoveCursor(screenInfo.screens[pt->index],
806
x + start->rootXOrigin - pt->rootXOrigin,
807
y + start->rootYOrigin - pt->rootYOrigin);
808
} else if (/* pt != start && */ pt->cursorVisible) {
809
_dmxSetCursor(screenInfo.screens[pt->index],
811
x + start->rootXOrigin - pt->rootXOrigin,
812
y + start->rootYOrigin - pt->rootYOrigin);
814
if (pt == start) break;
818
static void dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
820
DMXScreenInfo *start = &dmxScreens[pScreen->myNum];
824
DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n",
825
pScreen->myNum, start, pCursor, x, y);
827
/* We do this check here because of two cases:
829
* 1) if a client calls XWarpPointer()
830
* and Xinerama is not running, we can
831
* have mi's notion of the pointer
832
* position out of phase with DMX's
835
* 2) if a down button is held while the
836
* cursor moves outside the root window,
837
* mi's notion of the pointer position
838
* is out of phase with DMX's notion and
839
* the cursor can remain visible when it
842
dmxGetGlobalPosition(&GX, &GY);
843
gx = start->rootXOrigin + x;
844
gy = start->rootYOrigin + y;
845
if (x && y && (GX != gx || GY != gy))
846
dmxCoreMotion(gx, gy, 0, DMX_NO_BLOCK);
848
if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) {
849
_dmxSetCursor(pScreen, pCursor, x, y);
853
for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
854
if (pt->cursorNotShared) continue;
855
if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) {
856
_dmxSetCursor(screenInfo.screens[pt->index], pCursor,
857
x + start->rootXOrigin - pt->rootXOrigin,
858
y + start->rootYOrigin - pt->rootYOrigin);
860
_dmxSetCursor(screenInfo.screens[pt->index], NULL,
861
x + start->rootXOrigin - pt->rootXOrigin,
862
y + start->rootYOrigin - pt->rootYOrigin);
864
if (pt == start) break;
869
/** This routine is used by the backend input routines to hide the
870
* cursor on a screen that is being used for relative input. \see
872
void dmxHideCursor(DMXScreenInfo *dmxScreen)
875
ScreenPtr pScreen = screenInfo.screens[dmxScreen->index];
877
dmxGetGlobalPosition(&x, &y);
878
_dmxSetCursor(pScreen, NULL, x, y);
881
/** This routine is called during reconfiguration to make sure the
882
* cursor is visible. */
883
void dmxCheckCursor(void)
888
DMXScreenInfo *firstScreen;
890
dmxGetGlobalPosition(&x, &y);
891
firstScreen = dmxFindFirstScreen(x, y);
893
DMXDBG2("dmxCheckCursor %d %d\n", x, y);
894
for (i = 0; i < dmxNumScreens; i++) {
895
DMXScreenInfo *dmxScreen = &dmxScreens[i];
896
pScreen = screenInfo.screens[dmxScreen->index];
898
if (!dmxOnScreen(x, y, dmxScreen)) {
899
if (firstScreen && i == miPointerCurrentScreen()->myNum)
900
miPointerSetNewScreen(firstScreen->index, x, y);
901
_dmxSetCursor(pScreen, NULL,
902
x - dmxScreen->rootXOrigin,
903
y - dmxScreen->rootYOrigin);
905
if (!dmxScreen->cursor) {
908
if ((pCursor = dmxFindCursor(dmxScreen))) {
909
_dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor);
912
_dmxSetCursor(pScreen, dmxScreen->cursor,
913
x - dmxScreen->rootXOrigin,
914
y - dmxScreen->rootYOrigin);
917
DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y);
920
miPointerSpriteFuncRec dmxPointerSpriteFuncs =