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