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