dmxcursor.c revision 706f2543
1/* 2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. 3 * 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation on the rights to use, copy, modify, merge, 10 * publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial 16 * portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS 22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 */ 27 28/* 29 * Authors: 30 * David H. Dawes <dawes@xfree86.org> 31 * Kevin E. Martin <kem@redhat.com> 32 * Rickard E. (Rik) Faith <faith@redhat.com> 33 * 34 */ 35 36/** \file 37 * This file contains code than supports cursor movement, including the 38 * code that initializes and reinitializes the screen positions and 39 * computes screen overlap. 40 * 41 * "This code is based very closely on the XFree86 equivalent 42 * (xfree86/common/xf86Cursor.c)." --David Dawes. 43 * 44 * "This code was then extensively re-written, as explained here." 45 * --Rik Faith 46 * 47 * The code in xf86Cursor.c used edge lists to implement the 48 * CursorOffScreen function. The edge list computation was complex 49 * (especially in the face of arbitrarily overlapping screens) compared 50 * with the speed savings in the CursorOffScreen function. The new 51 * implementation has erred on the side of correctness, readability, and 52 * maintainability over efficiency. For the common (non-edge) case, the 53 * dmxCursorOffScreen function does avoid a loop over all the screens. 54 * When the cursor has left the screen, all the screens are searched, 55 * and the first screen (in dmxScreens order) containing the cursor will 56 * be returned. If run-time profiling shows that this routing is a 57 * performance bottle-neck, then an edge list may have to be 58 * reimplemented. An edge list algorithm is O(edges) whereas the new 59 * algorithm is O(dmxNumScreens). Since edges is usually 1-3 and 60 * dmxNumScreens may be 30-60 for large backend walls, this trade off 61 * may be compelling. 62 * 63 * The xf86InitOrigins routine uses bit masks during the computation and 64 * is therefore limited to the length of a word (e.g., 32 or 64 bits) 65 * screens. Because Xdmx is expected to be used with a large number of 66 * backend displays, this limitation was removed. The new 67 * implementation has erred on the side of readability over efficiency, 68 * using the dmxSL* routines to manage a screen list instead of a 69 * bitmap, and a function call to decrease the length of the main 70 * routine. Both algorithms are of the same order, and both are called 71 * only at server generation time, so trading clarity and long-term 72 * maintainability for efficiency does not seem justified in this case. 73 */ 74 75#ifdef HAVE_DMX_CONFIG_H 76#include <dmx-config.h> 77#endif 78 79#define DMX_CURSOR_DEBUG 0 80 81#include "dmx.h" 82#include "dmxsync.h" 83#include "dmxcursor.h" 84#include "dmxlog.h" 85#include "dmxprop.h" 86#include "dmxinput.h" 87 88#include "mipointer.h" 89#include "windowstr.h" 90#include "globals.h" 91#include "cursorstr.h" 92#include "dixevents.h" /* For GetSpriteCursor() */ 93#include "inputstr.h" /* for inputInfo.pointer */ 94 95#if DMX_CURSOR_DEBUG 96#define DMXDBG0(f) dmxLog(dmxDebug,f) 97#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) 98#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) 99#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) 100#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) 101#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) 102#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) 103#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) 104#else 105#define DMXDBG0(f) 106#define DMXDBG1(f,a) 107#define DMXDBG2(f,a,b) 108#define DMXDBG3(f,a,b,c) 109#define DMXDBG4(f,a,b,c,d) 110#define DMXDBG5(f,a,b,c,d,e) 111#define DMXDBG6(f,a,b,c,d,e,g) 112#define DMXDBG7(f,a,b,c,d,e,g,h) 113#endif 114 115static int dmxCursorDoMultiCursors = 1; 116 117/** Turn off support for displaying multiple cursors on overlapped 118 back-end displays. See #dmxCursorDoMultiCursors. */ 119void dmxCursorNoMulti(void) 120{ 121 dmxCursorDoMultiCursors = 0; 122} 123 124static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) 125{ 126 DMXScreenInfo *dmxScreen; 127 int i; 128 int localX = *x; 129 int localY = *y; 130 int globalX; 131 int globalY; 132 133 if (screenInfo.numScreens == 1) 134 return FALSE; 135 136 /* On current screen? */ 137 dmxScreen = &dmxScreens[(*ppScreen)->myNum]; 138 if (localX >= 0 139 && localX < dmxScreen->rootWidth 140 && localY >= 0 141 && localY < dmxScreen->rootHeight) 142 return FALSE; 143 144 /* Convert to global coordinate space */ 145 globalX = dmxScreen->rootXOrigin + localX; 146 globalY = dmxScreen->rootYOrigin + localY; 147 148 /* Is cursor on the current screen? 149 * This efficiently exits this routine 150 * for the most common case. */ 151 if (ppScreen && *ppScreen) { 152 dmxScreen = &dmxScreens[(*ppScreen)->myNum]; 153 if (globalX >= dmxScreen->rootXOrigin 154 && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth 155 && globalY >= dmxScreen->rootYOrigin 156 && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) 157 return FALSE; 158 } 159 160 /* Find first screen cursor is on */ 161 for (i = 0; i < dmxNumScreens; i++) { 162 dmxScreen = &dmxScreens[i]; 163 if (globalX >= dmxScreen->rootXOrigin 164 && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth 165 && globalY >= dmxScreen->rootYOrigin 166 && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) { 167 if (dmxScreen->index == (*ppScreen)->myNum) 168 return FALSE; 169 *ppScreen = screenInfo.screens[dmxScreen->index]; 170 *x = globalX - dmxScreen->rootXOrigin; 171 *y = globalY - dmxScreen->rootYOrigin; 172 return TRUE; 173 } 174 } 175 return FALSE; 176} 177 178static void dmxCrossScreen(ScreenPtr pScreen, Bool entering) 179{ 180} 181 182static void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 183{ 184 DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y); 185#if 11 /*BP*/ 186 /* This call is depracated. Replace with???? */ 187 miPointerWarpCursor(pDev, pScreen, x, y); 188#else 189 pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE); 190#endif 191} 192 193miPointerScreenFuncRec dmxPointerCursorFuncs = 194{ 195 dmxCursorOffScreen, 196 dmxCrossScreen, 197 dmxWarpCursor, 198 NULL, 199 NULL, 200}; 201 202 203/** Create a list of screens that we'll manipulate. */ 204static int *dmxSLCreate(void) 205{ 206 int *list = malloc(dmxNumScreens * sizeof(*list)); 207 int i; 208 209 for (i = 0; i < dmxNumScreens; i++) 210 list[i] = 1; 211 return list; 212} 213 214/** Free list. */ 215static void dmxSLFree(int *list) 216{ 217 free(list); 218} 219 220/** Find next uninitialized entry in list. */ 221static int dmxSLFindNext(int *list) 222{ 223 int i; 224 for (i = 0; i < dmxNumScreens; i++) 225 if (list[i]) 226 return i; 227 return -1; 228} 229 230/** Make one pass over all the screens and return the number updated. */ 231static int dmxTryComputeScreenOrigins(int *screensLeft) 232{ 233 ScreenPtr pScreen, refScreen; 234 DMXScreenInfo *screen; 235 int i, ref; 236 int changed = 0; 237 238 for (i = 0; i < dmxNumScreens; i++) { 239 if (!screensLeft[i]) 240 continue; 241 screen = &dmxScreens[i]; 242 pScreen = screenInfo.screens[i]; 243 switch (screen->where) { 244 case PosAbsolute: 245 pScreen->x = screen->whereX; 246 pScreen->y = screen->whereY; 247 ++changed, screensLeft[i] = 0; 248 break; 249 case PosRelative: 250 ref = screen->whereRefScreen; 251 if (screensLeft[ref]) 252 break; 253 refScreen = screenInfo.screens[ref]; 254 pScreen->x = refScreen->x + screen->whereX; 255 pScreen->y = refScreen->y + screen->whereY; 256 ++changed, screensLeft[i] = 0; 257 break; 258 case PosRightOf: 259 ref = screen->whereRefScreen; 260 if (screensLeft[ref]) 261 break; 262 refScreen = screenInfo.screens[ref]; 263 pScreen->x = refScreen->x + refScreen->width; 264 pScreen->y = refScreen->y; 265 ++changed, screensLeft[i] = 0; 266 break; 267 case PosLeftOf: 268 ref = screen->whereRefScreen; 269 if (screensLeft[ref]) 270 break; 271 refScreen = screenInfo.screens[ref]; 272 pScreen->x = refScreen->x - pScreen->width; 273 pScreen->y = refScreen->y; 274 ++changed, screensLeft[i] = 0; 275 break; 276 case PosBelow: 277 ref = screen->whereRefScreen; 278 if (screensLeft[ref]) 279 break; 280 refScreen = screenInfo.screens[ref]; 281 pScreen->x = refScreen->x; 282 pScreen->y = refScreen->y + refScreen->height; 283 ++changed, screensLeft[i] = 0; 284 break; 285 case PosAbove: 286 ref = screen->whereRefScreen; 287 if (screensLeft[ref]) 288 break; 289 refScreen = screenInfo.screens[ref]; 290 pScreen->x = refScreen->x; 291 pScreen->y = refScreen->y - pScreen->height; 292 ++changed, screensLeft[i] = 0; 293 break; 294 case PosNone: 295 dmxLog(dmxFatal, "No position information for screen %d\n", i); 296 } 297 } 298 return changed; 299} 300 301static void dmxComputeScreenOrigins(void) 302{ 303 ScreenPtr pScreen; 304 int *screensLeft; 305 int i, ref; 306 int minX, minY; 307 308 /* Compute origins based on 309 * configuration information. */ 310 screensLeft = dmxSLCreate(); 311 while ((i = dmxSLFindNext(screensLeft)) >= 0) { 312 while (dmxTryComputeScreenOrigins(screensLeft)); 313 if ((i = dmxSLFindNext(screensLeft)) >= 0) { 314 /* All of the remaining screens are referencing each other. 315 * Assign a value to one of them and go through again. This 316 * guarantees that we will eventually terminate. 317 */ 318 ref = dmxScreens[i].whereRefScreen; 319 pScreen = screenInfo.screens[ref]; 320 pScreen->x = pScreen->y = 0; 321 screensLeft[ref] = 0; 322 } 323 } 324 dmxSLFree(screensLeft); 325 326 327 /* Justify the topmost and leftmost to 328 * (0,0). */ 329 minX = screenInfo.screens[0]->x; 330 minY = screenInfo.screens[0]->y; 331 for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */ 332 if (screenInfo.screens[i]->x < minX) 333 minX = screenInfo.screens[i]->x; 334 if (screenInfo.screens[i]->y < minY) 335 minY = screenInfo.screens[i]->y; 336 } 337 if (minX || minY) { 338 for (i = 0; i < dmxNumScreens; i++) { 339 screenInfo.screens[i]->x -= minX; 340 screenInfo.screens[i]->y -= minY; 341 } 342 } 343} 344 345/** Recompute origin information in the #dmxScreens list. This is 346 * called from #dmxInitOrigins. */ 347void dmxReInitOrigins(void) 348{ 349 int i; 350 351 if (dmxNumScreens > MAXSCREENS) 352 dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", 353 dmxNumScreens, MAXSCREENS); 354 355 for (i = 0; i < dmxNumScreens; i++) { 356 DMXScreenInfo *dmxScreen = &dmxScreens[i]; 357 dmxLogOutput(dmxScreen, 358 "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d" 359 " (be=%dx%d depth=%d bpp=%d)\n", 360 dmxScreen->scrnWidth, dmxScreen->scrnHeight, 361 dmxScreen->scrnX, dmxScreen->scrnY, 362 363 dmxScreen->rootWidth, dmxScreen->rootHeight, 364 dmxScreen->rootX, dmxScreen->rootY, 365 366 dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, 367 dmxScreen->beWidth, dmxScreen->beHeight, 368 dmxScreen->beDepth, dmxScreen->beBPP); 369 } 370} 371 372/** Initialize screen origins (and relative position). This is called 373 * for each server generation. For dynamic reconfiguration, use 374 * #dmxReInitOrigins() instead. */ 375void dmxInitOrigins(void) 376{ 377 int i; 378 379 if (dmxNumScreens > MAXSCREENS) 380 dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", 381 dmxNumScreens, MAXSCREENS); 382 383 for (i = 0; i < dmxNumScreens; i++) { 384 DMXScreenInfo *dmxScreen = &dmxScreens[i]; 385 dmxLogOutput(dmxScreen, 386 "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)" 387 " (be=%dx%d depth=%d bpp=%d)\n", 388 dmxScreen->scrnWidth, dmxScreen->scrnHeight, 389 dmxScreen->scrnX, dmxScreen->scrnY, 390 391 dmxScreen->rootWidth, dmxScreen->rootHeight, 392 dmxScreen->rootX, dmxScreen->rootY, 393 394 dmxScreen->whereX, dmxScreen->whereY, 395 dmxScreen->where, 396 397 dmxScreen->beWidth, dmxScreen->beHeight, 398 dmxScreen->beDepth, dmxScreen->beBPP); 399 } 400 401 dmxComputeScreenOrigins(); 402 403 for (i = 0; i < dmxNumScreens; i++) { 404 DMXScreenInfo *dmxScreen = &dmxScreens[i]; 405 dmxScreen->rootXOrigin = screenInfo.screens[i]->x; 406 dmxScreen->rootYOrigin = screenInfo.screens[i]->y; 407 } 408 409 dmxReInitOrigins(); 410} 411 412/** Returns non-zero if the global \a x, \a y coordinate is on the 413 * screen window of the \a dmxScreen. */ 414int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen) 415{ 416#if DMX_CURSOR_DEBUG > 1 417 dmxLog(dmxDebug, 418 "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n", 419 dmxScreen->index, x, y, 420 dmxScreen->rootWidth, dmxScreen->rootHeight, 421 dmxScreen->rootX, dmxScreen->rootY, 422 dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, 423 dmxScreen->scrnWidth, dmxScreen->scrnHeight, 424 dmxScreen->scrnX, dmxScreen->scrnY); 425#endif 426 if (x >= dmxScreen->rootXOrigin 427 && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth 428 && y >= dmxScreen->rootYOrigin 429 && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1; 430 return 0; 431} 432 433/** Returns non-zero if \a a overlaps \a b. */ 434static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b) 435{ 436 if (dmxOnScreen(a->rootXOrigin, 437 a->rootYOrigin, b)) 438 return 1; 439 440 if (dmxOnScreen(a->rootXOrigin, 441 a->rootYOrigin + a->scrnWidth, b)) 442 return 1; 443 444 if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, 445 a->rootYOrigin, b)) 446 return 1; 447 448 if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, 449 a->rootYOrigin + a->scrnWidth, b)) 450 return 1; 451 452 if (dmxOnScreen(b->rootXOrigin, 453 b->rootYOrigin, a)) 454 return 1; 455 456 if (dmxOnScreen(b->rootXOrigin, 457 b->rootYOrigin + b->scrnWidth, a)) 458 return 1; 459 460 if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, 461 b->rootYOrigin, a)) 462 return 1; 463 464 if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, 465 b->rootYOrigin + b->scrnWidth, a)) 466 return 1; 467 468 return 0; 469} 470 471/** Used with \a dmxInterateOverlap to print out a list of screens which 472 * overlap each other. */ 473static void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure) 474{ 475 DMXScreenInfo *a = closure; 476 if (dmxScreen != a) { 477 if (dmxScreen->cursorNotShared) 478 dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name); 479 else 480 dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name); 481 } 482 return NULL; 483} 484 485/** Iterate over the screens which overlap with the \a start screen, 486 * calling \a f with the \a closure for each argument. Often used with 487 * #dmxPrintOverlap. */ 488static void *dmxIterateOverlap(DMXScreenInfo *start, 489 void *(*f)(DMXScreenInfo *dmxScreen, void *), 490 void *closure) 491{ 492 DMXScreenInfo *pt; 493 494 if (!start->over) return f(start, closure); 495 496 for (pt = start->over; /* condition at end of loop */; pt = pt->over) { 497 void *retval; 498 if ((retval = f(pt, closure))) return retval; 499 if (pt == start) break; 500 } 501 return NULL; 502} 503 504/** Used with #dmxPropertyIterate to determine if screen \a a is the 505 * same as the screen \a closure. */ 506static void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure) 507{ 508 DMXScreenInfo *b = closure; 509 510 if (a == b) 511 return a; 512 return NULL; 513} 514 515/** Detects overlapping dmxScreens and creates circular lists. This 516 * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and 517 * the computation only needs to be performed for every server 518 * generation or dynamic reconfiguration . */ 519void dmxInitOverlap(void) 520{ 521 int i, j; 522 DMXScreenInfo *a, *b, *pt; 523 524 for (i = 0; i < dmxNumScreens; i++) 525 dmxScreens[i].over = NULL; 526 527 for (i = 0; i < dmxNumScreens; i++) { 528 a = &dmxScreens[i]; 529 530 for (j = i+1; j < dmxNumScreens; j++) { 531 b = &dmxScreens[j]; 532 if (b->over) 533 continue; 534 535 if (dmxDoesOverlap(a, b)) { 536 DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n", 537 a->index, b->index, a, a->over, b, b->over); 538 b->over = (a->over ? a->over : a); 539 a->over = b; 540 } 541 } 542 } 543 544 for (i = 0; i < dmxNumScreens; i++) { 545 a = &dmxScreens[i]; 546 547 if (!a->over) 548 continue; 549 550 /* Flag all pairs that are on same display */ 551 for (pt = a->over; pt != a; pt = pt->over) { 552 if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) { 553 /* The ->over sets contain the transitive set of screens 554 * that overlap. For screens that are on the same 555 * backend display, we only want to exclude pairs of 556 * screens that mutually overlap on the backend display, 557 * so we call dmxDoesOverlap, which is stricter than the 558 * ->over set. */ 559 if (!dmxDoesOverlap(a, pt)) 560 continue; 561 a->cursorNotShared = 1; 562 pt->cursorNotShared = 1; 563 dmxLog(dmxInfo, 564 "Screen %d and %d overlap on %s\n", 565 a->index, pt->index, a->name); 566 } 567 } 568 } 569 570 for (i = 0; i < dmxNumScreens; i++) { 571 a = &dmxScreens[i]; 572 573 if (a->over) { 574 dmxLogOutput(a, "Overlaps"); 575 dmxIterateOverlap(a, dmxPrintOverlap, a); 576 dmxLogOutputCont(a, "\n"); 577 } 578 } 579} 580 581/** Create \a pCursor on the back-end associated with \a pScreen. */ 582void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor) 583{ 584 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 585 dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); 586 CursorBitsPtr pBits = pCursor->bits; 587 Pixmap src, msk; 588 XColor fg, bg; 589 XImage *img; 590 XlibGC gc = NULL; 591 XGCValues v; 592 unsigned long m; 593 int i; 594 595 if (!pCursorPriv) 596 return; 597 598 m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask; 599 v.function = GXcopy; 600 v.plane_mask = AllPlanes; 601 v.foreground = 1L; 602 v.background = 0L; 603 v.clip_mask = None; 604 605 for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { 606 if (dmxScreen->bePixmapFormats[i].depth == 1) { 607 /* Create GC in the back-end servers */ 608 gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i], 609 m, &v); 610 break; 611 } 612 } 613 if (!gc) 614 dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n"); 615 616 src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, 617 pBits->width, pBits->height, 1); 618 msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, 619 pBits->width, pBits->height, 1); 620 621 img = XCreateImage(dmxScreen->beDisplay, 622 dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, 623 1, XYBitmap, 0, (char *)pBits->source, 624 pBits->width, pBits->height, 625 BitmapPad(dmxScreen->beDisplay), 0); 626 627 XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0, 628 pBits->width, pBits->height); 629 630 XFree(img); 631 632 img = XCreateImage(dmxScreen->beDisplay, 633 dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, 634 1, XYBitmap, 0, (char *)pBits->mask, 635 pBits->width, pBits->height, 636 BitmapPad(dmxScreen->beDisplay), 0); 637 638 XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0, 639 pBits->width, pBits->height); 640 641 XFree(img); 642 643 fg.red = pCursor->foreRed; 644 fg.green = pCursor->foreGreen; 645 fg.blue = pCursor->foreBlue; 646 647 bg.red = pCursor->backRed; 648 bg.green = pCursor->backGreen; 649 bg.blue = pCursor->backBlue; 650 651 pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay, 652 src, msk, 653 &fg, &bg, 654 pBits->xhot, pBits->yhot); 655 656 XFreePixmap(dmxScreen->beDisplay, src); 657 XFreePixmap(dmxScreen->beDisplay, msk); 658 XFreeGC(dmxScreen->beDisplay, gc); 659 660 dmxSync(dmxScreen, FALSE); 661} 662 663static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) 664{ 665 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 666 dmxCursorPrivPtr pCursorPriv; 667 668 DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor); 669 670 DMX_SET_CURSOR_PRIV(pCursor, pScreen, malloc(sizeof(*pCursorPriv))); 671 if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen)) 672 return FALSE; 673 674 pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); 675 pCursorPriv->cursor = (Cursor)0; 676 677 if (!dmxScreen->beDisplay) 678 return TRUE; 679 680 dmxBECreateCursor(pScreen, pCursor); 681 return TRUE; 682} 683 684/** Free \a pCursor on the back-end associated with \a pScreen. */ 685Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor) 686{ 687 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 688 dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); 689 690 if (pCursorPriv) { 691 XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor); 692 pCursorPriv->cursor = (Cursor)0; 693 return TRUE; 694 } 695 696 return FALSE; 697} 698 699static Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) 700{ 701 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 702 703 DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", 704 pScreen->myNum, pCursor); 705 706 if (dmxScreen->beDisplay) { 707 if (dmxBEFreeCursor(pScreen, pCursor)) 708 free(DMX_GET_CURSOR_PRIV(pCursor, pScreen)); 709 } 710 DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL); 711 712 return TRUE; 713} 714 715static void _dmxMoveCursor(ScreenPtr pScreen, int x, int y) 716{ 717 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 718 int newX = x + dmxScreen->rootX; 719 int newY = y + dmxScreen->rootY; 720 721 if (newX < 0) newX = 0; 722 if (newY < 0) newY = 0; 723 724 DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n", 725 pScreen->myNum, x, y, newX, newY); 726 if (dmxScreen->beDisplay) { 727 XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin, 728 0, 0, 0, 0, newX, newY); 729 dmxSync(dmxScreen, TRUE); 730 } 731} 732 733static void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) 734{ 735 DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; 736 737 DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y); 738 739 if (pCursor) { 740 dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); 741 if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) { 742 if (dmxScreen->beDisplay) 743 XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, 744 pCursorPriv->cursor); 745 dmxScreen->cursor = pCursor; 746 dmxScreen->curCursor = pCursorPriv->cursor; 747 dmxScreen->cursorVisible = 1; 748 } 749 _dmxMoveCursor(pScreen, x, y); 750 } else { 751 if (dmxScreen->beDisplay) 752 XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, 753 dmxScreen->noCursor); 754 dmxScreen->cursor = NULL; 755 dmxScreen->curCursor = (Cursor)0; 756 dmxScreen->cursorVisible = 0; 757 } 758 if (dmxScreen->beDisplay) dmxSync(dmxScreen, TRUE); 759} 760 761static Bool dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 762{ 763 DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; 764 DMXScreenInfo *pt; 765 766 if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) 767 return _dmxRealizeCursor(pScreen, pCursor); 768 769 for (pt = start->over; /* condition at end of loop */; pt = pt->over) { 770 if (pt->cursorNotShared) 771 continue; 772 _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor); 773 if (pt == start) 774 break; 775 } 776 return TRUE; 777} 778 779static Bool dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 780{ 781 DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; 782 DMXScreenInfo *pt; 783 784 if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) 785 return _dmxUnrealizeCursor(pScreen, pCursor); 786 787 for (pt = start->over; /* condition at end of loop */; pt = pt->over) { 788 if (pt->cursorNotShared) 789 continue; 790 _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor); 791 if (pt == start) 792 break; 793 } 794 return TRUE; 795} 796 797static CursorPtr dmxFindCursor(DMXScreenInfo *start) 798{ 799 DMXScreenInfo *pt; 800 801 if (!start || !start->over) 802 return GetSpriteCursor(inputInfo.pointer); 803 for (pt = start->over; /* condition at end of loop */; pt = pt->over) { 804 if (pt->cursor) 805 return pt->cursor; 806 if (pt == start) 807 break; 808 } 809 return GetSpriteCursor(inputInfo.pointer); 810} 811 812/** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This 813 * function is usually called via #dmxPointerSpriteFuncs, except during 814 * reconfiguration when the cursor is repositioned to force an update on 815 * newley overlapping screens and on screens that no longer overlap. 816 * 817 * The coords (x,y) are in global coord space. We'll loop over the 818 * back-end screens and see if they contain the global coord. If so, call 819 * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen. 820 */ 821void dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 822{ 823 DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; 824 DMXScreenInfo *pt; 825 826 DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y); 827 828 if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { 829 _dmxMoveCursor(pScreen, x, y); 830 return; 831 } 832 833 for (pt = start->over; /* condition at end of loop */; pt = pt->over) { 834 if (pt->cursorNotShared) 835 continue; 836 if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { 837 if (/* pt != start && */ !pt->cursorVisible) { 838 if (!pt->cursor) { 839 /* This only happens during 840 * reconfiguration when a new overlap 841 * occurs. */ 842 CursorPtr pCursor; 843 844 if ((pCursor = dmxFindCursor(start))) 845 _dmxRealizeCursor(screenInfo.screens[pt->index], 846 pt->cursor = pCursor); 847 848 } 849 _dmxSetCursor(screenInfo.screens[pt->index], 850 pt->cursor, 851 x + start->rootXOrigin - pt->rootXOrigin, 852 y + start->rootYOrigin - pt->rootYOrigin); 853 } 854 _dmxMoveCursor(screenInfo.screens[pt->index], 855 x + start->rootXOrigin - pt->rootXOrigin, 856 y + start->rootYOrigin - pt->rootYOrigin); 857 } else if (/* pt != start && */ pt->cursorVisible) { 858 _dmxSetCursor(screenInfo.screens[pt->index], 859 NULL, 860 x + start->rootXOrigin - pt->rootXOrigin, 861 y + start->rootYOrigin - pt->rootYOrigin); 862 } 863 if (pt == start) 864 break; 865 } 866} 867 868static void dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) 869{ 870 DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; 871 DMXScreenInfo *pt; 872 int GX, GY, gx, gy; 873 874 DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n", 875 pScreen->myNum, start, pCursor, x, y); 876 877 /* We do this check here because of two cases: 878 * 879 * 1) if a client calls XWarpPointer() 880 * and Xinerama is not running, we can 881 * have mi's notion of the pointer 882 * position out of phase with DMX's 883 * notion. 884 * 885 * 2) if a down button is held while the 886 * cursor moves outside the root window, 887 * mi's notion of the pointer position 888 * is out of phase with DMX's notion and 889 * the cursor can remain visible when it 890 * shouldn't be. */ 891 892 dmxGetGlobalPosition(&GX, &GY); 893 gx = start->rootXOrigin + x; 894 gy = start->rootYOrigin + y; 895 if (x && y && (GX != gx || GY != gy)) 896 dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK); 897 898 if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { 899 _dmxSetCursor(pScreen, pCursor, x, y); 900 return; 901 } 902 903 for (pt = start->over; /* condition at end of loop */; pt = pt->over) { 904 if (pt->cursorNotShared) 905 continue; 906 if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { 907 _dmxSetCursor(screenInfo.screens[pt->index], pCursor, 908 x + start->rootXOrigin - pt->rootXOrigin, 909 y + start->rootYOrigin - pt->rootYOrigin); 910 } else { 911 _dmxSetCursor(screenInfo.screens[pt->index], NULL, 912 x + start->rootXOrigin - pt->rootXOrigin, 913 y + start->rootYOrigin - pt->rootYOrigin); 914 } 915 if (pt == start) 916 break; 917 } 918} 919 920 921/** This routine is used by the backend input routines to hide the 922 * cursor on a screen that is being used for relative input. \see 923 * dmxbackend.c */ 924void dmxHideCursor(DMXScreenInfo *dmxScreen) 925{ 926 int x, y; 927 ScreenPtr pScreen = screenInfo.screens[dmxScreen->index]; 928 929 dmxGetGlobalPosition(&x, &y); 930 _dmxSetCursor(pScreen, NULL, x, y); 931} 932 933/** This routine is called during reconfiguration to make sure the 934 * cursor is visible. */ 935void dmxCheckCursor(void) 936{ 937 int i; 938 int x, y; 939 ScreenPtr pScreen; 940 DMXScreenInfo *firstScreen; 941 942 dmxGetGlobalPosition(&x, &y); 943 firstScreen = dmxFindFirstScreen(x, y); 944 945 DMXDBG2("dmxCheckCursor %d %d\n", x, y); 946 for (i = 0; i < dmxNumScreens; i++) { 947 DMXScreenInfo *dmxScreen = &dmxScreens[i]; 948 pScreen = screenInfo.screens[dmxScreen->index]; 949 950 if (!dmxOnScreen(x, y, dmxScreen)) { 951 if (firstScreen && i == miPointerGetScreen(inputInfo.pointer)->myNum) 952 miPointerSetScreen(inputInfo.pointer, firstScreen->index, x, y); 953 _dmxSetCursor(pScreen, NULL, 954 x - dmxScreen->rootXOrigin, 955 y - dmxScreen->rootYOrigin); 956 } else { 957 if (!dmxScreen->cursor) { 958 CursorPtr pCursor; 959 960 if ((pCursor = dmxFindCursor(dmxScreen))) { 961 _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor); 962 } 963 } 964 _dmxSetCursor(pScreen, dmxScreen->cursor, 965 x - dmxScreen->rootXOrigin, 966 y - dmxScreen->rootYOrigin); 967 } 968 } 969 DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y); 970} 971 972static Bool dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr) 973{ 974 return TRUE; 975} 976 977static void dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr) 978{ 979} 980 981miPointerSpriteFuncRec dmxPointerSpriteFuncs = 982{ 983 dmxRealizeCursor, 984 dmxUnrealizeCursor, 985 dmxSetCursor, 986 dmxMoveCursor, 987 dmxDeviceCursorInitialize, 988 dmxDeviceCursorCleanup 989}; 990