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 | static void | |
51 | compScreenUpdate(ScreenPtr pScreen) | |
52 | { | |
53 | compCheckTree(pScreen); | |
54 | compPaintChildrenToWindow(pScreen->root); | |
55 | } | |
56 | ||
57 | static void | |
58 | compBlockHandler(ScreenPtr pScreen, pointer pTimeout, pointer pReadmask) | |
59 | { | |
60 | CompScreenPtr cs = GetCompScreen(pScreen); | |
61 | ||
62 | pScreen->BlockHandler = cs->BlockHandler; | |
63 | compScreenUpdate(pScreen); | |
64 | (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask); | |
65 | ||
66 | /* Next damage will restore the block handler */ | |
67 | cs->BlockHandler = NULL; | |
68 | } | |
69 | ||
70 | static void | |
71 | compReportDamage(DamagePtr pDamage, RegionPtr pRegion, void *closure) | |
72 | { | |
73 | WindowPtr pWin = (WindowPtr) closure; | |
74 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
75 | CompScreenPtr cs = GetCompScreen(pScreen); | |
76 | CompWindowPtr cw = GetCompWindow(pWin); | |
77 | ||
78 | if (!cs->BlockHandler) { | |
79 | cs->BlockHandler = pScreen->BlockHandler; | |
80 | pScreen->BlockHandler = compBlockHandler; | |
81 | } | |
82 | cw->damaged = TRUE; | |
83 | ||
84 | /* Mark the ancestors */ | |
85 | pWin = pWin->parent; | |
86 | while (pWin) { | |
87 | if (pWin->damagedDescendants) | |
88 | break; | |
89 | pWin->damagedDescendants = TRUE; | |
90 | pWin = pWin->parent; | |
91 | } | |
92 | } | |
93 | ||
94 | static void | |
95 | compDestroyDamage(DamagePtr pDamage, void *closure) | |
96 | { | |
97 | WindowPtr pWin = (WindowPtr) closure; | |
98 | CompWindowPtr cw = GetCompWindow(pWin); | |
99 | ||
100 | cw->damage = 0; | |
101 | } | |
102 | ||
103 | static Bool | |
104 | compMarkWindows(WindowPtr pWin, WindowPtr *ppLayerWin) | |
105 | { | |
106 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
107 | WindowPtr pLayerWin = pWin; | |
108 | ||
109 | if (!pWin->viewable) | |
110 | return FALSE; | |
111 | ||
112 | (*pScreen->MarkOverlappedWindows) (pWin, pWin, &pLayerWin); | |
113 | (*pScreen->MarkWindow) (pLayerWin->parent); | |
114 | ||
115 | *ppLayerWin = pLayerWin; | |
116 | ||
117 | return TRUE; | |
118 | } | |
119 | ||
120 | static void | |
121 | compHandleMarkedWindows(WindowPtr pWin, WindowPtr pLayerWin) | |
122 | { | |
123 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
124 | ||
125 | (*pScreen->ValidateTree) (pLayerWin->parent, pLayerWin, VTOther); | |
126 | (*pScreen->HandleExposures) (pLayerWin->parent); | |
127 | if (pScreen->PostValidateTree) | |
128 | (*pScreen->PostValidateTree) (pLayerWin->parent, pLayerWin, VTOther); | |
129 | } | |
130 | ||
131 | /* | |
132 | * Redirect one window for one client | |
133 | */ | |
134 | int | |
135 | compRedirectWindow(ClientPtr pClient, WindowPtr pWin, int update) | |
136 | { | |
137 | CompWindowPtr cw = GetCompWindow(pWin); | |
138 | CompClientWindowPtr ccw; | |
139 | CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen); | |
140 | WindowPtr pLayerWin; | |
141 | Bool anyMarked = FALSE; | |
142 | ||
143 | if (pWin == cs->pOverlayWin) { | |
144 | return Success; | |
145 | } | |
146 | ||
147 | if (!pWin->parent) | |
148 | return BadMatch; | |
149 | ||
150 | /* | |
151 | * Only one Manual update is allowed | |
152 | */ | |
153 | if (cw && update == CompositeRedirectManual) | |
154 | for (ccw = cw->clients; ccw; ccw = ccw->next) | |
155 | if (ccw->update == CompositeRedirectManual) | |
156 | return BadAccess; | |
157 | ||
158 | /* | |
159 | * Allocate per-client per-window structure | |
160 | * The client *could* allocate multiple, but while supported, | |
161 | * it is not expected to be common | |
162 | */ | |
163 | ccw = malloc(sizeof(CompClientWindowRec)); | |
164 | if (!ccw) | |
165 | return BadAlloc; | |
166 | ccw->id = FakeClientID(pClient->index); | |
167 | ccw->update = update; | |
168 | /* | |
169 | * Now make sure there's a per-window structure to hang this from | |
170 | */ | |
171 | if (!cw) { | |
172 | cw = malloc(sizeof(CompWindowRec)); | |
173 | if (!cw) { | |
174 | free(ccw); | |
175 | return BadAlloc; | |
176 | } | |
177 | cw->damage = DamageCreate(compReportDamage, | |
178 | compDestroyDamage, | |
179 | DamageReportNonEmpty, | |
180 | FALSE, pWin->drawable.pScreen, pWin); | |
181 | if (!cw->damage) { | |
182 | free(ccw); | |
183 | free(cw); | |
184 | return BadAlloc; | |
185 | } | |
186 | ||
187 | anyMarked = compMarkWindows(pWin, &pLayerWin); | |
188 | ||
189 | RegionNull(&cw->borderClip); | |
190 | cw->update = CompositeRedirectAutomatic; | |
191 | cw->clients = 0; | |
192 | cw->oldx = COMP_ORIGIN_INVALID; | |
193 | cw->oldy = COMP_ORIGIN_INVALID; | |
194 | cw->damageRegistered = FALSE; | |
195 | cw->damaged = FALSE; | |
196 | cw->pOldPixmap = NullPixmap; | |
197 | dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw); | |
198 | } | |
199 | ccw->next = cw->clients; | |
200 | cw->clients = ccw; | |
201 | if (!AddResource(ccw->id, CompositeClientWindowType, pWin)) | |
202 | return BadAlloc; | |
203 | if (ccw->update == CompositeRedirectManual) { | |
204 | if (!anyMarked) | |
205 | anyMarked = compMarkWindows(pWin, &pLayerWin); | |
206 | ||
207 | if (cw->damageRegistered) { | |
208 | DamageUnregister(cw->damage); | |
209 | cw->damageRegistered = FALSE; | |
210 | } | |
211 | cw->update = CompositeRedirectManual; | |
212 | } | |
213 | else if (cw->update == CompositeRedirectAutomatic && !cw->damageRegistered) { | |
214 | if (!anyMarked) | |
215 | anyMarked = compMarkWindows(pWin, &pLayerWin); | |
216 | } | |
217 | ||
218 | if (!compCheckRedirect(pWin)) { | |
219 | FreeResource(ccw->id, RT_NONE); | |
220 | return BadAlloc; | |
221 | } | |
222 | ||
223 | if (anyMarked) | |
224 | compHandleMarkedWindows(pWin, pLayerWin); | |
225 | ||
226 | return Success; | |
227 | } | |
228 | ||
229 | void | |
230 | compRestoreWindow(WindowPtr pWin, PixmapPtr pPixmap) | |
231 | { | |
232 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
233 | WindowPtr pParent = pWin->parent; | |
234 | ||
235 | if (pParent->drawable.depth == pWin->drawable.depth) { | |
236 | GCPtr pGC = GetScratchGC(pWin->drawable.depth, pScreen); | |
237 | int bw = (int) pWin->borderWidth; | |
238 | int x = bw; | |
239 | int y = bw; | |
240 | int w = pWin->drawable.width; | |
241 | int h = pWin->drawable.height; | |
242 | ||
243 | if (pGC) { | |
244 | ChangeGCVal val; | |
245 | ||
246 | val.val = IncludeInferiors; | |
247 | ChangeGC(NullClient, pGC, GCSubwindowMode, &val); | |
248 | ValidateGC(&pWin->drawable, pGC); | |
249 | (*pGC->ops->CopyArea) (&pPixmap->drawable, | |
250 | &pWin->drawable, pGC, x, y, w, h, 0, 0); | |
251 | FreeScratchGC(pGC); | |
252 | } | |
253 | } | |
254 | } | |
255 | ||
256 | /* | |
257 | * Free one of the per-client per-window resources, clearing | |
258 | * redirect and the per-window pointer as appropriate | |
259 | */ | |
260 | void | |
261 | compFreeClientWindow(WindowPtr pWin, XID id) | |
262 | { | |
263 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
264 | CompWindowPtr cw = GetCompWindow(pWin); | |
265 | CompClientWindowPtr ccw, *prev; | |
266 | Bool anyMarked = FALSE; | |
267 | WindowPtr pLayerWin; | |
268 | PixmapPtr pPixmap = NULL; | |
269 | ||
270 | if (!cw) | |
271 | return; | |
272 | for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next) { | |
273 | if (ccw->id == id) { | |
274 | *prev = ccw->next; | |
275 | if (ccw->update == CompositeRedirectManual) | |
276 | cw->update = CompositeRedirectAutomatic; | |
277 | free(ccw); | |
278 | break; | |
279 | } | |
280 | } | |
281 | if (!cw->clients) { | |
282 | anyMarked = compMarkWindows(pWin, &pLayerWin); | |
283 | ||
284 | if (pWin->redirectDraw != RedirectDrawNone) { | |
285 | pPixmap = (*pScreen->GetWindowPixmap) (pWin); | |
286 | compSetParentPixmap(pWin); | |
287 | } | |
288 | ||
289 | if (cw->damage) | |
290 | DamageDestroy(cw->damage); | |
291 | ||
292 | RegionUninit(&cw->borderClip); | |
293 | ||
294 | dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL); | |
295 | free(cw); | |
296 | } | |
297 | else if (cw->update == CompositeRedirectAutomatic && | |
298 | !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone) { | |
299 | anyMarked = compMarkWindows(pWin, &pLayerWin); | |
300 | ||
301 | DamageRegister(&pWin->drawable, cw->damage); | |
302 | cw->damageRegistered = TRUE; | |
303 | pWin->redirectDraw = RedirectDrawAutomatic; | |
304 | DamageDamageRegion(&pWin->drawable, &pWin->borderSize); | |
305 | } | |
306 | ||
307 | if (anyMarked) | |
308 | compHandleMarkedWindows(pWin, pLayerWin); | |
309 | ||
310 | if (pPixmap) { | |
311 | compRestoreWindow(pWin, pPixmap); | |
312 | (*pScreen->DestroyPixmap) (pPixmap); | |
313 | } | |
314 | } | |
315 | ||
316 | /* | |
317 | * This is easy, just free the appropriate resource. | |
318 | */ | |
319 | ||
320 | int | |
321 | compUnredirectWindow(ClientPtr pClient, WindowPtr pWin, int update) | |
322 | { | |
323 | CompWindowPtr cw = GetCompWindow(pWin); | |
324 | CompClientWindowPtr ccw; | |
325 | ||
326 | if (!cw) | |
327 | return BadValue; | |
328 | ||
329 | for (ccw = cw->clients; ccw; ccw = ccw->next) | |
330 | if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) { | |
331 | FreeResource(ccw->id, RT_NONE); | |
332 | return Success; | |
333 | } | |
334 | return BadValue; | |
335 | } | |
336 | ||
337 | /* | |
338 | * Redirect all subwindows for one client | |
339 | */ | |
340 | ||
341 | int | |
342 | compRedirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update) | |
343 | { | |
344 | CompSubwindowsPtr csw = GetCompSubwindows(pWin); | |
345 | CompClientWindowPtr ccw; | |
346 | WindowPtr pChild; | |
347 | ||
348 | /* | |
349 | * Only one Manual update is allowed | |
350 | */ | |
351 | if (csw && update == CompositeRedirectManual) | |
352 | for (ccw = csw->clients; ccw; ccw = ccw->next) | |
353 | if (ccw->update == CompositeRedirectManual) | |
354 | return BadAccess; | |
355 | /* | |
356 | * Allocate per-client per-window structure | |
357 | * The client *could* allocate multiple, but while supported, | |
358 | * it is not expected to be common | |
359 | */ | |
360 | ccw = malloc(sizeof(CompClientWindowRec)); | |
361 | if (!ccw) | |
362 | return BadAlloc; | |
363 | ccw->id = FakeClientID(pClient->index); | |
364 | ccw->update = update; | |
365 | /* | |
366 | * Now make sure there's a per-window structure to hang this from | |
367 | */ | |
368 | if (!csw) { | |
369 | csw = malloc(sizeof(CompSubwindowsRec)); | |
370 | if (!csw) { | |
371 | free(ccw); | |
372 | return BadAlloc; | |
373 | } | |
374 | csw->update = CompositeRedirectAutomatic; | |
375 | csw->clients = 0; | |
376 | dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw); | |
377 | } | |
378 | /* | |
379 | * Redirect all existing windows | |
380 | */ | |
381 | for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) { | |
382 | int ret = compRedirectWindow(pClient, pChild, update); | |
383 | ||
384 | if (ret != Success) { | |
385 | for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib) | |
386 | (void) compUnredirectWindow(pClient, pChild, update); | |
387 | if (!csw->clients) { | |
388 | free(csw); | |
389 | dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0); | |
390 | } | |
391 | free(ccw); | |
392 | return ret; | |
393 | } | |
394 | } | |
395 | /* | |
396 | * Hook into subwindows list | |
397 | */ | |
398 | ccw->next = csw->clients; | |
399 | csw->clients = ccw; | |
400 | if (!AddResource(ccw->id, CompositeClientSubwindowsType, pWin)) | |
401 | return BadAlloc; | |
402 | if (ccw->update == CompositeRedirectManual) { | |
403 | csw->update = CompositeRedirectManual; | |
404 | /* | |
405 | * tell damage extension that damage events for this client are | |
406 | * critical output | |
407 | */ | |
408 | DamageExtSetCritical(pClient, TRUE); | |
409 | pWin->inhibitBGPaint = TRUE; | |
410 | } | |
411 | return Success; | |
412 | } | |
413 | ||
414 | /* | |
415 | * Free one of the per-client per-subwindows resources, | |
416 | * which frees one redirect per subwindow | |
417 | */ | |
418 | void | |
419 | compFreeClientSubwindows(WindowPtr pWin, XID id) | |
420 | { | |
421 | CompSubwindowsPtr csw = GetCompSubwindows(pWin); | |
422 | CompClientWindowPtr ccw, *prev; | |
423 | WindowPtr pChild; | |
424 | ||
425 | if (!csw) | |
426 | return; | |
427 | for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next) { | |
428 | if (ccw->id == id) { | |
429 | ClientPtr pClient = clients[CLIENT_ID(id)]; | |
430 | ||
431 | *prev = ccw->next; | |
432 | if (ccw->update == CompositeRedirectManual) { | |
433 | /* | |
434 | * tell damage extension that damage events for this client are | |
435 | * critical output | |
436 | */ | |
437 | DamageExtSetCritical(pClient, FALSE); | |
438 | csw->update = CompositeRedirectAutomatic; | |
439 | pWin->inhibitBGPaint = FALSE; | |
440 | if (pWin->mapped) | |
441 | (*pWin->drawable.pScreen->ClearToBackground) (pWin, 0, 0, 0, | |
442 | 0, TRUE); | |
443 | } | |
444 | ||
445 | /* | |
446 | * Unredirect all existing subwindows | |
447 | */ | |
448 | for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) | |
449 | (void) compUnredirectWindow(pClient, pChild, ccw->update); | |
450 | ||
451 | free(ccw); | |
452 | break; | |
453 | } | |
454 | } | |
455 | ||
456 | /* | |
457 | * Check if all of the per-client records are gone | |
458 | */ | |
459 | if (!csw->clients) { | |
460 | dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL); | |
461 | free(csw); | |
462 | } | |
463 | } | |
464 | ||
465 | /* | |
466 | * This is easy, just free the appropriate resource. | |
467 | */ | |
468 | ||
469 | int | |
470 | compUnredirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update) | |
471 | { | |
472 | CompSubwindowsPtr csw = GetCompSubwindows(pWin); | |
473 | CompClientWindowPtr ccw; | |
474 | ||
475 | if (!csw) | |
476 | return BadValue; | |
477 | for (ccw = csw->clients; ccw; ccw = ccw->next) | |
478 | if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) { | |
479 | FreeResource(ccw->id, RT_NONE); | |
480 | return Success; | |
481 | } | |
482 | return BadValue; | |
483 | } | |
484 | ||
485 | /* | |
486 | * Add redirection information for one subwindow (during reparent) | |
487 | */ | |
488 | ||
489 | int | |
490 | compRedirectOneSubwindow(WindowPtr pParent, WindowPtr pWin) | |
491 | { | |
492 | CompSubwindowsPtr csw = GetCompSubwindows(pParent); | |
493 | CompClientWindowPtr ccw; | |
494 | ||
495 | if (!csw) | |
496 | return Success; | |
497 | for (ccw = csw->clients; ccw; ccw = ccw->next) { | |
498 | int ret = compRedirectWindow(clients[CLIENT_ID(ccw->id)], | |
499 | pWin, ccw->update); | |
500 | ||
501 | if (ret != Success) | |
502 | return ret; | |
503 | } | |
504 | return Success; | |
505 | } | |
506 | ||
507 | /* | |
508 | * Remove redirection information for one subwindow (during reparent) | |
509 | */ | |
510 | ||
511 | int | |
512 | compUnredirectOneSubwindow(WindowPtr pParent, WindowPtr pWin) | |
513 | { | |
514 | CompSubwindowsPtr csw = GetCompSubwindows(pParent); | |
515 | CompClientWindowPtr ccw; | |
516 | ||
517 | if (!csw) | |
518 | return Success; | |
519 | for (ccw = csw->clients; ccw; ccw = ccw->next) { | |
520 | int ret = compUnredirectWindow(clients[CLIENT_ID(ccw->id)], | |
521 | pWin, ccw->update); | |
522 | ||
523 | if (ret != Success) | |
524 | return ret; | |
525 | } | |
526 | return Success; | |
527 | } | |
528 | ||
529 | static PixmapPtr | |
530 | compNewPixmap(WindowPtr pWin, int x, int y, int w, int h) | |
531 | { | |
532 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
533 | WindowPtr pParent = pWin->parent; | |
534 | PixmapPtr pPixmap; | |
535 | ||
536 | pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth, | |
537 | CREATE_PIXMAP_USAGE_BACKING_PIXMAP); | |
538 | ||
539 | if (!pPixmap) | |
540 | return 0; | |
541 | ||
542 | pPixmap->screen_x = x; | |
543 | pPixmap->screen_y = y; | |
544 | ||
545 | if (pParent->drawable.depth == pWin->drawable.depth) { | |
546 | GCPtr pGC = GetScratchGC(pWin->drawable.depth, pScreen); | |
547 | ||
548 | if (pGC) { | |
549 | ChangeGCVal val; | |
550 | ||
551 | val.val = IncludeInferiors; | |
552 | ChangeGC(NullClient, pGC, GCSubwindowMode, &val); | |
553 | ValidateGC(&pPixmap->drawable, pGC); | |
554 | (*pGC->ops->CopyArea) (&pParent->drawable, | |
555 | &pPixmap->drawable, | |
556 | pGC, | |
557 | x - pParent->drawable.x, | |
558 | y - pParent->drawable.y, w, h, 0, 0); | |
559 | FreeScratchGC(pGC); | |
560 | } | |
561 | } | |
562 | else { | |
563 | PictFormatPtr pSrcFormat = PictureWindowFormat(pParent); | |
564 | PictFormatPtr pDstFormat = PictureWindowFormat(pWin); | |
565 | XID inferiors = IncludeInferiors; | |
566 | int error; | |
567 | ||
568 | PicturePtr pSrcPicture = CreatePicture(None, | |
569 | &pParent->drawable, | |
570 | pSrcFormat, | |
571 | CPSubwindowMode, | |
572 | &inferiors, | |
573 | serverClient, &error); | |
574 | ||
575 | PicturePtr pDstPicture = CreatePicture(None, | |
576 | &pPixmap->drawable, | |
577 | pDstFormat, | |
578 | 0, 0, | |
579 | serverClient, &error); | |
580 | ||
581 | if (pSrcPicture && pDstPicture) { | |
582 | CompositePicture(PictOpSrc, | |
583 | pSrcPicture, | |
584 | NULL, | |
585 | pDstPicture, | |
586 | x - pParent->drawable.x, | |
587 | y - pParent->drawable.y, 0, 0, 0, 0, w, h); | |
588 | } | |
589 | if (pSrcPicture) | |
590 | FreePicture(pSrcPicture, 0); | |
591 | if (pDstPicture) | |
592 | FreePicture(pDstPicture, 0); | |
593 | } | |
594 | return pPixmap; | |
595 | } | |
596 | ||
597 | Bool | |
598 | compAllocPixmap(WindowPtr pWin) | |
599 | { | |
600 | int bw = (int) pWin->borderWidth; | |
601 | int x = pWin->drawable.x - bw; | |
602 | int y = pWin->drawable.y - bw; | |
603 | int w = pWin->drawable.width + (bw << 1); | |
604 | int h = pWin->drawable.height + (bw << 1); | |
605 | PixmapPtr pPixmap = compNewPixmap(pWin, x, y, w, h); | |
606 | CompWindowPtr cw = GetCompWindow(pWin); | |
607 | ||
608 | if (!pPixmap) | |
609 | return FALSE; | |
610 | if (cw->update == CompositeRedirectAutomatic) | |
611 | pWin->redirectDraw = RedirectDrawAutomatic; | |
612 | else | |
613 | pWin->redirectDraw = RedirectDrawManual; | |
614 | ||
615 | compSetPixmap(pWin, pPixmap); | |
616 | cw->oldx = COMP_ORIGIN_INVALID; | |
617 | cw->oldy = COMP_ORIGIN_INVALID; | |
618 | cw->damageRegistered = FALSE; | |
619 | if (cw->update == CompositeRedirectAutomatic) { | |
620 | DamageRegister(&pWin->drawable, cw->damage); | |
621 | cw->damageRegistered = TRUE; | |
622 | } | |
623 | ||
624 | /* Make sure our borderClip is up to date */ | |
625 | RegionUninit(&cw->borderClip); | |
626 | RegionCopy(&cw->borderClip, &pWin->borderClip); | |
627 | cw->borderClipX = pWin->drawable.x; | |
628 | cw->borderClipY = pWin->drawable.y; | |
629 | ||
630 | return TRUE; | |
631 | } | |
632 | ||
633 | void | |
634 | compSetParentPixmap(WindowPtr pWin) | |
635 | { | |
636 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
637 | PixmapPtr pParentPixmap; | |
638 | CompWindowPtr cw = GetCompWindow(pWin); | |
639 | ||
640 | if (cw->damageRegistered) { | |
641 | DamageUnregister(cw->damage); | |
642 | cw->damageRegistered = FALSE; | |
643 | DamageEmpty(cw->damage); | |
644 | } | |
645 | /* | |
646 | * Move the parent-constrained border clip region back into | |
647 | * the window so that ValidateTree will handle the unmap | |
648 | * case correctly. Unmap adds the window borderClip to the | |
649 | * parent exposed area; regions beyond the parent cause crashes | |
650 | */ | |
651 | RegionCopy(&pWin->borderClip, &cw->borderClip); | |
652 | pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent); | |
653 | pWin->redirectDraw = RedirectDrawNone; | |
654 | compSetPixmap(pWin, pParentPixmap); | |
655 | } | |
656 | ||
657 | /* | |
658 | * Make sure the pixmap is the right size and offset. Allocate a new | |
659 | * pixmap to change size, adjust origin to change offset, leaving the | |
660 | * old pixmap in cw->pOldPixmap so bits can be recovered | |
661 | */ | |
662 | Bool | |
663 | compReallocPixmap(WindowPtr pWin, int draw_x, int draw_y, | |
664 | unsigned int w, unsigned int h, int bw) | |
665 | { | |
666 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
667 | PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin); | |
668 | PixmapPtr pNew; | |
669 | CompWindowPtr cw = GetCompWindow(pWin); | |
670 | int pix_x, pix_y; | |
671 | int pix_w, pix_h; | |
672 | ||
673 | assert(cw && pWin->redirectDraw != RedirectDrawNone); | |
674 | cw->oldx = pOld->screen_x; | |
675 | cw->oldy = pOld->screen_y; | |
676 | pix_x = draw_x - bw; | |
677 | pix_y = draw_y - bw; | |
678 | pix_w = w + (bw << 1); | |
679 | pix_h = h + (bw << 1); | |
680 | if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height) { | |
681 | pNew = compNewPixmap(pWin, pix_x, pix_y, pix_w, pix_h); | |
682 | if (!pNew) | |
683 | return FALSE; | |
684 | cw->pOldPixmap = pOld; | |
685 | compSetPixmap(pWin, pNew); | |
686 | } | |
687 | else { | |
688 | pNew = pOld; | |
689 | cw->pOldPixmap = 0; | |
690 | } | |
691 | pNew->screen_x = pix_x; | |
692 | pNew->screen_y = pix_y; | |
693 | return TRUE; | |
694 | } |