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