| 1 | /* |
| 2 | * Copyright (c) 2006, Oracle and/or its affiliates. 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 | |
| 50 | #ifdef PANORAMIX |
| 51 | #include "panoramiXsrv.h" |
| 52 | #endif |
| 53 | |
| 54 | #ifdef COMPOSITE_DEBUG |
| 55 | static int |
| 56 | compCheckWindow(WindowPtr pWin, pointer data) |
| 57 | { |
| 58 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 59 | PixmapPtr pWinPixmap = (*pScreen->GetWindowPixmap) (pWin); |
| 60 | PixmapPtr pParentPixmap = |
| 61 | pWin->parent ? (*pScreen->GetWindowPixmap) (pWin->parent) : 0; |
| 62 | PixmapPtr pScreenPixmap = (*pScreen->GetScreenPixmap) (pScreen); |
| 63 | |
| 64 | if (!pWin->parent) { |
| 65 | assert(pWin->redirectDraw == RedirectDrawNone); |
| 66 | assert(pWinPixmap == pScreenPixmap); |
| 67 | } |
| 68 | else if (pWin->redirectDraw != RedirectDrawNone) { |
| 69 | assert(pWinPixmap != pParentPixmap); |
| 70 | assert(pWinPixmap != pScreenPixmap); |
| 71 | } |
| 72 | else { |
| 73 | assert(pWinPixmap == pParentPixmap); |
| 74 | } |
| 75 | assert(0 < pWinPixmap->refcnt && pWinPixmap->refcnt < 3); |
| 76 | assert(0 < pScreenPixmap->refcnt && pScreenPixmap->refcnt < 3); |
| 77 | if (pParentPixmap) |
| 78 | assert(0 <= pParentPixmap->refcnt && pParentPixmap->refcnt < 3); |
| 79 | return WT_WALKCHILDREN; |
| 80 | } |
| 81 | |
| 82 | void |
| 83 | compCheckTree(ScreenPtr pScreen) |
| 84 | { |
| 85 | WalkTree(pScreen, compCheckWindow, 0); |
| 86 | } |
| 87 | #endif |
| 88 | |
| 89 | typedef struct _compPixmapVisit { |
| 90 | WindowPtr pWindow; |
| 91 | PixmapPtr pPixmap; |
| 92 | } CompPixmapVisitRec, *CompPixmapVisitPtr; |
| 93 | |
| 94 | static Bool |
| 95 | compRepaintBorder(ClientPtr pClient, pointer closure) |
| 96 | { |
| 97 | WindowPtr pWindow; |
| 98 | int rc = |
| 99 | dixLookupWindow(&pWindow, (XID) (intptr_t) closure, pClient, |
| 100 | DixWriteAccess); |
| 101 | |
| 102 | if (rc == Success) { |
| 103 | RegionRec exposed; |
| 104 | |
| 105 | RegionNull(&exposed); |
| 106 | RegionSubtract(&exposed, &pWindow->borderClip, &pWindow->winSize); |
| 107 | miPaintWindow(pWindow, &exposed, PW_BORDER); |
| 108 | RegionUninit(&exposed); |
| 109 | } |
| 110 | return TRUE; |
| 111 | } |
| 112 | |
| 113 | static int |
| 114 | compSetPixmapVisitWindow(WindowPtr pWindow, pointer data) |
| 115 | { |
| 116 | CompPixmapVisitPtr pVisit = (CompPixmapVisitPtr) data; |
| 117 | ScreenPtr pScreen = pWindow->drawable.pScreen; |
| 118 | |
| 119 | if (pWindow != pVisit->pWindow && pWindow->redirectDraw != RedirectDrawNone) |
| 120 | return WT_DONTWALKCHILDREN; |
| 121 | (*pScreen->SetWindowPixmap) (pWindow, pVisit->pPixmap); |
| 122 | /* |
| 123 | * Recompute winSize and borderSize. This is duplicate effort |
| 124 | * when resizing pixmaps, but necessary when changing redirection. |
| 125 | * Might be nice to fix this. |
| 126 | */ |
| 127 | SetWinSize(pWindow); |
| 128 | SetBorderSize(pWindow); |
| 129 | if (HasBorder(pWindow)) |
| 130 | QueueWorkProc(compRepaintBorder, serverClient, |
| 131 | (pointer) (intptr_t) pWindow->drawable.id); |
| 132 | return WT_WALKCHILDREN; |
| 133 | } |
| 134 | |
| 135 | void |
| 136 | compSetPixmap(WindowPtr pWindow, PixmapPtr pPixmap) |
| 137 | { |
| 138 | CompPixmapVisitRec visitRec; |
| 139 | |
| 140 | visitRec.pWindow = pWindow; |
| 141 | visitRec.pPixmap = pPixmap; |
| 142 | TraverseTree(pWindow, compSetPixmapVisitWindow, (pointer) &visitRec); |
| 143 | compCheckTree(pWindow->drawable.pScreen); |
| 144 | } |
| 145 | |
| 146 | Bool |
| 147 | compCheckRedirect(WindowPtr pWin) |
| 148 | { |
| 149 | CompWindowPtr cw = GetCompWindow(pWin); |
| 150 | CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen); |
| 151 | Bool should; |
| 152 | |
| 153 | should = pWin->realized && (pWin->drawable.class != InputOnly) && |
| 154 | (cw != NULL) && (pWin->parent != NULL); |
| 155 | |
| 156 | /* Never redirect the overlay window */ |
| 157 | if (cs->pOverlayWin != NULL) { |
| 158 | if (pWin == cs->pOverlayWin) { |
| 159 | should = FALSE; |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | if (should != (pWin->redirectDraw != RedirectDrawNone)) { |
| 164 | if (should) |
| 165 | return compAllocPixmap(pWin); |
| 166 | else { |
| 167 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 168 | PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin); |
| 169 | |
| 170 | compSetParentPixmap(pWin); |
| 171 | compRestoreWindow(pWin, pPixmap); |
| 172 | (*pScreen->DestroyPixmap) (pPixmap); |
| 173 | } |
| 174 | } |
| 175 | else if (should) { |
| 176 | if (cw->update == CompositeRedirectAutomatic) |
| 177 | pWin->redirectDraw = RedirectDrawAutomatic; |
| 178 | else |
| 179 | pWin->redirectDraw = RedirectDrawManual; |
| 180 | } |
| 181 | return TRUE; |
| 182 | } |
| 183 | |
| 184 | static int |
| 185 | updateOverlayWindow(ScreenPtr pScreen) |
| 186 | { |
| 187 | CompScreenPtr cs; |
| 188 | WindowPtr pWin; /* overlay window */ |
| 189 | XID vlist[2]; |
| 190 | int w = pScreen->width; |
| 191 | int h = pScreen->height; |
| 192 | |
| 193 | #ifdef PANORAMIX |
| 194 | if (!noPanoramiXExtension) { |
| 195 | w = PanoramiXPixWidth; |
| 196 | h = PanoramiXPixHeight; |
| 197 | } |
| 198 | #endif |
| 199 | |
| 200 | cs = GetCompScreen(pScreen); |
| 201 | if ((pWin = cs->pOverlayWin) != NULL) { |
| 202 | if ((pWin->drawable.width == w) && (pWin->drawable.height == h)) |
| 203 | return Success; |
| 204 | |
| 205 | /* Let's resize the overlay window. */ |
| 206 | vlist[0] = w; |
| 207 | vlist[1] = h; |
| 208 | return ConfigureWindow(pWin, CWWidth | CWHeight, vlist, wClient(pWin)); |
| 209 | } |
| 210 | |
| 211 | /* Let's be on the safe side and not assume an overlay window is |
| 212 | always allocated. */ |
| 213 | return Success; |
| 214 | } |
| 215 | |
| 216 | Bool |
| 217 | compPositionWindow(WindowPtr pWin, int x, int y) |
| 218 | { |
| 219 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 220 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 221 | Bool ret = TRUE; |
| 222 | |
| 223 | pScreen->PositionWindow = cs->PositionWindow; |
| 224 | /* |
| 225 | * "Shouldn't need this as all possible places should be wrapped |
| 226 | * |
| 227 | compCheckRedirect (pWin); |
| 228 | */ |
| 229 | #ifdef COMPOSITE_DEBUG |
| 230 | if ((pWin->redirectDraw != RedirectDrawNone) != |
| 231 | (pWin->viewable && (GetCompWindow(pWin) != NULL))) |
| 232 | OsAbort(); |
| 233 | #endif |
| 234 | if (pWin->redirectDraw != RedirectDrawNone) { |
| 235 | PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin); |
| 236 | int bw = wBorderWidth(pWin); |
| 237 | int nx = pWin->drawable.x - bw; |
| 238 | int ny = pWin->drawable.y - bw; |
| 239 | |
| 240 | if (pPixmap->screen_x != nx || pPixmap->screen_y != ny) { |
| 241 | pPixmap->screen_x = nx; |
| 242 | pPixmap->screen_y = ny; |
| 243 | pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | if (!(*pScreen->PositionWindow) (pWin, x, y)) |
| 248 | ret = FALSE; |
| 249 | cs->PositionWindow = pScreen->PositionWindow; |
| 250 | pScreen->PositionWindow = compPositionWindow; |
| 251 | compCheckTree(pWin->drawable.pScreen); |
| 252 | if (updateOverlayWindow(pScreen) != Success) |
| 253 | ret = FALSE; |
| 254 | return ret; |
| 255 | } |
| 256 | |
| 257 | Bool |
| 258 | compRealizeWindow(WindowPtr pWin) |
| 259 | { |
| 260 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 261 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 262 | Bool ret = TRUE; |
| 263 | |
| 264 | pScreen->RealizeWindow = cs->RealizeWindow; |
| 265 | compCheckRedirect(pWin); |
| 266 | if (!(*pScreen->RealizeWindow) (pWin)) |
| 267 | ret = FALSE; |
| 268 | cs->RealizeWindow = pScreen->RealizeWindow; |
| 269 | pScreen->RealizeWindow = compRealizeWindow; |
| 270 | compCheckTree(pWin->drawable.pScreen); |
| 271 | return ret; |
| 272 | } |
| 273 | |
| 274 | Bool |
| 275 | compUnrealizeWindow(WindowPtr pWin) |
| 276 | { |
| 277 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 278 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 279 | Bool ret = TRUE; |
| 280 | |
| 281 | pScreen->UnrealizeWindow = cs->UnrealizeWindow; |
| 282 | compCheckRedirect(pWin); |
| 283 | if (!(*pScreen->UnrealizeWindow) (pWin)) |
| 284 | ret = FALSE; |
| 285 | cs->UnrealizeWindow = pScreen->UnrealizeWindow; |
| 286 | pScreen->UnrealizeWindow = compUnrealizeWindow; |
| 287 | compCheckTree(pWin->drawable.pScreen); |
| 288 | return ret; |
| 289 | } |
| 290 | |
| 291 | /* |
| 292 | * Called after the borderClip for the window has settled down |
| 293 | * We use this to make sure our extra borderClip has the right origin |
| 294 | */ |
| 295 | |
| 296 | void |
| 297 | compClipNotify(WindowPtr pWin, int dx, int dy) |
| 298 | { |
| 299 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 300 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 301 | CompWindowPtr cw = GetCompWindow(pWin); |
| 302 | |
| 303 | if (cw) { |
| 304 | if (cw->borderClipX != pWin->drawable.x || |
| 305 | cw->borderClipY != pWin->drawable.y) { |
| 306 | RegionTranslate(&cw->borderClip, |
| 307 | pWin->drawable.x - cw->borderClipX, |
| 308 | pWin->drawable.y - cw->borderClipY); |
| 309 | cw->borderClipX = pWin->drawable.x; |
| 310 | cw->borderClipY = pWin->drawable.y; |
| 311 | } |
| 312 | } |
| 313 | if (cs->ClipNotify) { |
| 314 | pScreen->ClipNotify = cs->ClipNotify; |
| 315 | (*pScreen->ClipNotify) (pWin, dx, dy); |
| 316 | cs->ClipNotify = pScreen->ClipNotify; |
| 317 | pScreen->ClipNotify = compClipNotify; |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | /* |
| 322 | * Returns TRUE if the window needs server-provided automatic redirect, |
| 323 | * which is true if the child and parent aren't both regular or ARGB visuals |
| 324 | */ |
| 325 | |
| 326 | static Bool |
| 327 | compIsAlternateVisual(ScreenPtr pScreen, XID visual) |
| 328 | { |
| 329 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 330 | int i; |
| 331 | |
| 332 | for (i = 0; i < cs->numAlternateVisuals; i++) |
| 333 | if (cs->alternateVisuals[i] == visual) |
| 334 | return TRUE; |
| 335 | return FALSE; |
| 336 | } |
| 337 | |
| 338 | static Bool |
| 339 | compImplicitRedirect(WindowPtr pWin, WindowPtr pParent) |
| 340 | { |
| 341 | if (pParent) { |
| 342 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 343 | XID winVisual = wVisual(pWin); |
| 344 | XID parentVisual = wVisual(pParent); |
| 345 | |
| 346 | if (winVisual != parentVisual && |
| 347 | (compIsAlternateVisual(pScreen, winVisual) || |
| 348 | compIsAlternateVisual(pScreen, parentVisual))) |
| 349 | return TRUE; |
| 350 | } |
| 351 | return FALSE; |
| 352 | } |
| 353 | |
| 354 | static void |
| 355 | compFreeOldPixmap(WindowPtr pWin) |
| 356 | { |
| 357 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 358 | |
| 359 | if (pWin->redirectDraw != RedirectDrawNone) { |
| 360 | CompWindowPtr cw = GetCompWindow(pWin); |
| 361 | |
| 362 | if (cw->pOldPixmap) { |
| 363 | (*pScreen->DestroyPixmap) (cw->pOldPixmap); |
| 364 | cw->pOldPixmap = NullPixmap; |
| 365 | } |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | void |
| 370 | compMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind) |
| 371 | { |
| 372 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 373 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 374 | |
| 375 | pScreen->MoveWindow = cs->MoveWindow; |
| 376 | (*pScreen->MoveWindow) (pWin, x, y, pSib, kind); |
| 377 | cs->MoveWindow = pScreen->MoveWindow; |
| 378 | pScreen->MoveWindow = compMoveWindow; |
| 379 | |
| 380 | compFreeOldPixmap(pWin); |
| 381 | compCheckTree(pScreen); |
| 382 | } |
| 383 | |
| 384 | void |
| 385 | compResizeWindow(WindowPtr pWin, int x, int y, |
| 386 | unsigned int w, unsigned int h, WindowPtr pSib) |
| 387 | { |
| 388 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 389 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 390 | |
| 391 | pScreen->ResizeWindow = cs->ResizeWindow; |
| 392 | (*pScreen->ResizeWindow) (pWin, x, y, w, h, pSib); |
| 393 | cs->ResizeWindow = pScreen->ResizeWindow; |
| 394 | pScreen->ResizeWindow = compResizeWindow; |
| 395 | |
| 396 | compFreeOldPixmap(pWin); |
| 397 | compCheckTree(pWin->drawable.pScreen); |
| 398 | } |
| 399 | |
| 400 | void |
| 401 | compChangeBorderWidth(WindowPtr pWin, unsigned int bw) |
| 402 | { |
| 403 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 404 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 405 | |
| 406 | pScreen->ChangeBorderWidth = cs->ChangeBorderWidth; |
| 407 | (*pScreen->ChangeBorderWidth) (pWin, bw); |
| 408 | cs->ChangeBorderWidth = pScreen->ChangeBorderWidth; |
| 409 | pScreen->ChangeBorderWidth = compChangeBorderWidth; |
| 410 | |
| 411 | compFreeOldPixmap(pWin); |
| 412 | compCheckTree(pWin->drawable.pScreen); |
| 413 | } |
| 414 | |
| 415 | void |
| 416 | compReparentWindow(WindowPtr pWin, WindowPtr pPriorParent) |
| 417 | { |
| 418 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 419 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 420 | |
| 421 | pScreen->ReparentWindow = cs->ReparentWindow; |
| 422 | /* |
| 423 | * Remove any implicit redirect due to synthesized visual |
| 424 | */ |
| 425 | if (compImplicitRedirect(pWin, pPriorParent)) |
| 426 | compUnredirectWindow(serverClient, pWin, CompositeRedirectAutomatic); |
| 427 | /* |
| 428 | * Handle subwindows redirection |
| 429 | */ |
| 430 | compUnredirectOneSubwindow(pPriorParent, pWin); |
| 431 | compRedirectOneSubwindow(pWin->parent, pWin); |
| 432 | /* |
| 433 | * Add any implict redirect due to synthesized visual |
| 434 | */ |
| 435 | if (compImplicitRedirect(pWin, pWin->parent)) |
| 436 | compRedirectWindow(serverClient, pWin, CompositeRedirectAutomatic); |
| 437 | |
| 438 | /* |
| 439 | * Allocate any necessary redirect pixmap |
| 440 | * (this actually should never be true; pWin is always unmapped) |
| 441 | */ |
| 442 | compCheckRedirect(pWin); |
| 443 | |
| 444 | /* |
| 445 | * Reset pixmap pointers as appropriate |
| 446 | */ |
| 447 | if (pWin->parent && pWin->redirectDraw == RedirectDrawNone) |
| 448 | compSetPixmap(pWin, (*pScreen->GetWindowPixmap) (pWin->parent)); |
| 449 | /* |
| 450 | * Call down to next function |
| 451 | */ |
| 452 | if (pScreen->ReparentWindow) |
| 453 | (*pScreen->ReparentWindow) (pWin, pPriorParent); |
| 454 | cs->ReparentWindow = pScreen->ReparentWindow; |
| 455 | pScreen->ReparentWindow = compReparentWindow; |
| 456 | compCheckTree(pWin->drawable.pScreen); |
| 457 | } |
| 458 | |
| 459 | void |
| 460 | compCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) |
| 461 | { |
| 462 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 463 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 464 | int dx = 0, dy = 0; |
| 465 | |
| 466 | if (pWin->redirectDraw != RedirectDrawNone) { |
| 467 | PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin); |
| 468 | CompWindowPtr cw = GetCompWindow(pWin); |
| 469 | |
| 470 | assert(cw->oldx != COMP_ORIGIN_INVALID); |
| 471 | assert(cw->oldy != COMP_ORIGIN_INVALID); |
| 472 | if (cw->pOldPixmap) { |
| 473 | /* |
| 474 | * Ok, the old bits are available in pOldPixmap and |
| 475 | * need to be copied to pNewPixmap. |
| 476 | */ |
| 477 | RegionRec rgnDst; |
| 478 | PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin); |
| 479 | GCPtr pGC; |
| 480 | |
| 481 | dx = ptOldOrg.x - pWin->drawable.x; |
| 482 | dy = ptOldOrg.y - pWin->drawable.y; |
| 483 | RegionTranslate(prgnSrc, -dx, -dy); |
| 484 | |
| 485 | RegionNull(&rgnDst); |
| 486 | |
| 487 | RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc); |
| 488 | |
| 489 | RegionTranslate(&rgnDst, -pPixmap->screen_x, -pPixmap->screen_y); |
| 490 | |
| 491 | dx = dx + pPixmap->screen_x - cw->oldx; |
| 492 | dy = dy + pPixmap->screen_y - cw->oldy; |
| 493 | pGC = GetScratchGC(pPixmap->drawable.depth, pScreen); |
| 494 | if (pGC) { |
| 495 | BoxPtr pBox = RegionRects(&rgnDst); |
| 496 | int nBox = RegionNumRects(&rgnDst); |
| 497 | |
| 498 | ValidateGC(&pPixmap->drawable, pGC); |
| 499 | while (nBox--) { |
| 500 | (void) (*pGC->ops->CopyArea) (&cw->pOldPixmap->drawable, |
| 501 | &pPixmap->drawable, |
| 502 | pGC, |
| 503 | pBox->x1 + dx, pBox->y1 + dy, |
| 504 | pBox->x2 - pBox->x1, |
| 505 | pBox->y2 - pBox->y1, |
| 506 | pBox->x1, pBox->y1); |
| 507 | pBox++; |
| 508 | } |
| 509 | FreeScratchGC(pGC); |
| 510 | } |
| 511 | return; |
| 512 | } |
| 513 | dx = pPixmap->screen_x - cw->oldx; |
| 514 | dy = pPixmap->screen_y - cw->oldy; |
| 515 | ptOldOrg.x += dx; |
| 516 | ptOldOrg.y += dy; |
| 517 | } |
| 518 | |
| 519 | pScreen->CopyWindow = cs->CopyWindow; |
| 520 | if (ptOldOrg.x != pWin->drawable.x || ptOldOrg.y != pWin->drawable.y) { |
| 521 | if (dx || dy) |
| 522 | RegionTranslate(prgnSrc, dx, dy); |
| 523 | (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc); |
| 524 | if (dx || dy) |
| 525 | RegionTranslate(prgnSrc, -dx, -dy); |
| 526 | } |
| 527 | else { |
| 528 | ptOldOrg.x -= dx; |
| 529 | ptOldOrg.y -= dy; |
| 530 | RegionTranslate(prgnSrc, |
| 531 | pWin->drawable.x - ptOldOrg.x, |
| 532 | pWin->drawable.y - ptOldOrg.y); |
| 533 | DamageDamageRegion(&pWin->drawable, prgnSrc); |
| 534 | } |
| 535 | cs->CopyWindow = pScreen->CopyWindow; |
| 536 | pScreen->CopyWindow = compCopyWindow; |
| 537 | compCheckTree(pWin->drawable.pScreen); |
| 538 | } |
| 539 | |
| 540 | Bool |
| 541 | compCreateWindow(WindowPtr pWin) |
| 542 | { |
| 543 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 544 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 545 | Bool ret; |
| 546 | |
| 547 | pScreen->CreateWindow = cs->CreateWindow; |
| 548 | ret = (*pScreen->CreateWindow) (pWin); |
| 549 | if (pWin->parent && ret) { |
| 550 | CompSubwindowsPtr csw = GetCompSubwindows(pWin->parent); |
| 551 | CompClientWindowPtr ccw; |
| 552 | |
| 553 | (*pScreen->SetWindowPixmap) (pWin, |
| 554 | (*pScreen->GetWindowPixmap) (pWin-> |
| 555 | parent)); |
| 556 | if (csw) |
| 557 | for (ccw = csw->clients; ccw; ccw = ccw->next) |
| 558 | compRedirectWindow(clients[CLIENT_ID(ccw->id)], |
| 559 | pWin, ccw->update); |
| 560 | if (compImplicitRedirect(pWin, pWin->parent)) |
| 561 | compRedirectWindow(serverClient, pWin, CompositeRedirectAutomatic); |
| 562 | } |
| 563 | cs->CreateWindow = pScreen->CreateWindow; |
| 564 | pScreen->CreateWindow = compCreateWindow; |
| 565 | compCheckTree(pWin->drawable.pScreen); |
| 566 | return ret; |
| 567 | } |
| 568 | |
| 569 | Bool |
| 570 | compDestroyWindow(WindowPtr pWin) |
| 571 | { |
| 572 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 573 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 574 | CompWindowPtr cw; |
| 575 | CompSubwindowsPtr csw; |
| 576 | Bool ret; |
| 577 | |
| 578 | pScreen->DestroyWindow = cs->DestroyWindow; |
| 579 | while ((cw = GetCompWindow(pWin))) |
| 580 | FreeResource(cw->clients->id, RT_NONE); |
| 581 | while ((csw = GetCompSubwindows(pWin))) |
| 582 | FreeResource(csw->clients->id, RT_NONE); |
| 583 | |
| 584 | if (pWin->redirectDraw != RedirectDrawNone) { |
| 585 | PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin); |
| 586 | |
| 587 | compSetParentPixmap(pWin); |
| 588 | (*pScreen->DestroyPixmap) (pPixmap); |
| 589 | } |
| 590 | ret = (*pScreen->DestroyWindow) (pWin); |
| 591 | cs->DestroyWindow = pScreen->DestroyWindow; |
| 592 | pScreen->DestroyWindow = compDestroyWindow; |
| 593 | /* compCheckTree (pWin->drawable.pScreen); can't check -- tree isn't good*/ |
| 594 | return ret; |
| 595 | } |
| 596 | |
| 597 | void |
| 598 | compSetRedirectBorderClip(WindowPtr pWin, RegionPtr pRegion) |
| 599 | { |
| 600 | CompWindowPtr cw = GetCompWindow(pWin); |
| 601 | RegionRec damage; |
| 602 | |
| 603 | RegionNull(&damage); |
| 604 | /* |
| 605 | * Align old border clip with new border clip |
| 606 | */ |
| 607 | RegionTranslate(&cw->borderClip, |
| 608 | pWin->drawable.x - cw->borderClipX, |
| 609 | pWin->drawable.y - cw->borderClipY); |
| 610 | /* |
| 611 | * Compute newly visible portion of window for repaint |
| 612 | */ |
| 613 | RegionSubtract(&damage, pRegion, &cw->borderClip); |
| 614 | /* |
| 615 | * Report that as damaged so it will be redrawn |
| 616 | */ |
| 617 | DamageDamageRegion(&pWin->drawable, &damage); |
| 618 | RegionUninit(&damage); |
| 619 | /* |
| 620 | * Save the new border clip region |
| 621 | */ |
| 622 | RegionCopy(&cw->borderClip, pRegion); |
| 623 | cw->borderClipX = pWin->drawable.x; |
| 624 | cw->borderClipY = pWin->drawable.y; |
| 625 | } |
| 626 | |
| 627 | RegionPtr |
| 628 | compGetRedirectBorderClip(WindowPtr pWin) |
| 629 | { |
| 630 | CompWindowPtr cw = GetCompWindow(pWin); |
| 631 | |
| 632 | return &cw->borderClip; |
| 633 | } |
| 634 | |
| 635 | static void |
| 636 | compWindowUpdateAutomatic(WindowPtr pWin) |
| 637 | { |
| 638 | CompWindowPtr cw = GetCompWindow(pWin); |
| 639 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 640 | WindowPtr pParent = pWin->parent; |
| 641 | PixmapPtr pSrcPixmap = (*pScreen->GetWindowPixmap) (pWin); |
| 642 | PictFormatPtr pSrcFormat = PictureWindowFormat(pWin); |
| 643 | PictFormatPtr pDstFormat = PictureWindowFormat(pWin->parent); |
| 644 | int error; |
| 645 | RegionPtr pRegion = DamageRegion(cw->damage); |
| 646 | PicturePtr pSrcPicture = CreatePicture(0, &pSrcPixmap->drawable, |
| 647 | pSrcFormat, |
| 648 | 0, 0, |
| 649 | serverClient, |
| 650 | &error); |
| 651 | XID subwindowMode = IncludeInferiors; |
| 652 | PicturePtr pDstPicture = CreatePicture(0, &pParent->drawable, |
| 653 | pDstFormat, |
| 654 | CPSubwindowMode, |
| 655 | &subwindowMode, |
| 656 | serverClient, |
| 657 | &error); |
| 658 | |
| 659 | /* |
| 660 | * First move the region from window to screen coordinates |
| 661 | */ |
| 662 | RegionTranslate(pRegion, pWin->drawable.x, pWin->drawable.y); |
| 663 | |
| 664 | /* |
| 665 | * Clip against the "real" border clip |
| 666 | */ |
| 667 | RegionIntersect(pRegion, pRegion, &cw->borderClip); |
| 668 | |
| 669 | /* |
| 670 | * Now translate from screen to dest coordinates |
| 671 | */ |
| 672 | RegionTranslate(pRegion, -pParent->drawable.x, -pParent->drawable.y); |
| 673 | |
| 674 | /* |
| 675 | * Clip the picture |
| 676 | */ |
| 677 | SetPictureClipRegion(pDstPicture, 0, 0, pRegion); |
| 678 | |
| 679 | /* |
| 680 | * And paint |
| 681 | */ |
| 682 | CompositePicture(PictOpSrc, pSrcPicture, 0, pDstPicture, |
| 683 | 0, 0, /* src_x, src_y */ |
| 684 | 0, 0, /* msk_x, msk_y */ |
| 685 | pSrcPixmap->screen_x - pParent->drawable.x, |
| 686 | pSrcPixmap->screen_y - pParent->drawable.y, |
| 687 | pSrcPixmap->drawable.width, pSrcPixmap->drawable.height); |
| 688 | FreePicture(pSrcPicture, 0); |
| 689 | FreePicture(pDstPicture, 0); |
| 690 | /* |
| 691 | * Empty the damage region. This has the nice effect of |
| 692 | * rendering the translations above harmless |
| 693 | */ |
| 694 | DamageEmpty(cw->damage); |
| 695 | } |
| 696 | |
| 697 | static void |
| 698 | compPaintWindowToParent(WindowPtr pWin) |
| 699 | { |
| 700 | compPaintChildrenToWindow(pWin); |
| 701 | |
| 702 | if (pWin->redirectDraw != RedirectDrawNone) { |
| 703 | CompWindowPtr cw = GetCompWindow(pWin); |
| 704 | |
| 705 | if (cw->damaged) { |
| 706 | compWindowUpdateAutomatic(pWin); |
| 707 | cw->damaged = FALSE; |
| 708 | } |
| 709 | } |
| 710 | } |
| 711 | |
| 712 | void |
| 713 | compPaintChildrenToWindow(WindowPtr pWin) |
| 714 | { |
| 715 | WindowPtr pChild; |
| 716 | |
| 717 | if (!pWin->damagedDescendants) |
| 718 | return; |
| 719 | |
| 720 | for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) |
| 721 | compPaintWindowToParent(pChild); |
| 722 | |
| 723 | pWin->damagedDescendants = FALSE; |
| 724 | } |
| 725 | |
| 726 | WindowPtr |
| 727 | CompositeRealChildHead(WindowPtr pWin) |
| 728 | { |
| 729 | WindowPtr pChild, pChildBefore; |
| 730 | CompScreenPtr cs; |
| 731 | |
| 732 | if (!pWin->parent && |
| 733 | (screenIsSaved == SCREEN_SAVER_ON) && |
| 734 | (HasSaverWindow(pWin->drawable.pScreen))) { |
| 735 | |
| 736 | /* First child is the screen saver; see if next child is the overlay */ |
| 737 | pChildBefore = pWin->firstChild; |
| 738 | pChild = pChildBefore->nextSib; |
| 739 | |
| 740 | } |
| 741 | else { |
| 742 | pChildBefore = NullWindow; |
| 743 | pChild = pWin->firstChild; |
| 744 | } |
| 745 | |
| 746 | if (!pChild) { |
| 747 | return NullWindow; |
| 748 | } |
| 749 | |
| 750 | cs = GetCompScreen(pWin->drawable.pScreen); |
| 751 | if (pChild == cs->pOverlayWin) { |
| 752 | return pChild; |
| 753 | } |
| 754 | else { |
| 755 | return pChildBefore; |
| 756 | } |
| 757 | } |
| 758 | |
| 759 | int |
| 760 | compConfigNotify(WindowPtr pWin, int x, int y, int w, int h, |
| 761 | int bw, WindowPtr pSib) |
| 762 | { |
| 763 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 764 | CompScreenPtr cs = GetCompScreen(pScreen); |
| 765 | Bool ret = 0; |
| 766 | WindowPtr pParent = pWin->parent; |
| 767 | int draw_x, draw_y; |
| 768 | Bool alloc_ret; |
| 769 | |
| 770 | if (cs->ConfigNotify) { |
| 771 | pScreen->ConfigNotify = cs->ConfigNotify; |
| 772 | ret = (*pScreen->ConfigNotify) (pWin, x, y, w, h, bw, pSib); |
| 773 | cs->ConfigNotify = pScreen->ConfigNotify; |
| 774 | pScreen->ConfigNotify = compConfigNotify; |
| 775 | |
| 776 | if (ret) |
| 777 | return ret; |
| 778 | } |
| 779 | |
| 780 | if (pWin->redirectDraw == RedirectDrawNone) |
| 781 | return Success; |
| 782 | |
| 783 | compCheckTree(pScreen); |
| 784 | |
| 785 | draw_x = pParent->drawable.x + x + bw; |
| 786 | draw_y = pParent->drawable.y + y + bw; |
| 787 | alloc_ret = compReallocPixmap(pWin, draw_x, draw_y, w, h, bw); |
| 788 | |
| 789 | if (alloc_ret == FALSE) |
| 790 | return BadAlloc; |
| 791 | return Success; |
| 792 | } |