compalloc.c revision 05b261ec
1/* 2 * Copyright © 2006 Sun Microsystems 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Sun Microsystems not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Sun Microsystems makes no 11 * representations about the suitability of this software for any purpose. It 12 * is provided "as is" without express or implied warranty. 13 * 14 * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Copyright © 2003 Keith Packard 23 * 24 * Permission to use, copy, modify, distribute, and sell this software and its 25 * documentation for any purpose is hereby granted without fee, provided that 26 * the above copyright notice appear in all copies and that both that 27 * copyright notice and this permission notice appear in supporting 28 * documentation, and that the name of Keith Packard not be used in 29 * advertising or publicity pertaining to distribution of the software without 30 * specific, written prior permission. Keith Packard makes no 31 * representations about the suitability of this software for any purpose. It 32 * is provided "as is" without express or implied warranty. 33 * 34 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 35 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 36 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 37 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 38 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 39 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 40 * PERFORMANCE OF THIS SOFTWARE. 41 */ 42 43#ifdef HAVE_DIX_CONFIG_H 44#include <dix-config.h> 45#endif 46 47#include "compint.h" 48 49static void 50compReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) 51{ 52 WindowPtr pWin = (WindowPtr) closure; 53 ScreenPtr pScreen = pWin->drawable.pScreen; 54 CompScreenPtr cs = GetCompScreen (pScreen); 55 CompWindowPtr cw = GetCompWindow (pWin); 56 57 cs->damaged = TRUE; 58 cw->damaged = TRUE; 59} 60 61static void 62compDestroyDamage (DamagePtr pDamage, void *closure) 63{ 64 WindowPtr pWin = (WindowPtr) closure; 65 CompWindowPtr cw = GetCompWindow (pWin); 66 67 cw->damage = 0; 68} 69 70/* 71 * Redirect one window for one client 72 */ 73int 74compRedirectWindow (ClientPtr pClient, WindowPtr pWin, int update) 75{ 76 CompWindowPtr cw = GetCompWindow (pWin); 77 CompClientWindowPtr ccw; 78 Bool wasMapped = pWin->mapped; 79 CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen); 80 81 if (pWin == cs->pOverlayWin) { 82 return Success; 83 } 84 85 /* 86 * Only one Manual update is allowed 87 */ 88 if (cw && update == CompositeRedirectManual) 89 for (ccw = cw->clients; ccw; ccw = ccw->next) 90 if (ccw->update == CompositeRedirectManual) 91 return BadAccess; 92 93 /* 94 * Allocate per-client per-window structure 95 * The client *could* allocate multiple, but while supported, 96 * it is not expected to be common 97 */ 98 ccw = xalloc (sizeof (CompClientWindowRec)); 99 if (!ccw) 100 return BadAlloc; 101 ccw->id = FakeClientID (pClient->index); 102 ccw->update = update; 103 /* 104 * Now make sure there's a per-window structure to hang this from 105 */ 106 if (!cw) 107 { 108 cw = xalloc (sizeof (CompWindowRec)); 109 if (!cw) 110 { 111 xfree (ccw); 112 return BadAlloc; 113 } 114 cw->damage = DamageCreate (compReportDamage, 115 compDestroyDamage, 116 DamageReportNonEmpty, 117 FALSE, 118 pWin->drawable.pScreen, 119 pWin); 120 if (!cw->damage) 121 { 122 xfree (ccw); 123 xfree (cw); 124 return BadAlloc; 125 } 126 if (wasMapped) 127 { 128 DisableMapUnmapEvents (pWin); 129 UnmapWindow (pWin, FALSE); 130 EnableMapUnmapEvents (pWin); 131 } 132 133 REGION_NULL (pScreen, &cw->borderClip); 134 cw->update = CompositeRedirectAutomatic; 135 cw->clients = 0; 136 cw->oldx = COMP_ORIGIN_INVALID; 137 cw->oldy = COMP_ORIGIN_INVALID; 138 cw->damageRegistered = FALSE; 139 cw->damaged = FALSE; 140 pWin->devPrivates[CompWindowPrivateIndex].ptr = cw; 141 } 142 ccw->next = cw->clients; 143 cw->clients = ccw; 144 if (!AddResource (ccw->id, CompositeClientWindowType, pWin)) 145 return BadAlloc; 146 if (ccw->update == CompositeRedirectManual) 147 { 148 if (cw->damageRegistered) 149 { 150 DamageUnregister (&pWin->drawable, cw->damage); 151 cw->damageRegistered = FALSE; 152 } 153 cw->update = CompositeRedirectManual; 154 } 155 156 if (!compCheckRedirect (pWin)) 157 { 158 FreeResource (ccw->id, RT_NONE); 159 return BadAlloc; 160 } 161 if (wasMapped && !pWin->mapped) 162 { 163 Bool overrideRedirect = pWin->overrideRedirect; 164 pWin->overrideRedirect = TRUE; 165 DisableMapUnmapEvents (pWin); 166 MapWindow (pWin, pClient); 167 EnableMapUnmapEvents (pWin); 168 pWin->overrideRedirect = overrideRedirect; 169 } 170 171 return Success; 172} 173 174/* 175 * Free one of the per-client per-window resources, clearing 176 * redirect and the per-window pointer as appropriate 177 */ 178void 179compFreeClientWindow (WindowPtr pWin, XID id) 180{ 181 CompWindowPtr cw = GetCompWindow (pWin); 182 CompClientWindowPtr ccw, *prev; 183 Bool wasMapped = pWin->mapped; 184 185 if (!cw) 186 return; 187 for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next) 188 { 189 if (ccw->id == id) 190 { 191 *prev = ccw->next; 192 if (ccw->update == CompositeRedirectManual) 193 cw->update = CompositeRedirectAutomatic; 194 xfree (ccw); 195 break; 196 } 197 } 198 if (!cw->clients) 199 { 200 if (wasMapped) 201 { 202 DisableMapUnmapEvents (pWin); 203 UnmapWindow (pWin, FALSE); 204 EnableMapUnmapEvents (pWin); 205 } 206 207 if (pWin->redirectDraw != RedirectDrawNone) 208 compFreePixmap (pWin); 209 210 if (cw->damage) 211 DamageDestroy (cw->damage); 212 213 REGION_UNINIT (pScreen, &cw->borderClip); 214 215 pWin->devPrivates[CompWindowPrivateIndex].ptr = 0; 216 xfree (cw); 217 } 218 else if (cw->update == CompositeRedirectAutomatic && 219 !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone) 220 { 221 DamageRegister (&pWin->drawable, cw->damage); 222 cw->damageRegistered = TRUE; 223 pWin->redirectDraw = RedirectDrawAutomatic; 224 DamageDamageRegion (&pWin->drawable, &pWin->borderSize); 225 } 226 if (wasMapped && !pWin->mapped) 227 { 228 Bool overrideRedirect = pWin->overrideRedirect; 229 pWin->overrideRedirect = TRUE; 230 DisableMapUnmapEvents (pWin); 231 MapWindow (pWin, clients[CLIENT_ID(id)]); 232 EnableMapUnmapEvents (pWin); 233 pWin->overrideRedirect = overrideRedirect; 234 } 235} 236 237/* 238 * This is easy, just free the appropriate resource. 239 */ 240 241int 242compUnredirectWindow (ClientPtr pClient, WindowPtr pWin, int update) 243{ 244 CompWindowPtr cw = GetCompWindow (pWin); 245 CompClientWindowPtr ccw; 246 247 if (!cw) 248 return BadValue; 249 250 for (ccw = cw->clients; ccw; ccw = ccw->next) 251 if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) 252 { 253 FreeResource (ccw->id, RT_NONE); 254 return Success; 255 } 256 return BadValue; 257} 258 259/* 260 * Redirect all subwindows for one client 261 */ 262 263int 264compRedirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update) 265{ 266 CompSubwindowsPtr csw = GetCompSubwindows (pWin); 267 CompClientWindowPtr ccw; 268 WindowPtr pChild; 269 270 /* 271 * Only one Manual update is allowed 272 */ 273 if (csw && update == CompositeRedirectManual) 274 for (ccw = csw->clients; ccw; ccw = ccw->next) 275 if (ccw->update == CompositeRedirectManual) 276 return BadAccess; 277 /* 278 * Allocate per-client per-window structure 279 * The client *could* allocate multiple, but while supported, 280 * it is not expected to be common 281 */ 282 ccw = xalloc (sizeof (CompClientWindowRec)); 283 if (!ccw) 284 return BadAlloc; 285 ccw->id = FakeClientID (pClient->index); 286 ccw->update = update; 287 /* 288 * Now make sure there's a per-window structure to hang this from 289 */ 290 if (!csw) 291 { 292 csw = xalloc (sizeof (CompSubwindowsRec)); 293 if (!csw) 294 { 295 xfree (ccw); 296 return BadAlloc; 297 } 298 csw->update = CompositeRedirectAutomatic; 299 csw->clients = 0; 300 pWin->devPrivates[CompSubwindowsPrivateIndex].ptr = csw; 301 } 302 /* 303 * Redirect all existing windows 304 */ 305 for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) 306 { 307 int ret = compRedirectWindow (pClient, pChild, update); 308 if (ret != Success) 309 { 310 for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib) 311 (void) compUnredirectWindow (pClient, pChild, update); 312 if (!csw->clients) 313 { 314 xfree (csw); 315 pWin->devPrivates[CompSubwindowsPrivateIndex].ptr = 0; 316 } 317 xfree (ccw); 318 return ret; 319 } 320 } 321 /* 322 * Hook into subwindows list 323 */ 324 ccw->next = csw->clients; 325 csw->clients = ccw; 326 if (!AddResource (ccw->id, CompositeClientSubwindowsType, pWin)) 327 return BadAlloc; 328 if (ccw->update == CompositeRedirectManual) 329 { 330 csw->update = CompositeRedirectManual; 331 /* 332 * tell damage extension that damage events for this client are 333 * critical output 334 */ 335 DamageExtSetCritical (pClient, TRUE); 336 } 337 return Success; 338} 339 340/* 341 * Free one of the per-client per-subwindows resources, 342 * which frees one redirect per subwindow 343 */ 344void 345compFreeClientSubwindows (WindowPtr pWin, XID id) 346{ 347 CompSubwindowsPtr csw = GetCompSubwindows (pWin); 348 CompClientWindowPtr ccw, *prev; 349 WindowPtr pChild; 350 351 if (!csw) 352 return; 353 for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next) 354 { 355 if (ccw->id == id) 356 { 357 ClientPtr pClient = clients[CLIENT_ID(id)]; 358 359 *prev = ccw->next; 360 if (ccw->update == CompositeRedirectManual) 361 { 362 /* 363 * tell damage extension that damage events for this client are 364 * critical output 365 */ 366 DamageExtSetCritical (pClient, FALSE); 367 csw->update = CompositeRedirectAutomatic; 368 if (pWin->mapped) 369 (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, TRUE); 370 } 371 372 /* 373 * Unredirect all existing subwindows 374 */ 375 for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) 376 (void) compUnredirectWindow (pClient, pChild, ccw->update); 377 378 xfree (ccw); 379 break; 380 } 381 } 382 383 /* 384 * Check if all of the per-client records are gone 385 */ 386 if (!csw->clients) 387 { 388 pWin->devPrivates[CompSubwindowsPrivateIndex].ptr = 0; 389 xfree (csw); 390 } 391} 392 393/* 394 * This is easy, just free the appropriate resource. 395 */ 396 397int 398compUnredirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update) 399{ 400 CompSubwindowsPtr csw = GetCompSubwindows (pWin); 401 CompClientWindowPtr ccw; 402 403 if (!csw) 404 return BadValue; 405 for (ccw = csw->clients; ccw; ccw = ccw->next) 406 if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) 407 { 408 FreeResource (ccw->id, RT_NONE); 409 return Success; 410 } 411 return BadValue; 412} 413 414/* 415 * Add redirection information for one subwindow (during reparent) 416 */ 417 418int 419compRedirectOneSubwindow (WindowPtr pParent, WindowPtr pWin) 420{ 421 CompSubwindowsPtr csw = GetCompSubwindows (pParent); 422 CompClientWindowPtr ccw; 423 424 if (!csw) 425 return Success; 426 for (ccw = csw->clients; ccw; ccw = ccw->next) 427 { 428 int ret = compRedirectWindow (clients[CLIENT_ID(ccw->id)], 429 pWin, ccw->update); 430 if (ret != Success) 431 return ret; 432 } 433 return Success; 434} 435 436/* 437 * Remove redirection information for one subwindow (during reparent) 438 */ 439 440int 441compUnredirectOneSubwindow (WindowPtr pParent, WindowPtr pWin) 442{ 443 CompSubwindowsPtr csw = GetCompSubwindows (pParent); 444 CompClientWindowPtr ccw; 445 446 if (!csw) 447 return Success; 448 for (ccw = csw->clients; ccw; ccw = ccw->next) 449 { 450 int ret = compUnredirectWindow (clients[CLIENT_ID(ccw->id)], 451 pWin, ccw->update); 452 if (ret != Success) 453 return ret; 454 } 455 return Success; 456} 457 458static PixmapPtr 459compNewPixmap (WindowPtr pWin, int x, int y, int w, int h) 460{ 461 ScreenPtr pScreen = pWin->drawable.pScreen; 462 WindowPtr pParent = pWin->parent; 463 PixmapPtr pPixmap; 464 465 pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth); 466 467 if (!pPixmap) 468 return 0; 469 470 pPixmap->screen_x = x; 471 pPixmap->screen_y = y; 472 473 if (pParent->drawable.depth == pWin->drawable.depth) 474 { 475 GCPtr pGC = GetScratchGC (pWin->drawable.depth, pScreen); 476 477 /* 478 * Copy bits from the parent into the new pixmap so that it will 479 * have "reasonable" contents in case for background None areas. 480 */ 481 if (pGC) 482 { 483 XID val = IncludeInferiors; 484 485 ValidateGC(&pPixmap->drawable, pGC); 486 dixChangeGC (serverClient, pGC, GCSubwindowMode, &val, NULL); 487 (*pGC->ops->CopyArea) (&pParent->drawable, 488 &pPixmap->drawable, 489 pGC, 490 x - pParent->drawable.x, 491 y - pParent->drawable.y, 492 w, h, 0, 0); 493 FreeScratchGC (pGC); 494 } 495 } 496 else 497 { 498 PictFormatPtr pSrcFormat = compWindowFormat (pParent); 499 PictFormatPtr pDstFormat = compWindowFormat (pWin); 500 XID inferiors = IncludeInferiors; 501 int error; 502 503 PicturePtr pSrcPicture = CreatePicture (None, 504 &pParent->drawable, 505 pSrcFormat, 506 CPSubwindowMode, 507 &inferiors, 508 serverClient, &error); 509 510 PicturePtr pDstPicture = CreatePicture (None, 511 &pPixmap->drawable, 512 pDstFormat, 513 0, 0, 514 serverClient, &error); 515 516 if (pSrcPicture && pDstPicture) 517 { 518 CompositePicture (PictOpSrc, 519 pSrcPicture, 520 NULL, 521 pDstPicture, 522 x - pParent->drawable.x, 523 y - pParent->drawable.y, 524 0, 0, 0, 0, w, h); 525 } 526 if (pSrcPicture) 527 FreePicture (pSrcPicture, 0); 528 if (pDstPicture) 529 FreePicture (pDstPicture, 0); 530 } 531 return pPixmap; 532} 533 534Bool 535compAllocPixmap (WindowPtr pWin) 536{ 537 int bw = (int) pWin->borderWidth; 538 int x = pWin->drawable.x - bw; 539 int y = pWin->drawable.y - bw; 540 int w = pWin->drawable.width + (bw << 1); 541 int h = pWin->drawable.height + (bw << 1); 542 PixmapPtr pPixmap = compNewPixmap (pWin, x, y, w, h); 543 CompWindowPtr cw = GetCompWindow (pWin); 544 545 if (!pPixmap) 546 return FALSE; 547 if (cw->update == CompositeRedirectAutomatic) 548 pWin->redirectDraw = RedirectDrawAutomatic; 549 else 550 pWin->redirectDraw = RedirectDrawManual; 551 552 compSetPixmap (pWin, pPixmap); 553 cw->oldx = COMP_ORIGIN_INVALID; 554 cw->oldy = COMP_ORIGIN_INVALID; 555 cw->damageRegistered = FALSE; 556 if (cw->update == CompositeRedirectAutomatic) 557 { 558 DamageRegister (&pWin->drawable, cw->damage); 559 cw->damageRegistered = TRUE; 560 } 561 return TRUE; 562} 563 564void 565compFreePixmap (WindowPtr pWin) 566{ 567 ScreenPtr pScreen = pWin->drawable.pScreen; 568 PixmapPtr pRedirectPixmap, pParentPixmap; 569 CompWindowPtr cw = GetCompWindow (pWin); 570 571 if (cw->damageRegistered) 572 { 573 DamageUnregister (&pWin->drawable, cw->damage); 574 cw->damageRegistered = FALSE; 575 DamageEmpty (cw->damage); 576 } 577 /* 578 * Move the parent-constrained border clip region back into 579 * the window so that ValidateTree will handle the unmap 580 * case correctly. Unmap adds the window borderClip to the 581 * parent exposed area; regions beyond the parent cause crashes 582 */ 583 REGION_COPY (pScreen, &pWin->borderClip, &cw->borderClip); 584 pRedirectPixmap = (*pScreen->GetWindowPixmap) (pWin); 585 pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent); 586 pWin->redirectDraw = RedirectDrawNone; 587 compSetPixmap (pWin, pParentPixmap); 588 (*pScreen->DestroyPixmap) (pRedirectPixmap); 589} 590 591/* 592 * Make sure the pixmap is the right size and offset. Allocate a new 593 * pixmap to change size, adjust origin to change offset, leaving the 594 * old pixmap in cw->pOldPixmap so bits can be recovered 595 */ 596Bool 597compReallocPixmap (WindowPtr pWin, int draw_x, int draw_y, 598 unsigned int w, unsigned int h, int bw) 599{ 600 ScreenPtr pScreen = pWin->drawable.pScreen; 601 PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin); 602 PixmapPtr pNew; 603 CompWindowPtr cw = GetCompWindow (pWin); 604 int pix_x, pix_y; 605 int pix_w, pix_h; 606 607 assert (cw && pWin->redirectDraw != RedirectDrawNone); 608 cw->oldx = pOld->screen_x; 609 cw->oldy = pOld->screen_y; 610 pix_x = draw_x - bw; 611 pix_y = draw_y - bw; 612 pix_w = w + (bw << 1); 613 pix_h = h + (bw << 1); 614 if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height) 615 { 616 pNew = compNewPixmap (pWin, pix_x, pix_y, pix_w, pix_h); 617 if (!pNew) 618 return FALSE; 619 cw->pOldPixmap = pOld; 620 compSetPixmap (pWin, pNew); 621 } 622 else 623 { 624 pNew = pOld; 625 cw->pOldPixmap = 0; 626 } 627 pNew->screen_x = pix_x; 628 pNew->screen_y = pix_y; 629 return TRUE; 630} 631