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