midispcur.c revision 6747b715
1/* 2 * midispcur.c 3 * 4 * machine independent cursor display routines 5 */ 6 7 8/* 9 10Copyright 1989, 1998 The Open Group 11 12Permission to use, copy, modify, distribute, and sell this software and its 13documentation for any purpose is hereby granted without fee, provided that 14the above copyright notice appear in all copies and that both that 15copyright notice and this permission notice appear in supporting 16documentation. 17 18The above copyright notice and this permission notice shall be included in 19all copies or substantial portions of the Software. 20 21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 25AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 28Except as contained in this notice, the name of The Open Group shall not be 29used in advertising or otherwise to promote the sale, use or other dealings 30in this Software without prior written authorization from The Open Group. 31*/ 32 33#ifdef HAVE_DIX_CONFIG_H 34#include <dix-config.h> 35#endif 36 37# include <X11/X.h> 38# include "misc.h" 39# include "input.h" 40# include "cursorstr.h" 41# include "windowstr.h" 42# include "regionstr.h" 43# include "dixstruct.h" 44# include "scrnintstr.h" 45# include "servermd.h" 46# include "mipointer.h" 47# include "misprite.h" 48# include "gcstruct.h" 49 50#ifdef ARGB_CURSOR 51# include "picturestr.h" 52#endif 53 54# include "inputstr.h" 55 56/* per-screen private data */ 57static DevPrivateKeyRec miDCScreenKeyRec; 58#define miDCScreenKey (&miDCScreenKeyRec) 59 60static Bool miDCCloseScreen(int index, ScreenPtr pScreen); 61 62/* per device private data */ 63typedef struct { 64 GCPtr pSourceGC, pMaskGC; 65 GCPtr pSaveGC, pRestoreGC; 66 PixmapPtr pSave; 67#ifdef ARGB_CURSOR 68 PicturePtr pRootPicture; 69#endif 70} miDCBufferRec, *miDCBufferPtr; 71 72#define miGetDCDevice(dev, screen) \ 73 ((DevHasCursor(dev)) ? \ 74 (miDCBufferPtr)dixLookupPrivate(&dev->devPrivates, miDCDeviceKey(screen)) : \ 75 (miDCBufferPtr)dixLookupPrivate(&dev->u.master->devPrivates, miDCDeviceKey(screen))) 76 77/* 78 * The core pointer buffer will point to the index of the virtual core pointer 79 * in the pCursorBuffers array. 80 */ 81typedef struct { 82 CloseScreenProcPtr CloseScreen; 83 DevPrivateKey device_key; 84 DevPrivateKey cursor_bits_key; 85} miDCScreenRec, *miDCScreenPtr; 86 87#define miGetDCScreen(s) ((miDCScreenPtr)(dixLookupPrivate(&(s)->devPrivates, miDCScreenKey))) 88#define miDCDeviceKey(s) (miGetDCScreen(s)->device_key) 89#define miDCCursorBitsKey(s) (miGetDCScreen(s)->cursor_bits_key) 90 91/* per-cursor per-screen private data */ 92typedef struct { 93 PixmapPtr sourceBits; /* source bits */ 94 PixmapPtr maskBits; /* mask bits */ 95#ifdef ARGB_CURSOR 96 PicturePtr pPicture; 97#endif 98} miDCCursorRec, *miDCCursorPtr; 99 100Bool 101miDCInitialize (ScreenPtr pScreen, miPointerScreenFuncPtr screenFuncs) 102{ 103 miDCScreenPtr pScreenPriv; 104 105 if (!dixRegisterPrivateKey(&miDCScreenKeyRec, PRIVATE_SCREEN, 0)) 106 return FALSE; 107 108 pScreenPriv = malloc(sizeof (miDCScreenRec)); 109 if (!pScreenPriv) 110 return FALSE; 111 112 pScreenPriv->cursor_bits_key = dixCreatePrivateKey(PRIVATE_CURSOR_BITS, 0); 113 pScreenPriv->device_key = dixCreatePrivateKey(PRIVATE_DEVICE, 0); 114 if (!pScreenPriv->cursor_bits_key || !pScreenPriv->device_key) { 115 free(pScreenPriv); 116 return FALSE; 117 } 118 pScreenPriv->CloseScreen = pScreen->CloseScreen; 119 pScreen->CloseScreen = miDCCloseScreen; 120 121 dixSetPrivate(&pScreen->devPrivates, miDCScreenKey, pScreenPriv); 122 123 if (!miSpriteInitialize (pScreen, screenFuncs)) 124 { 125 free((pointer) pScreenPriv); 126 return FALSE; 127 } 128 return TRUE; 129} 130 131static Bool 132miDCCloseScreen (int index, ScreenPtr pScreen) 133{ 134 miDCScreenPtr pScreenPriv; 135 136 pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, 137 miDCScreenKey); 138 pScreen->CloseScreen = pScreenPriv->CloseScreen; 139 free((pointer) pScreenPriv); 140 return (*pScreen->CloseScreen) (index, pScreen); 141} 142 143Bool 144miDCRealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) 145{ 146 if (pCursor->bits->refcnt <= 1) 147 dixSetPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey(pScreen), NULL); 148 return TRUE; 149} 150 151#ifdef ARGB_CURSOR 152#define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win)) 153 154static VisualPtr 155miDCGetWindowVisual (WindowPtr pWin) 156{ 157 ScreenPtr pScreen = pWin->drawable.pScreen; 158 VisualID vid = wVisual (pWin); 159 int i; 160 161 for (i = 0; i < pScreen->numVisuals; i++) 162 if (pScreen->visuals[i].vid == vid) 163 return &pScreen->visuals[i]; 164 return 0; 165} 166 167static PicturePtr 168miDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin) 169{ 170 ScreenPtr pScreen = pDraw->pScreen; 171 VisualPtr pVisual; 172 PictFormatPtr pFormat; 173 XID subwindow_mode = IncludeInferiors; 174 PicturePtr pPicture; 175 int error; 176 177 pVisual = miDCGetWindowVisual (pWin); 178 if (!pVisual) 179 return 0; 180 pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual); 181 if (!pFormat) 182 return 0; 183 pPicture = CreatePicture (0, pDraw, pFormat, 184 CPSubwindowMode, &subwindow_mode, 185 serverClient, &error); 186 *ppPicture = pPicture; 187 return pPicture; 188} 189#endif 190 191static miDCCursorPtr 192miDCRealize (ScreenPtr pScreen, CursorPtr pCursor) 193{ 194 miDCCursorPtr pPriv; 195 GCPtr pGC; 196 ChangeGCVal gcvals; 197 198 pPriv = malloc(sizeof (miDCCursorRec)); 199 if (!pPriv) 200 return NULL; 201#ifdef ARGB_CURSOR 202 if (pCursor->bits->argb) 203 { 204 PixmapPtr pPixmap; 205 PictFormatPtr pFormat; 206 int error; 207 208 pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); 209 if (!pFormat) 210 { 211 free((pointer) pPriv); 212 return NULL; 213 } 214 215 pPriv->sourceBits = 0; 216 pPriv->maskBits = 0; 217 pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, 218 pCursor->bits->height, 32, 219 CREATE_PIXMAP_USAGE_SCRATCH); 220 if (!pPixmap) 221 { 222 free((pointer) pPriv); 223 return NULL; 224 } 225 pGC = GetScratchGC (32, pScreen); 226 if (!pGC) 227 { 228 (*pScreen->DestroyPixmap) (pPixmap); 229 free((pointer) pPriv); 230 return NULL; 231 } 232 ValidateGC (&pPixmap->drawable, pGC); 233 (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32, 234 0, 0, pCursor->bits->width, 235 pCursor->bits->height, 236 0, ZPixmap, (char *) pCursor->bits->argb); 237 FreeScratchGC (pGC); 238 pPriv->pPicture = CreatePicture (0, &pPixmap->drawable, 239 pFormat, 0, 0, serverClient, &error); 240 (*pScreen->DestroyPixmap) (pPixmap); 241 if (!pPriv->pPicture) 242 { 243 free((pointer) pPriv); 244 return NULL; 245 } 246 dixSetPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey(pScreen), pPriv); 247 return pPriv; 248 } 249 pPriv->pPicture = 0; 250#endif 251 pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); 252 if (!pPriv->sourceBits) 253 { 254 free((pointer) pPriv); 255 return NULL; 256 } 257 pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); 258 if (!pPriv->maskBits) 259 { 260 (*pScreen->DestroyPixmap) (pPriv->sourceBits); 261 free((pointer) pPriv); 262 return NULL; 263 } 264 dixSetPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey(pScreen), pPriv); 265 266 /* create the two sets of bits, clipping as appropriate */ 267 268 pGC = GetScratchGC (1, pScreen); 269 if (!pGC) 270 { 271 (void) miDCUnrealizeCursor (pScreen, pCursor); 272 return NULL; 273 } 274 275 ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); 276 (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, 277 0, 0, pCursor->bits->width, pCursor->bits->height, 278 0, XYPixmap, (char *)pCursor->bits->source); 279 gcvals.val = GXand; 280 ChangeGC (NullClient, pGC, GCFunction, &gcvals); 281 ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); 282 (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, 283 0, 0, pCursor->bits->width, pCursor->bits->height, 284 0, XYPixmap, (char *)pCursor->bits->mask); 285 286 /* mask bits -- pCursor->mask & ~pCursor->source */ 287 gcvals.val = GXcopy; 288 ChangeGC (NullClient, pGC, GCFunction, &gcvals); 289 ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); 290 (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, 291 0, 0, pCursor->bits->width, pCursor->bits->height, 292 0, XYPixmap, (char *)pCursor->bits->mask); 293 gcvals.val = GXandInverted; 294 ChangeGC (NullClient, pGC, GCFunction, &gcvals); 295 ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); 296 (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, 297 0, 0, pCursor->bits->width, pCursor->bits->height, 298 0, XYPixmap, (char *)pCursor->bits->source); 299 FreeScratchGC (pGC); 300 return pPriv; 301} 302 303Bool 304miDCUnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) 305{ 306 miDCCursorPtr pPriv; 307 308 pPriv = (miDCCursorPtr)dixLookupPrivate(&pCursor->bits->devPrivates, 309 miDCCursorBitsKey(pScreen)); 310 if (pPriv && (pCursor->bits->refcnt <= 1)) 311 { 312 if (pPriv->sourceBits) 313 (*pScreen->DestroyPixmap) (pPriv->sourceBits); 314 if (pPriv->maskBits) 315 (*pScreen->DestroyPixmap) (pPriv->maskBits); 316#ifdef ARGB_CURSOR 317 if (pPriv->pPicture) 318 FreePicture (pPriv->pPicture, 0); 319#endif 320 free((pointer) pPriv); 321 dixSetPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey(pScreen), NULL); 322 } 323 return TRUE; 324} 325 326static void 327miDCPutBits ( 328 DrawablePtr pDrawable, 329 miDCCursorPtr pPriv, 330 GCPtr sourceGC, 331 GCPtr maskGC, 332 int x_org, 333 int y_org, 334 unsigned w, 335 unsigned h, 336 unsigned long source, 337 unsigned long mask) 338{ 339 ChangeGCVal gcval; 340 int x, y; 341 342 if (sourceGC->fgPixel != source) 343 { 344 gcval.val = source; 345 ChangeGC (NullClient, sourceGC, GCForeground, &gcval); 346 } 347 if (sourceGC->serialNumber != pDrawable->serialNumber) 348 ValidateGC (pDrawable, sourceGC); 349 350 if(sourceGC->miTranslate) 351 { 352 x = pDrawable->x + x_org; 353 y = pDrawable->y + y_org; 354 } 355 else 356 { 357 x = x_org; 358 y = y_org; 359 } 360 361 (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y); 362 if (maskGC->fgPixel != mask) 363 { 364 gcval.val = mask; 365 ChangeGC (NullClient, maskGC, GCForeground, &gcval); 366 } 367 if (maskGC->serialNumber != pDrawable->serialNumber) 368 ValidateGC (pDrawable, maskGC); 369 370 if(maskGC->miTranslate) 371 { 372 x = pDrawable->x + x_org; 373 y = pDrawable->y + y_org; 374 } 375 else 376 { 377 x = x_org; 378 y = y_org; 379 } 380 381 (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y); 382} 383 384static GCPtr 385miDCMakeGC(WindowPtr pWin) 386{ 387 GCPtr pGC; 388 int status; 389 XID gcvals[2]; 390 391 gcvals[0] = IncludeInferiors; 392 gcvals[1] = FALSE; 393 pGC = CreateGC((DrawablePtr)pWin, 394 GCSubwindowMode|GCGraphicsExposures, gcvals, &status, 395 (XID)0, serverClient); 396 return pGC; 397} 398 399 400Bool 401miDCPutUpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, 402 int x, int y, unsigned long source, unsigned long mask) 403{ 404 miDCScreenPtr pScreenPriv; 405 miDCCursorPtr pPriv; 406 miDCBufferPtr pBuffer; 407 WindowPtr pWin; 408 409 pPriv = (miDCCursorPtr)dixLookupPrivate(&pCursor->bits->devPrivates, 410 miDCCursorBitsKey(pScreen)); 411 if (!pPriv) 412 { 413 pPriv = miDCRealize(pScreen, pCursor); 414 if (!pPriv) 415 return FALSE; 416 } 417 pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, 418 miDCScreenKey); 419 pWin = pScreen->root; 420 pBuffer = miGetDCDevice(pDev, pScreen); 421 422#ifdef ARGB_CURSOR 423 if (pPriv->pPicture) 424 { 425 if (!EnsurePicture(pBuffer->pRootPicture, &pWin->drawable, pWin)) 426 return FALSE; 427 CompositePicture (PictOpOver, 428 pPriv->pPicture, 429 NULL, 430 pBuffer->pRootPicture, 431 0, 0, 0, 0, 432 x, y, 433 pCursor->bits->width, 434 pCursor->bits->height); 435 } 436 else 437#endif 438 { 439 miDCPutBits ((DrawablePtr)pWin, pPriv, 440 pBuffer->pSourceGC, pBuffer->pMaskGC, 441 x, y, pCursor->bits->width, pCursor->bits->height, 442 source, mask); 443 } 444 return TRUE; 445} 446 447Bool 448miDCSaveUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, 449 int x, int y, int w, int h) 450{ 451 miDCScreenPtr pScreenPriv; 452 miDCBufferPtr pBuffer; 453 PixmapPtr pSave; 454 WindowPtr pWin; 455 GCPtr pGC; 456 457 pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, 458 miDCScreenKey); 459 pBuffer = miGetDCDevice(pDev, pScreen); 460 461 pSave = pBuffer->pSave; 462 pWin = pScreen->root; 463 if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) 464 { 465 if (pSave) 466 (*pScreen->DestroyPixmap) (pSave); 467 pBuffer->pSave = pSave = 468 (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth, 0); 469 if (!pSave) 470 return FALSE; 471 } 472 473 pGC = pBuffer->pSaveGC; 474 if (pSave->drawable.serialNumber != pGC->serialNumber) 475 ValidateGC ((DrawablePtr) pSave, pGC); 476 (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, 477 x, y, w, h, 0, 0); 478 return TRUE; 479} 480 481Bool 482miDCRestoreUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, 483 int x, int y, int w, int h) 484{ 485 miDCScreenPtr pScreenPriv; 486 miDCBufferPtr pBuffer; 487 PixmapPtr pSave; 488 WindowPtr pWin; 489 GCPtr pGC; 490 491 pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, 492 miDCScreenKey); 493 pBuffer = miGetDCDevice(pDev, pScreen); 494 pSave = pBuffer->pSave; 495 496 pWin = pScreen->root; 497 if (!pSave) 498 return FALSE; 499 500 pGC = pBuffer->pRestoreGC; 501 if (pWin->drawable.serialNumber != pGC->serialNumber) 502 ValidateGC ((DrawablePtr) pWin, pGC); 503 (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, 504 0, 0, w, h, x, y); 505 return TRUE; 506} 507 508Bool 509miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) 510{ 511 miDCBufferPtr pBuffer; 512 WindowPtr pWin; 513 int i; 514 515 if (!DevHasCursor(pDev)) 516 return TRUE; 517 518 for (i = 0; i < screenInfo.numScreens; i++) 519 { 520 pScreen = screenInfo.screens[i]; 521 522 pBuffer = calloc(1, sizeof(miDCBufferRec)); 523 if (!pBuffer) 524 goto failure; 525 526 dixSetPrivate(&pDev->devPrivates, miDCDeviceKey(pScreen), pBuffer); 527 pWin = pScreen->root; 528 529 pBuffer->pSourceGC = miDCMakeGC(pWin); 530 if (!pBuffer->pSourceGC) 531 goto failure; 532 533 pBuffer->pMaskGC = miDCMakeGC(pWin); 534 if (!pBuffer->pMaskGC) 535 goto failure; 536 537 pBuffer->pSaveGC = miDCMakeGC(pWin); 538 if (!pBuffer->pSaveGC) 539 goto failure; 540 541 pBuffer->pRestoreGC = miDCMakeGC(pWin); 542 if (!pBuffer->pRestoreGC) 543 goto failure; 544 545#ifdef ARGB_CURSOR 546 pBuffer->pRootPicture = NULL; 547#endif 548 549 /* (re)allocated lazily depending on the cursor size */ 550 pBuffer->pSave = NULL; 551 } 552 553 return TRUE; 554 555failure: 556 557 miDCDeviceCleanup(pDev, pScreen); 558 559 return FALSE; 560} 561 562void 563miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) 564{ 565 miDCBufferPtr pBuffer; 566 int i; 567 568 if (DevHasCursor(pDev)) 569 { 570 for (i = 0; i < screenInfo.numScreens; i++) 571 { 572 pScreen = screenInfo.screens[i]; 573 574 pBuffer = miGetDCDevice(pDev, pScreen); 575 576 if (pBuffer) 577 { 578 if (pBuffer->pSourceGC) FreeGC(pBuffer->pSourceGC, (GContext) 0); 579 if (pBuffer->pMaskGC) FreeGC(pBuffer->pMaskGC, (GContext) 0); 580 if (pBuffer->pSaveGC) FreeGC(pBuffer->pSaveGC, (GContext) 0); 581 if (pBuffer->pRestoreGC) FreeGC(pBuffer->pRestoreGC, (GContext) 0); 582 583#ifdef ARGB_CURSOR 584 /* If a pRootPicture was allocated for a root window, it 585 * is freed when that root window is destroyed, so don't 586 * free it again here. */ 587#endif 588 589 if (pBuffer->pSave) (*pScreen->DestroyPixmap)(pBuffer->pSave); 590 591 free(pBuffer); 592 dixSetPrivate(&pDev->devPrivates, miDCDeviceKey(pScreen), NULL); 593 } 594 } 595 } 596} 597