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