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