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) 59static DevScreenPrivateKeyRec miDCCursorBitsKeyRec; 60#define miDCCursorBitsKey (&miDCCursorBitsKeyRec) 61static DevScreenPrivateKeyRec miDCDeviceKeyRec; 62#define miDCDeviceKey (&miDCDeviceKeyRec) 63 64static Bool miDCCloseScreen(int index, ScreenPtr pScreen); 65 66/* per device private data */ 67typedef struct { 68 GCPtr pSourceGC, pMaskGC; 69 GCPtr pSaveGC, pRestoreGC; 70 PixmapPtr pSave; 71#ifdef ARGB_CURSOR 72 PicturePtr pRootPicture; 73#endif 74} miDCBufferRec, *miDCBufferPtr; 75 76#define miGetDCDevice(dev, screen) \ 77 ((DevHasCursor(dev)) ? \ 78 (miDCBufferPtr)dixLookupScreenPrivate(&dev->devPrivates, miDCDeviceKey, screen) : \ 79 (miDCBufferPtr)dixLookupScreenPrivate(&dev->u.master->devPrivates, miDCDeviceKey, screen)) 80 81/* 82 * The core pointer buffer will point to the index of the virtual core pointer 83 * in the pCursorBuffers array. 84 */ 85typedef struct { 86 CloseScreenProcPtr CloseScreen; 87} miDCScreenRec, *miDCScreenPtr; 88 89#define miGetDCScreen(s) ((miDCScreenPtr)(dixLookupPrivate(&(s)->devPrivates, miDCScreenKey))) 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 !dixRegisterScreenPrivateKey(&miDCCursorBitsKeyRec, pScreen, PRIVATE_CURSOR_BITS, 0) || 107 !dixRegisterScreenPrivateKey(&miDCDeviceKeyRec, pScreen, PRIVATE_DEVICE, 0)) 108 return FALSE; 109 110 pScreenPriv = malloc(sizeof (miDCScreenRec)); 111 if (!pScreenPriv) 112 return FALSE; 113 114 pScreenPriv->CloseScreen = pScreen->CloseScreen; 115 pScreen->CloseScreen = miDCCloseScreen; 116 117 dixSetPrivate(&pScreen->devPrivates, miDCScreenKey, pScreenPriv); 118 119 if (!miSpriteInitialize (pScreen, screenFuncs)) 120 { 121 free((pointer) pScreenPriv); 122 return FALSE; 123 } 124 return TRUE; 125} 126 127static Bool 128miDCCloseScreen (int index, ScreenPtr pScreen) 129{ 130 miDCScreenPtr pScreenPriv; 131 132 pScreenPriv = (miDCScreenPtr)dixLookupPrivate(&pScreen->devPrivates, 133 miDCScreenKey); 134 pScreen->CloseScreen = pScreenPriv->CloseScreen; 135 free((pointer) pScreenPriv); 136 return (*pScreen->CloseScreen) (index, pScreen); 137} 138 139Bool 140miDCRealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) 141{ 142 if (pCursor->bits->refcnt <= 1) 143 dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, NULL); 144 return TRUE; 145} 146 147#ifdef ARGB_CURSOR 148#define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win)) 149 150static VisualPtr 151miDCGetWindowVisual (WindowPtr pWin) 152{ 153 ScreenPtr pScreen = pWin->drawable.pScreen; 154 VisualID vid = wVisual (pWin); 155 int i; 156 157 for (i = 0; i < pScreen->numVisuals; i++) 158 if (pScreen->visuals[i].vid == vid) 159 return &pScreen->visuals[i]; 160 return 0; 161} 162 163static PicturePtr 164miDCMakePicture (PicturePtr *ppPicture, DrawablePtr pDraw, WindowPtr pWin) 165{ 166 ScreenPtr pScreen = pDraw->pScreen; 167 VisualPtr pVisual; 168 PictFormatPtr pFormat; 169 XID subwindow_mode = IncludeInferiors; 170 PicturePtr pPicture; 171 int error; 172 173 pVisual = miDCGetWindowVisual (pWin); 174 if (!pVisual) 175 return 0; 176 pFormat = PictureMatchVisual (pScreen, pDraw->depth, pVisual); 177 if (!pFormat) 178 return 0; 179 pPicture = CreatePicture (0, pDraw, pFormat, 180 CPSubwindowMode, &subwindow_mode, 181 serverClient, &error); 182 *ppPicture = pPicture; 183 return pPicture; 184} 185#endif 186 187static miDCCursorPtr 188miDCRealize (ScreenPtr pScreen, CursorPtr pCursor) 189{ 190 miDCCursorPtr pPriv; 191 GCPtr pGC; 192 ChangeGCVal gcvals; 193 194 pPriv = malloc(sizeof (miDCCursorRec)); 195 if (!pPriv) 196 return NULL; 197#ifdef ARGB_CURSOR 198 if (pCursor->bits->argb) 199 { 200 PixmapPtr pPixmap; 201 PictFormatPtr pFormat; 202 int error; 203 204 pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); 205 if (!pFormat) 206 { 207 free((pointer) pPriv); 208 return NULL; 209 } 210 211 pPriv->sourceBits = 0; 212 pPriv->maskBits = 0; 213 pPixmap = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, 214 pCursor->bits->height, 32, 215 CREATE_PIXMAP_USAGE_SCRATCH); 216 if (!pPixmap) 217 { 218 free((pointer) pPriv); 219 return NULL; 220 } 221 pGC = GetScratchGC (32, pScreen); 222 if (!pGC) 223 { 224 (*pScreen->DestroyPixmap) (pPixmap); 225 free((pointer) pPriv); 226 return NULL; 227 } 228 ValidateGC (&pPixmap->drawable, pGC); 229 (*pGC->ops->PutImage) (&pPixmap->drawable, pGC, 32, 230 0, 0, pCursor->bits->width, 231 pCursor->bits->height, 232 0, ZPixmap, (char *) pCursor->bits->argb); 233 FreeScratchGC (pGC); 234 pPriv->pPicture = CreatePicture (0, &pPixmap->drawable, 235 pFormat, 0, 0, serverClient, &error); 236 (*pScreen->DestroyPixmap) (pPixmap); 237 if (!pPriv->pPicture) 238 { 239 free((pointer) pPriv); 240 return NULL; 241 } 242 dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, pPriv); 243 return pPriv; 244 } 245 pPriv->pPicture = 0; 246#endif 247 pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); 248 if (!pPriv->sourceBits) 249 { 250 free((pointer) pPriv); 251 return NULL; 252 } 253 pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1, 0); 254 if (!pPriv->maskBits) 255 { 256 (*pScreen->DestroyPixmap) (pPriv->sourceBits); 257 free((pointer) pPriv); 258 return NULL; 259 } 260 dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, pPriv); 261 262 /* create the two sets of bits, clipping as appropriate */ 263 264 pGC = GetScratchGC (1, pScreen); 265 if (!pGC) 266 { 267 (void) miDCUnrealizeCursor (pScreen, pCursor); 268 return NULL; 269 } 270 271 ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); 272 (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, 273 0, 0, pCursor->bits->width, pCursor->bits->height, 274 0, XYPixmap, (char *)pCursor->bits->source); 275 gcvals.val = GXand; 276 ChangeGC (NullClient, pGC, GCFunction, &gcvals); 277 ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); 278 (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, 279 0, 0, pCursor->bits->width, pCursor->bits->height, 280 0, XYPixmap, (char *)pCursor->bits->mask); 281 282 /* mask bits -- pCursor->mask & ~pCursor->source */ 283 gcvals.val = GXcopy; 284 ChangeGC (NullClient, pGC, GCFunction, &gcvals); 285 ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); 286 (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, 287 0, 0, pCursor->bits->width, pCursor->bits->height, 288 0, XYPixmap, (char *)pCursor->bits->mask); 289 gcvals.val = GXandInverted; 290 ChangeGC (NullClient, pGC, GCFunction, &gcvals); 291 ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); 292 (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, 293 0, 0, pCursor->bits->width, pCursor->bits->height, 294 0, XYPixmap, (char *)pCursor->bits->source); 295 FreeScratchGC (pGC); 296 return pPriv; 297} 298 299Bool 300miDCUnrealizeCursor (ScreenPtr pScreen, CursorPtr pCursor) 301{ 302 miDCCursorPtr pPriv; 303 304 pPriv = (miDCCursorPtr)dixLookupScreenPrivate(&pCursor->bits->devPrivates, 305 miDCCursorBitsKey, pScreen); 306 if (pPriv && (pCursor->bits->refcnt <= 1)) 307 { 308 if (pPriv->sourceBits) 309 (*pScreen->DestroyPixmap) (pPriv->sourceBits); 310 if (pPriv->maskBits) 311 (*pScreen->DestroyPixmap) (pPriv->maskBits); 312#ifdef ARGB_CURSOR 313 if (pPriv->pPicture) 314 FreePicture (pPriv->pPicture, 0); 315#endif 316 free((pointer) pPriv); 317 dixSetScreenPrivate(&pCursor->bits->devPrivates, miDCCursorBitsKey, pScreen, NULL); 318 } 319 return TRUE; 320} 321 322static void 323miDCPutBits ( 324 DrawablePtr pDrawable, 325 miDCCursorPtr pPriv, 326 GCPtr sourceGC, 327 GCPtr maskGC, 328 int x_org, 329 int y_org, 330 unsigned w, 331 unsigned h, 332 unsigned long source, 333 unsigned long mask) 334{ 335 ChangeGCVal gcval; 336 int x, y; 337 338 if (sourceGC->fgPixel != source) 339 { 340 gcval.val = source; 341 ChangeGC (NullClient, sourceGC, GCForeground, &gcval); 342 } 343 if (sourceGC->serialNumber != pDrawable->serialNumber) 344 ValidateGC (pDrawable, sourceGC); 345 346 if(sourceGC->miTranslate) 347 { 348 x = pDrawable->x + x_org; 349 y = pDrawable->y + y_org; 350 } 351 else 352 { 353 x = x_org; 354 y = y_org; 355 } 356 357 (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y); 358 if (maskGC->fgPixel != mask) 359 { 360 gcval.val = mask; 361 ChangeGC (NullClient, maskGC, GCForeground, &gcval); 362 } 363 if (maskGC->serialNumber != pDrawable->serialNumber) 364 ValidateGC (pDrawable, maskGC); 365 366 if(maskGC->miTranslate) 367 { 368 x = pDrawable->x + x_org; 369 y = pDrawable->y + y_org; 370 } 371 else 372 { 373 x = x_org; 374 y = y_org; 375 } 376 377 (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y); 378} 379 380static GCPtr 381miDCMakeGC(WindowPtr pWin) 382{ 383 GCPtr pGC; 384 int status; 385 XID gcvals[2]; 386 387 gcvals[0] = IncludeInferiors; 388 gcvals[1] = FALSE; 389 pGC = CreateGC((DrawablePtr)pWin, 390 GCSubwindowMode|GCGraphicsExposures, gcvals, &status, 391 (XID)0, serverClient); 392 return pGC; 393} 394 395 396Bool 397miDCPutUpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, 398 int x, int y, unsigned long source, unsigned long mask) 399{ 400 miDCCursorPtr pPriv; 401 miDCBufferPtr pBuffer; 402 WindowPtr pWin; 403 404 pPriv = (miDCCursorPtr)dixLookupScreenPrivate(&pCursor->bits->devPrivates, 405 miDCCursorBitsKey, pScreen); 406 if (!pPriv) 407 { 408 pPriv = miDCRealize(pScreen, pCursor); 409 if (!pPriv) 410 return FALSE; 411 } 412 413 pWin = pScreen->root; 414 pBuffer = miGetDCDevice(pDev, pScreen); 415 416#ifdef ARGB_CURSOR 417 if (pPriv->pPicture) 418 { 419 if (!EnsurePicture(pBuffer->pRootPicture, &pWin->drawable, pWin)) 420 return FALSE; 421 CompositePicture (PictOpOver, 422 pPriv->pPicture, 423 NULL, 424 pBuffer->pRootPicture, 425 0, 0, 0, 0, 426 x, y, 427 pCursor->bits->width, 428 pCursor->bits->height); 429 } 430 else 431#endif 432 { 433 miDCPutBits ((DrawablePtr)pWin, pPriv, 434 pBuffer->pSourceGC, pBuffer->pMaskGC, 435 x, y, pCursor->bits->width, pCursor->bits->height, 436 source, mask); 437 } 438 return TRUE; 439} 440 441Bool 442miDCSaveUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, 443 int x, int y, int w, int h) 444{ 445 miDCBufferPtr pBuffer; 446 PixmapPtr pSave; 447 WindowPtr pWin; 448 GCPtr pGC; 449 450 pBuffer = miGetDCDevice(pDev, pScreen); 451 452 pSave = pBuffer->pSave; 453 pWin = pScreen->root; 454 if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) 455 { 456 if (pSave) 457 (*pScreen->DestroyPixmap) (pSave); 458 pBuffer->pSave = pSave = 459 (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth, 0); 460 if (!pSave) 461 return FALSE; 462 } 463 464 pGC = pBuffer->pSaveGC; 465 if (pSave->drawable.serialNumber != pGC->serialNumber) 466 ValidateGC ((DrawablePtr) pSave, pGC); 467 (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, 468 x, y, w, h, 0, 0); 469 return TRUE; 470} 471 472Bool 473miDCRestoreUnderCursor (DeviceIntPtr pDev, ScreenPtr pScreen, 474 int x, int y, int w, int h) 475{ 476 miDCBufferPtr pBuffer; 477 PixmapPtr pSave; 478 WindowPtr pWin; 479 GCPtr pGC; 480 481 pBuffer = miGetDCDevice(pDev, pScreen); 482 pSave = pBuffer->pSave; 483 484 pWin = pScreen->root; 485 if (!pSave) 486 return FALSE; 487 488 pGC = pBuffer->pRestoreGC; 489 if (pWin->drawable.serialNumber != pGC->serialNumber) 490 ValidateGC ((DrawablePtr) pWin, pGC); 491 (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, 492 0, 0, w, h, x, y); 493 return TRUE; 494} 495 496Bool 497miDCDeviceInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) 498{ 499 miDCBufferPtr pBuffer; 500 WindowPtr pWin; 501 int i; 502 503 if (!DevHasCursor(pDev)) 504 return TRUE; 505 506 for (i = 0; i < screenInfo.numScreens; i++) 507 { 508 pScreen = screenInfo.screens[i]; 509 510 pBuffer = calloc(1, sizeof(miDCBufferRec)); 511 if (!pBuffer) 512 goto failure; 513 514 dixSetScreenPrivate(&pDev->devPrivates, miDCDeviceKey, pScreen, pBuffer); 515 pWin = pScreen->root; 516 517 pBuffer->pSourceGC = miDCMakeGC(pWin); 518 if (!pBuffer->pSourceGC) 519 goto failure; 520 521 pBuffer->pMaskGC = miDCMakeGC(pWin); 522 if (!pBuffer->pMaskGC) 523 goto failure; 524 525 pBuffer->pSaveGC = miDCMakeGC(pWin); 526 if (!pBuffer->pSaveGC) 527 goto failure; 528 529 pBuffer->pRestoreGC = miDCMakeGC(pWin); 530 if (!pBuffer->pRestoreGC) 531 goto failure; 532 533#ifdef ARGB_CURSOR 534 pBuffer->pRootPicture = NULL; 535#endif 536 537 /* (re)allocated lazily depending on the cursor size */ 538 pBuffer->pSave = NULL; 539 } 540 541 return TRUE; 542 543failure: 544 545 miDCDeviceCleanup(pDev, pScreen); 546 547 return FALSE; 548} 549 550void 551miDCDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) 552{ 553 miDCBufferPtr pBuffer; 554 int i; 555 556 if (DevHasCursor(pDev)) 557 { 558 for (i = 0; i < screenInfo.numScreens; i++) 559 { 560 pScreen = screenInfo.screens[i]; 561 562 pBuffer = miGetDCDevice(pDev, pScreen); 563 564 if (pBuffer) 565 { 566 if (pBuffer->pSourceGC) FreeGC(pBuffer->pSourceGC, (GContext) 0); 567 if (pBuffer->pMaskGC) FreeGC(pBuffer->pMaskGC, (GContext) 0); 568 if (pBuffer->pSaveGC) FreeGC(pBuffer->pSaveGC, (GContext) 0); 569 if (pBuffer->pRestoreGC) FreeGC(pBuffer->pRestoreGC, (GContext) 0); 570 571#ifdef ARGB_CURSOR 572 /* If a pRootPicture was allocated for a root window, it 573 * is freed when that root window is destroyed, so don't 574 * free it again here. */ 575#endif 576 577 if (pBuffer->pSave) (*pScreen->DestroyPixmap)(pBuffer->pSave); 578 579 free(pBuffer); 580 dixSetScreenPrivate(&pDev->devPrivates, miDCDeviceKey, pScreen, NULL); 581 } 582 } 583 } 584} 585