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