Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | } |