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