1/* 2 * misprite.c 3 * 4 * machine independent software sprite routines 5 */ 6 7/* 8 9Copyright 1989, 1998 The Open Group 10 11Permission to use, copy, modify, distribute, and sell this software and its 12documentation for any purpose is hereby granted without fee, provided that 13the above copyright notice appear in all copies and that both that 14copyright notice and this permission notice appear in supporting 15documentation. 16 17The above copyright notice and this permission notice shall be included in 18all copies or substantial portions of the Software. 19 20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 24AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 25CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 27Except as contained in this notice, the name of The Open Group shall not be 28used in advertising or otherwise to promote the sale, use or other dealings 29in this Software without prior written authorization from The Open Group. 30*/ 31 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include <X11/X.h> 37#include <X11/Xproto.h> 38#include "misc.h" 39#include "pixmapstr.h" 40#include "input.h" 41#include "mi.h" 42#include "cursorstr.h" 43#include <X11/fonts/font.h> 44#include "scrnintstr.h" 45#include "colormapst.h" 46#include "windowstr.h" 47#include "gcstruct.h" 48#include "mipointer.h" 49#include "misprite.h" 50#include "dixfontstr.h" 51#include <X11/fonts/fontstruct.h> 52#include "inputstr.h" 53#include "damage.h" 54 55typedef struct { 56 CursorPtr pCursor; 57 int x; /* cursor hotspot */ 58 int y; 59 BoxRec saved; /* saved area from the screen */ 60 Bool isUp; /* cursor in frame buffer */ 61 Bool shouldBeUp; /* cursor should be displayed */ 62 WindowPtr pCacheWin; /* window the cursor last seen in */ 63 Bool isInCacheWin; 64 Bool checkPixels; /* check colormap collision */ 65 ScreenPtr pScreen; 66} miCursorInfoRec, *miCursorInfoPtr; 67 68/* 69 * per screen information 70 */ 71 72typedef struct { 73 /* screen procedures */ 74 CloseScreenProcPtr CloseScreen; 75 GetImageProcPtr GetImage; 76 GetSpansProcPtr GetSpans; 77 SourceValidateProcPtr SourceValidate; 78 79 /* window procedures */ 80 CopyWindowProcPtr CopyWindow; 81 82 /* colormap procedures */ 83 InstallColormapProcPtr InstallColormap; 84 StoreColorsProcPtr StoreColors; 85 86 /* os layer procedures */ 87 ScreenBlockHandlerProcPtr BlockHandler; 88 89 /* device cursor procedures */ 90 DeviceCursorInitializeProcPtr DeviceCursorInitialize; 91 DeviceCursorCleanupProcPtr DeviceCursorCleanup; 92 93 xColorItem colors[2]; 94 ColormapPtr pInstalledMap; 95 ColormapPtr pColormap; 96 VisualPtr pVisual; 97 DamagePtr pDamage; /* damage tracking structure */ 98 Bool damageRegistered; 99 int numberOfCursors; 100} miSpriteScreenRec, *miSpriteScreenPtr; 101 102#define SOURCE_COLOR 0 103#define MASK_COLOR 1 104 105/* 106 * Overlap BoxPtr and Box elements 107 */ 108#define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \ 109 (((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \ 110 ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2)) 111 112/* 113 * Overlap BoxPtr, origins, and rectangle 114 */ 115#define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \ 116 BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h)) 117 118/* 119 * Overlap BoxPtr, origins and RectPtr 120 */ 121#define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \ 122 ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \ 123 (int)((pRect)->width), (int)((pRect)->height)) 124/* 125 * Overlap BoxPtr and horizontal span 126 */ 127#define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y)) 128 129#define LINE_SORT(x1,y1,x2,y2) \ 130{ int _t; \ 131 if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \ 132 if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } } 133 134#define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \ 135 BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2)) 136 137 138#define SPRITE_DEBUG_ENABLE 0 139#if SPRITE_DEBUG_ENABLE 140#define SPRITE_DEBUG(x) ErrorF x 141#else 142#define SPRITE_DEBUG(x) 143#endif 144 145#define MISPRITE(dev) \ 146 ((!IsMaster(dev) && !dev->u.master) ? \ 147 (miCursorInfoPtr)dixLookupPrivate(&dev->devPrivates, miSpriteDevPrivatesKey) : \ 148 (miCursorInfoPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miSpriteDevPrivatesKey)) 149 150static void 151miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) 152{ 153 if (pScreenPriv->damageRegistered) { 154 DamageUnregister (&(pScreen->GetScreenPixmap(pScreen)->drawable), 155 pScreenPriv->pDamage); 156 pScreenPriv->damageRegistered = 0; 157 } 158} 159 160static void 161miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) 162{ 163 if (!pScreenPriv->damageRegistered) { 164 pScreenPriv->damageRegistered = 1; 165 DamageRegister (&(pScreen->GetScreenPixmap(pScreen)->drawable), 166 pScreenPriv->pDamage); 167 } 168} 169 170static void 171miSpriteIsUp(miCursorInfoPtr pDevCursor) 172{ 173 pDevCursor->isUp = TRUE; 174} 175 176static void 177miSpriteIsDown(miCursorInfoPtr pDevCursor) 178{ 179 pDevCursor->isUp = FALSE; 180} 181 182/* 183 * screen wrappers 184 */ 185 186static DevPrivateKeyRec miSpriteScreenKeyRec; 187#define miSpriteScreenKey (&miSpriteScreenKeyRec) 188#define GetSpriteScreen(pScreen) \ 189 (dixLookupPrivate(&(pScreen)->devPrivates, miSpriteScreenKey)) 190static DevPrivateKeyRec miSpriteDevPrivatesKeyRec; 191#define miSpriteDevPrivatesKey (&miSpriteDevPrivatesKeyRec) 192 193static Bool miSpriteCloseScreen(int i, ScreenPtr pScreen); 194static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, 195 int w, int h, unsigned int format, 196 unsigned long planemask, char *pdstLine); 197static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax, 198 DDXPointPtr ppt, int *pwidth, int nspans, 199 char *pdstStart); 200static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, 201 int width, int height, 202 unsigned int subWindowMode); 203static void miSpriteCopyWindow (WindowPtr pWindow, 204 DDXPointRec ptOldOrg, 205 RegionPtr prgnSrc); 206static void miSpriteBlockHandler(int i, pointer blockData, 207 pointer pTimeout, 208 pointer pReadMask); 209static void miSpriteInstallColormap(ColormapPtr pMap); 210static void miSpriteStoreColors(ColormapPtr pMap, int ndef, 211 xColorItem *pdef); 212 213static void miSpriteComputeSaved(DeviceIntPtr pDev, 214 ScreenPtr pScreen); 215 216static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, 217 ScreenPtr pScreen); 218static void miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, 219 ScreenPtr pScreen); 220 221#define SCREEN_PROLOGUE(pPriv, pScreen, field) ((pScreen)->field = \ 222 (pPriv)->field) 223#define SCREEN_EPILOGUE(pPriv, pScreen, field)\ 224 ((pPriv)->field = (pScreen)->field, (pScreen)->field = miSprite##field) 225 226/* 227 * pointer-sprite method table 228 */ 229 230static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 231 CursorPtr pCursor); 232static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 233 CursorPtr pCursor); 234static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 235 CursorPtr pCursor, int x, int y); 236static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, 237 int x, int y); 238 239miPointerSpriteFuncRec miSpritePointerFuncs = { 240 miSpriteRealizeCursor, 241 miSpriteUnrealizeCursor, 242 miSpriteSetCursor, 243 miSpriteMoveCursor, 244 miSpriteDeviceCursorInitialize, 245 miSpriteDeviceCursorCleanup, 246}; 247 248/* 249 * other misc functions 250 */ 251 252static void miSpriteRemoveCursor(DeviceIntPtr pDev, 253 ScreenPtr pScreen); 254static void miSpriteSaveUnderCursor(DeviceIntPtr pDev, 255 ScreenPtr pScreen); 256static void miSpriteRestoreCursor(DeviceIntPtr pDev, 257 ScreenPtr pScreen); 258 259static void 260miSpriteRegisterBlockHandler(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) 261{ 262 if (!pScreenPriv->BlockHandler) { 263 pScreenPriv->BlockHandler = pScreen->BlockHandler; 264 pScreen->BlockHandler = miSpriteBlockHandler; 265 } 266} 267 268static void 269miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) 270{ 271 ScreenPtr pScreen = closure; 272 miCursorInfoPtr pCursorInfo; 273 DeviceIntPtr pDev; 274 275 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) 276 { 277 if (DevHasCursor(pDev)) 278 { 279 pCursorInfo = MISPRITE(pDev); 280 281 if (pCursorInfo->isUp && 282 pCursorInfo->pScreen == pScreen && 283 RegionContainsRect(pRegion, &pCursorInfo->saved) != rgnOUT) 284 { 285 SPRITE_DEBUG(("Damage remove\n")); 286 miSpriteRemoveCursor (pDev, pScreen); 287 } 288 } 289 } 290} 291 292/* 293 * miSpriteInitialize -- called from device-dependent screen 294 * initialization proc after all of the function pointers have 295 * been stored in the screen structure. 296 */ 297 298Bool 299miSpriteInitialize (ScreenPtr pScreen, 300 miPointerScreenFuncPtr screenFuncs) 301{ 302 miSpriteScreenPtr pScreenPriv; 303 VisualPtr pVisual; 304 305 if (!DamageSetup (pScreen)) 306 return FALSE; 307 308 if (!dixRegisterPrivateKey(&miSpriteScreenKeyRec, PRIVATE_SCREEN, 0)) 309 return FALSE; 310 311 if (!dixRegisterPrivateKey(&miSpriteDevPrivatesKeyRec, PRIVATE_DEVICE, 0)) 312 return FALSE; 313 314 pScreenPriv = malloc(sizeof (miSpriteScreenRec)); 315 if (!pScreenPriv) 316 return FALSE; 317 318 pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage, 319 NULL, 320 DamageReportRawRegion, 321 TRUE, 322 pScreen, 323 pScreen); 324 325 if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE)) 326 { 327 free(pScreenPriv); 328 return FALSE; 329 } 330 for (pVisual = pScreen->visuals; 331 pVisual->vid != pScreen->rootVisual; 332 pVisual++) 333 ; 334 pScreenPriv->pVisual = pVisual; 335 pScreenPriv->CloseScreen = pScreen->CloseScreen; 336 pScreenPriv->GetImage = pScreen->GetImage; 337 pScreenPriv->GetSpans = pScreen->GetSpans; 338 pScreenPriv->SourceValidate = pScreen->SourceValidate; 339 340 pScreenPriv->CopyWindow = pScreen->CopyWindow; 341 342 pScreenPriv->InstallColormap = pScreen->InstallColormap; 343 pScreenPriv->StoreColors = pScreen->StoreColors; 344 345 pScreenPriv->BlockHandler = NULL; 346 347 pScreenPriv->DeviceCursorInitialize = pScreen->DeviceCursorInitialize; 348 pScreenPriv->DeviceCursorCleanup = pScreen->DeviceCursorCleanup; 349 350 pScreenPriv->pInstalledMap = NULL; 351 pScreenPriv->pColormap = NULL; 352 pScreenPriv->colors[SOURCE_COLOR].red = 0; 353 pScreenPriv->colors[SOURCE_COLOR].green = 0; 354 pScreenPriv->colors[SOURCE_COLOR].blue = 0; 355 pScreenPriv->colors[MASK_COLOR].red = 0; 356 pScreenPriv->colors[MASK_COLOR].green = 0; 357 pScreenPriv->colors[MASK_COLOR].blue = 0; 358 pScreenPriv->damageRegistered = 0; 359 pScreenPriv->numberOfCursors = 0; 360 361 dixSetPrivate(&pScreen->devPrivates, miSpriteScreenKey, pScreenPriv); 362 363 pScreen->CloseScreen = miSpriteCloseScreen; 364 pScreen->GetImage = miSpriteGetImage; 365 pScreen->GetSpans = miSpriteGetSpans; 366 pScreen->SourceValidate = miSpriteSourceValidate; 367 368 pScreen->CopyWindow = miSpriteCopyWindow; 369 pScreen->InstallColormap = miSpriteInstallColormap; 370 pScreen->StoreColors = miSpriteStoreColors; 371 372 return TRUE; 373} 374 375/* 376 * Screen wrappers 377 */ 378 379/* 380 * CloseScreen wrapper -- unwrap everything, free the private data 381 * and call the wrapped function 382 */ 383 384static Bool 385miSpriteCloseScreen (int i, ScreenPtr pScreen) 386{ 387 miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen); 388 389 pScreen->CloseScreen = pScreenPriv->CloseScreen; 390 pScreen->GetImage = pScreenPriv->GetImage; 391 pScreen->GetSpans = pScreenPriv->GetSpans; 392 pScreen->SourceValidate = pScreenPriv->SourceValidate; 393 pScreen->InstallColormap = pScreenPriv->InstallColormap; 394 pScreen->StoreColors = pScreenPriv->StoreColors; 395 396 DamageDestroy (pScreenPriv->pDamage); 397 398 free(pScreenPriv); 399 400 return (*pScreen->CloseScreen) (i, pScreen); 401} 402 403static void 404miSpriteGetImage (DrawablePtr pDrawable, int sx, int sy, int w, int h, 405 unsigned int format, unsigned long planemask, 406 char *pdstLine) 407{ 408 ScreenPtr pScreen = pDrawable->pScreen; 409 DeviceIntPtr pDev; 410 miCursorInfoPtr pCursorInfo; 411 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); 412 413 SCREEN_PROLOGUE (pPriv, pScreen, GetImage); 414 415 if (pDrawable->type == DRAWABLE_WINDOW) 416 { 417 for(pDev = inputInfo.devices; pDev; pDev = pDev->next) 418 { 419 if (DevHasCursor(pDev)) 420 { 421 pCursorInfo = MISPRITE(pDev); 422 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && 423 ORG_OVERLAP(&pCursorInfo->saved,pDrawable->x,pDrawable->y, 424 sx, sy, w, h)) 425 { 426 SPRITE_DEBUG (("GetImage remove\n")); 427 miSpriteRemoveCursor (pDev, pScreen); 428 } 429 } 430 } 431 } 432 433 (*pScreen->GetImage) (pDrawable, sx, sy, w, h, 434 format, planemask, pdstLine); 435 436 SCREEN_EPILOGUE (pPriv, pScreen, GetImage); 437} 438 439static void 440miSpriteGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, 441 int *pwidth, int nspans, char *pdstStart) 442{ 443 ScreenPtr pScreen = pDrawable->pScreen; 444 DeviceIntPtr pDev; 445 miCursorInfoPtr pCursorInfo; 446 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); 447 448 SCREEN_PROLOGUE (pPriv, pScreen, GetSpans); 449 450 if (pDrawable->type == DRAWABLE_WINDOW) 451 { 452 for(pDev = inputInfo.devices; pDev; pDev = pDev->next) 453 { 454 if (DevHasCursor(pDev)) 455 { 456 pCursorInfo = MISPRITE(pDev); 457 458 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) 459 { 460 DDXPointPtr pts; 461 int *widths; 462 int nPts; 463 int xorg, 464 yorg; 465 466 xorg = pDrawable->x; 467 yorg = pDrawable->y; 468 469 for (pts = ppt, widths = pwidth, nPts = nspans; 470 nPts--; 471 pts++, widths++) 472 { 473 if (SPN_OVERLAP(&pCursorInfo->saved,pts->y+yorg, 474 pts->x+xorg,*widths)) 475 { 476 SPRITE_DEBUG (("GetSpans remove\n")); 477 miSpriteRemoveCursor (pDev, pScreen); 478 break; 479 } 480 } 481 } 482 } 483 } 484 } 485 486 (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); 487 488 SCREEN_EPILOGUE (pPriv, pScreen, GetSpans); 489} 490 491static void 492miSpriteSourceValidate (DrawablePtr pDrawable, int x, int y, int width, 493 int height, unsigned int subWindowMode) 494{ 495 ScreenPtr pScreen = pDrawable->pScreen; 496 DeviceIntPtr pDev; 497 miCursorInfoPtr pCursorInfo; 498 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); 499 500 SCREEN_PROLOGUE (pPriv, pScreen, SourceValidate); 501 502 if (pDrawable->type == DRAWABLE_WINDOW) 503 { 504 for(pDev = inputInfo.devices; pDev; pDev = pDev->next) 505 { 506 if (DevHasCursor(pDev)) 507 { 508 pCursorInfo = MISPRITE(pDev); 509 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && 510 ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y, 511 x, y, width, height)) 512 { 513 SPRITE_DEBUG (("SourceValidate remove\n")); 514 miSpriteRemoveCursor (pDev, pScreen); 515 } 516 } 517 } 518 } 519 520 if (pScreen->SourceValidate) 521 (*pScreen->SourceValidate) (pDrawable, x, y, width, height, subWindowMode); 522 523 SCREEN_EPILOGUE (pPriv, pScreen, SourceValidate); 524} 525 526static void 527miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 528{ 529 ScreenPtr pScreen = pWindow->drawable.pScreen; 530 DeviceIntPtr pDev; 531 miCursorInfoPtr pCursorInfo; 532 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); 533 534 SCREEN_PROLOGUE (pPriv, pScreen, CopyWindow); 535 536 for(pDev = inputInfo.devices; pDev; pDev = pDev->next) 537 { 538 if (DevHasCursor(pDev)) 539 { 540 pCursorInfo = MISPRITE(pDev); 541 /* 542 * Damage will take care of destination check 543 */ 544 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && 545 RegionContainsRect(prgnSrc, &pCursorInfo->saved) != rgnOUT) 546 { 547 SPRITE_DEBUG (("CopyWindow remove\n")); 548 miSpriteRemoveCursor (pDev, pScreen); 549 } 550 } 551 } 552 553 (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); 554 SCREEN_EPILOGUE (pPriv, pScreen, CopyWindow); 555} 556 557static void 558miSpriteBlockHandler (int i, pointer blockData, pointer pTimeout, 559 pointer pReadmask) 560{ 561 ScreenPtr pScreen = screenInfo.screens[i]; 562 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); 563 DeviceIntPtr pDev; 564 miCursorInfoPtr pCursorInfo; 565 Bool WorkToDo = FALSE; 566 567 for(pDev = inputInfo.devices; pDev; pDev = pDev->next) 568 { 569 if (DevHasCursor(pDev)) 570 { 571 pCursorInfo = MISPRITE(pDev); 572 if (pCursorInfo && !pCursorInfo->isUp 573 && pCursorInfo->pScreen == pScreen 574 && pCursorInfo->shouldBeUp) 575 { 576 SPRITE_DEBUG (("BlockHandler save")); 577 miSpriteSaveUnderCursor (pDev, pScreen); 578 } 579 } 580 } 581 for(pDev = inputInfo.devices; pDev; pDev = pDev->next) 582 { 583 if (DevHasCursor(pDev)) 584 { 585 pCursorInfo = MISPRITE(pDev); 586 if (pCursorInfo && !pCursorInfo->isUp && 587 pCursorInfo->pScreen == pScreen && 588 pCursorInfo->shouldBeUp) 589 { 590 SPRITE_DEBUG (("BlockHandler restore\n")); 591 miSpriteRestoreCursor (pDev, pScreen); 592 if (!pCursorInfo->isUp) 593 WorkToDo = TRUE; 594 } 595 } 596 } 597 598 SCREEN_PROLOGUE(pPriv, pScreen, BlockHandler); 599 600 (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); 601 602 if (WorkToDo) 603 SCREEN_EPILOGUE(pPriv, pScreen, BlockHandler); 604 else 605 pPriv->BlockHandler = NULL; 606} 607 608static void 609miSpriteInstallColormap (ColormapPtr pMap) 610{ 611 ScreenPtr pScreen = pMap->pScreen; 612 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); 613 614 SCREEN_PROLOGUE(pPriv, pScreen, InstallColormap); 615 616 (*pScreen->InstallColormap) (pMap); 617 618 SCREEN_EPILOGUE(pPriv, pScreen, InstallColormap); 619 620 /* InstallColormap can be called before devices are initialized. */ 621 pPriv->pInstalledMap = pMap; 622 if (pPriv->pColormap != pMap) 623 { 624 DeviceIntPtr pDev; 625 miCursorInfoPtr pCursorInfo; 626 for (pDev = inputInfo.devices; pDev; pDev = pDev->next) 627 { 628 if (DevHasCursor(pDev)) 629 { 630 pCursorInfo = MISPRITE(pDev); 631 pCursorInfo->checkPixels = TRUE; 632 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) 633 miSpriteRemoveCursor(pDev, pScreen); 634 } 635 } 636 637 } 638} 639 640static void 641miSpriteStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef) 642{ 643 ScreenPtr pScreen = pMap->pScreen; 644 miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); 645 int i; 646 int updated; 647 VisualPtr pVisual; 648 DeviceIntPtr pDev; 649 miCursorInfoPtr pCursorInfo; 650 651 SCREEN_PROLOGUE(pPriv, pScreen, StoreColors); 652 653 (*pScreen->StoreColors) (pMap, ndef, pdef); 654 655 SCREEN_EPILOGUE(pPriv, pScreen, StoreColors); 656 657 if (pPriv->pColormap == pMap) 658 { 659 updated = 0; 660 pVisual = pMap->pVisual; 661 if (pVisual->class == DirectColor) 662 { 663 /* Direct color - match on any of the subfields */ 664 665#define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask))) 666 667#define UpdateDAC(dev, plane,dac,mask) {\ 668 if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\ 669 dev->colors[plane].dac = pdef[i].dac; \ 670 updated = 1; \ 671 } \ 672} 673 674#define CheckDirect(dev, plane) \ 675 UpdateDAC(dev, plane,red,redMask) \ 676 UpdateDAC(dev, plane,green,greenMask) \ 677 UpdateDAC(dev, plane,blue,blueMask) 678 679 for (i = 0; i < ndef; i++) 680 { 681 CheckDirect (pPriv, SOURCE_COLOR) 682 CheckDirect (pPriv, MASK_COLOR) 683 } 684 } 685 else 686 { 687 /* PseudoColor/GrayScale - match on exact pixel */ 688 for (i = 0; i < ndef; i++) 689 { 690 if (pdef[i].pixel == 691 pPriv->colors[SOURCE_COLOR].pixel) 692 { 693 pPriv->colors[SOURCE_COLOR] = pdef[i]; 694 if (++updated == 2) 695 break; 696 } 697 if (pdef[i].pixel == 698 pPriv->colors[MASK_COLOR].pixel) 699 { 700 pPriv->colors[MASK_COLOR] = pdef[i]; 701 if (++updated == 2) 702 break; 703 } 704 } 705 } 706 if (updated) 707 { 708 for(pDev = inputInfo.devices; pDev; pDev = pDev->next) 709 { 710 if (DevHasCursor(pDev)) 711 { 712 pCursorInfo = MISPRITE(pDev); 713 pCursorInfo->checkPixels = TRUE; 714 if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) 715 miSpriteRemoveCursor (pDev, pScreen); 716 } 717 } 718 } 719 } 720} 721 722static void 723miSpriteFindColors (miCursorInfoPtr pDevCursor, ScreenPtr pScreen) 724{ 725 miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen); 726 CursorPtr pCursor; 727 xColorItem *sourceColor, *maskColor; 728 729 pCursor = pDevCursor->pCursor; 730 sourceColor = &pScreenPriv->colors[SOURCE_COLOR]; 731 maskColor = &pScreenPriv->colors[MASK_COLOR]; 732 if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap || 733 !(pCursor->foreRed == sourceColor->red && 734 pCursor->foreGreen == sourceColor->green && 735 pCursor->foreBlue == sourceColor->blue && 736 pCursor->backRed == maskColor->red && 737 pCursor->backGreen == maskColor->green && 738 pCursor->backBlue == maskColor->blue)) 739 { 740 pScreenPriv->pColormap = pScreenPriv->pInstalledMap; 741 sourceColor->red = pCursor->foreRed; 742 sourceColor->green = pCursor->foreGreen; 743 sourceColor->blue = pCursor->foreBlue; 744 FakeAllocColor (pScreenPriv->pColormap, sourceColor); 745 maskColor->red = pCursor->backRed; 746 maskColor->green = pCursor->backGreen; 747 maskColor->blue = pCursor->backBlue; 748 FakeAllocColor (pScreenPriv->pColormap, maskColor); 749 /* "free" the pixels right away, don't let this confuse you */ 750 FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel); 751 FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel); 752 } 753 754 pDevCursor->checkPixels = FALSE; 755 756} 757 758/* 759 * miPointer interface routines 760 */ 761 762#define SPRITE_PAD 8 763 764static Bool 765miSpriteRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 766{ 767 miCursorInfoPtr pCursorInfo; 768 769 if (!IsMaster(pDev) && !pDev->u.master) 770 return FALSE; 771 772 pCursorInfo = MISPRITE(pDev); 773 774 if (pCursor == pCursorInfo->pCursor) 775 pCursorInfo->checkPixels = TRUE; 776 777 return miDCRealizeCursor(pScreen, pCursor); 778} 779 780static Bool 781miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) 782{ 783 return miDCUnrealizeCursor(pScreen, pCursor); 784} 785 786static void 787miSpriteSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen, 788 CursorPtr pCursor, int x, int y) 789{ 790 miCursorInfoPtr pPointer; 791 miSpriteScreenPtr pScreenPriv; 792 793 if (!IsMaster(pDev) && !pDev->u.master) 794 return; 795 796 pPointer = MISPRITE(pDev); 797 pScreenPriv = GetSpriteScreen(pScreen); 798 799 if (!pCursor) 800 { 801 if (pPointer->shouldBeUp) 802 --pScreenPriv->numberOfCursors; 803 pPointer->shouldBeUp = FALSE; 804 if (pPointer->isUp) 805 miSpriteRemoveCursor (pDev, pScreen); 806 if (pScreenPriv->numberOfCursors == 0) 807 miSpriteDisableDamage(pScreen, pScreenPriv); 808 pPointer->pCursor = 0; 809 return; 810 } 811 if (!pPointer->shouldBeUp) 812 pScreenPriv->numberOfCursors++; 813 pPointer->shouldBeUp = TRUE; 814 if (!pPointer->isUp) 815 miSpriteRegisterBlockHandler(pScreen, pScreenPriv); 816 if (pPointer->x == x && 817 pPointer->y == y && 818 pPointer->pCursor == pCursor && 819 !pPointer->checkPixels) 820 { 821 return; 822 } 823 pPointer->x = x; 824 pPointer->y = y; 825 pPointer->pCacheWin = NullWindow; 826 if (pPointer->checkPixels || pPointer->pCursor != pCursor) 827 { 828 pPointer->pCursor = pCursor; 829 miSpriteFindColors (pPointer, pScreen); 830 } 831 if (pPointer->isUp) { 832 /* TODO: reimplement flicker-free MoveCursor */ 833 SPRITE_DEBUG (("SetCursor remove %d\n", pDev->id)); 834 miSpriteRemoveCursor (pDev, pScreen); 835 } 836 837 if (!pPointer->isUp && pPointer->pCursor) 838 { 839 SPRITE_DEBUG (("SetCursor restore %d\n", pDev->id)); 840 miSpriteSaveUnderCursor(pDev, pScreen); 841 miSpriteRestoreCursor (pDev, pScreen); 842 } 843 844} 845 846static void 847miSpriteMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 848{ 849 CursorPtr pCursor; 850 851 if (!IsMaster(pDev) && !pDev->u.master) 852 return; 853 854 pCursor = MISPRITE(pDev)->pCursor; 855 856 miSpriteSetCursor (pDev, pScreen, pCursor, x, y); 857} 858 859 860static Bool 861miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) 862{ 863 miCursorInfoPtr pCursorInfo; 864 int ret = FALSE; 865 866 pCursorInfo = malloc(sizeof(miCursorInfoRec)); 867 if (!pCursorInfo) 868 return FALSE; 869 870 pCursorInfo->pCursor = NULL; 871 pCursorInfo->x = 0; 872 pCursorInfo->y = 0; 873 pCursorInfo->isUp = FALSE; 874 pCursorInfo->shouldBeUp = FALSE; 875 pCursorInfo->pCacheWin = NullWindow; 876 pCursorInfo->isInCacheWin = FALSE; 877 pCursorInfo->checkPixels = TRUE; 878 pCursorInfo->pScreen = FALSE; 879 880 ret = miDCDeviceInitialize(pDev, pScreen); 881 if (!ret) 882 { 883 free(pCursorInfo); 884 pCursorInfo = NULL; 885 } 886 dixSetPrivate(&pDev->devPrivates, miSpriteDevPrivatesKey, pCursorInfo); 887 return ret; 888} 889 890static void 891miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) 892{ 893 if (DevHasCursor(pDev)) 894 miDCDeviceCleanup(pDev, pScreen); 895} 896 897/* 898 * undraw/draw cursor 899 */ 900 901static void 902miSpriteRemoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen) 903{ 904 miSpriteScreenPtr pScreenPriv; 905 miCursorInfoPtr pCursorInfo; 906 907 908 if (!IsMaster(pDev) && !pDev->u.master) 909 return; 910 911 DamageDrawInternal (pScreen, TRUE); 912 pScreenPriv = GetSpriteScreen(pScreen); 913 pCursorInfo = MISPRITE(pDev); 914 915 miSpriteIsDown(pCursorInfo); 916 miSpriteRegisterBlockHandler(pScreen, pScreenPriv); 917 pCursorInfo->pCacheWin = NullWindow; 918 miSpriteDisableDamage(pScreen, pScreenPriv); 919 if (!miDCRestoreUnderCursor(pDev, 920 pScreen, 921 pCursorInfo->saved.x1, 922 pCursorInfo->saved.y1, 923 pCursorInfo->saved.x2 - 924 pCursorInfo->saved.x1, 925 pCursorInfo->saved.y2 - 926 pCursorInfo->saved.y1)) 927 { 928 miSpriteIsUp(pCursorInfo); 929 } 930 miSpriteEnableDamage(pScreen, pScreenPriv); 931 DamageDrawInternal (pScreen, FALSE); 932} 933 934/* 935 * Called from the block handler, saves area under cursor 936 * before waiting for something to do. 937 */ 938 939static void 940miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen) 941{ 942 miSpriteScreenPtr pScreenPriv; 943 int x, y; 944 CursorPtr pCursor; 945 miCursorInfoPtr pCursorInfo; 946 947 if (!IsMaster(pDev) && !pDev->u.master) 948 return; 949 950 DamageDrawInternal (pScreen, TRUE); 951 pScreenPriv = GetSpriteScreen(pScreen); 952 pCursorInfo = MISPRITE(pDev); 953 954 miSpriteComputeSaved (pDev, pScreen); 955 pCursor = pCursorInfo->pCursor; 956 957 x = pCursorInfo->x - (int)pCursor->bits->xhot; 958 y = pCursorInfo->y - (int)pCursor->bits->yhot; 959 miSpriteDisableDamage(pScreen, pScreenPriv); 960 961 miDCSaveUnderCursor(pDev, 962 pScreen, 963 pCursorInfo->saved.x1, 964 pCursorInfo->saved.y1, 965 pCursorInfo->saved.x2 - 966 pCursorInfo->saved.x1, 967 pCursorInfo->saved.y2 - 968 pCursorInfo->saved.y1); 969 SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id)); 970 miSpriteEnableDamage(pScreen, pScreenPriv); 971 DamageDrawInternal (pScreen, FALSE); 972} 973 974 975/* 976 * Called from the block handler, restores the cursor 977 * before waiting for something to do. 978 */ 979 980static void 981miSpriteRestoreCursor (DeviceIntPtr pDev, ScreenPtr pScreen) 982{ 983 miSpriteScreenPtr pScreenPriv; 984 int x, y; 985 CursorPtr pCursor; 986 miCursorInfoPtr pCursorInfo; 987 988 if (!IsMaster(pDev) && !pDev->u.master) 989 return; 990 991 DamageDrawInternal (pScreen, TRUE); 992 pScreenPriv = GetSpriteScreen(pScreen); 993 pCursorInfo = MISPRITE(pDev); 994 995 miSpriteComputeSaved (pDev, pScreen); 996 pCursor = pCursorInfo->pCursor; 997 998 x = pCursorInfo->x - (int)pCursor->bits->xhot; 999 y = pCursorInfo->y - (int)pCursor->bits->yhot; 1000 miSpriteDisableDamage(pScreen, pScreenPriv); 1001 SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id)); 1002 if (pCursorInfo->checkPixels) 1003 miSpriteFindColors (pCursorInfo, pScreen); 1004 if (miDCPutUpCursor(pDev, pScreen, 1005 pCursor, x, y, 1006 pScreenPriv->colors[SOURCE_COLOR].pixel, 1007 pScreenPriv->colors[MASK_COLOR].pixel)) 1008 { 1009 miSpriteIsUp(pCursorInfo); 1010 pCursorInfo->pScreen = pScreen; 1011 } 1012 miSpriteEnableDamage(pScreen, pScreenPriv); 1013 DamageDrawInternal (pScreen, FALSE); 1014} 1015 1016/* 1017 * compute the desired area of the screen to save 1018 */ 1019 1020static void 1021miSpriteComputeSaved (DeviceIntPtr pDev, ScreenPtr pScreen) 1022{ 1023 int x, y, w, h; 1024 int wpad, hpad; 1025 CursorPtr pCursor; 1026 miCursorInfoPtr pCursorInfo; 1027 1028 if (!IsMaster(pDev) && !pDev->u.master) 1029 return; 1030 1031 pCursorInfo = MISPRITE(pDev); 1032 1033 pCursor = pCursorInfo->pCursor; 1034 x = pCursorInfo->x - (int)pCursor->bits->xhot; 1035 y = pCursorInfo->y - (int)pCursor->bits->yhot; 1036 w = pCursor->bits->width; 1037 h = pCursor->bits->height; 1038 wpad = SPRITE_PAD; 1039 hpad = SPRITE_PAD; 1040 pCursorInfo->saved.x1 = x - wpad; 1041 pCursorInfo->saved.y1 = y - hpad; 1042 pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2; 1043 pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2; 1044} 1045 1046