midispcur.c revision 35c4bbdf
1/* 2 * midispcur.c 3 * 4 * machine independent cursor display 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 "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 */ 54static DevPrivateKeyRec miDCScreenKeyRec; 55 56#define miDCScreenKey (&miDCScreenKeyRec) 57 58static DevScreenPrivateKeyRec miDCDeviceKeyRec; 59 60#define miDCDeviceKey (&miDCDeviceKeyRec) 61 62static Bool miDCCloseScreen(ScreenPtr pScreen); 63 64/* per device private data */ 65typedef 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 */ 81typedef 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 91Bool 92miDCInitialize(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 117static void 118miDCSwitchScreenCursor(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 137static Bool 138miDCCloseScreen(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 151Bool 152miDCRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) 153{ 154 return TRUE; 155} 156 157#define EnsurePicture(picture,draw,win) (picture || miDCMakePicture(&picture,draw,win)) 158 159static PicturePtr 160miDCMakePicture(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 177static Bool 178miDCRealize(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 276Bool 277miDCUnrealizeCursor(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 286static void 287miDCPutBits(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 335static GCPtr 336miDCMakeGC(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 350Bool 351miDCPutUpCursor(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 384Bool 385miDCSaveUnderCursor(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 414Bool 415miDCRestoreUnderCursor(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 438Bool 439miDCDeviceInitialize(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 490void 491miDCDeviceCleanup(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} 526