compwindow.c revision 1b5d61b8
1/*
2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Copyright © 2003 Keith Packard
24 *
25 * Permission to use, copy, modify, distribute, and sell this software and its
26 * documentation for any purpose is hereby granted without fee, provided that
27 * the above copyright notice appear in all copies and that both that
28 * copyright notice and this permission notice appear in supporting
29 * documentation, and that the name of Keith Packard not be used in
30 * advertising or publicity pertaining to distribution of the software without
31 * specific, written prior permission.  Keith Packard makes no
32 * representations about the suitability of this software for any purpose.  It
33 * is provided "as is" without express or implied warranty.
34 *
35 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
36 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
37 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
39 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
40 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
41 * PERFORMANCE OF THIS SOFTWARE.
42 */
43
44#ifdef HAVE_DIX_CONFIG_H
45#include <dix-config.h>
46#endif
47
48#include "compint.h"
49
50#ifdef PANORAMIX
51#include "panoramiXsrv.h"
52#endif
53
54#ifdef COMPOSITE_DEBUG
55static int
56compCheckWindow(WindowPtr pWin, void *data)
57{
58    ScreenPtr pScreen = pWin->drawable.pScreen;
59    PixmapPtr pWinPixmap = (*pScreen->GetWindowPixmap) (pWin);
60    PixmapPtr pParentPixmap =
61        pWin->parent ? (*pScreen->GetWindowPixmap) (pWin->parent) : 0;
62    PixmapPtr pScreenPixmap = (*pScreen->GetScreenPixmap) (pScreen);
63
64    if (!pWin->parent) {
65        assert(pWin->redirectDraw == RedirectDrawNone);
66        assert(pWinPixmap == pScreenPixmap);
67    }
68    else if (pWin->redirectDraw != RedirectDrawNone) {
69        assert(pWinPixmap != pParentPixmap);
70        assert(pWinPixmap != pScreenPixmap);
71    }
72    else {
73        assert(pWinPixmap == pParentPixmap);
74    }
75    assert(0 < pWinPixmap->refcnt && pWinPixmap->refcnt < 3);
76    assert(0 < pScreenPixmap->refcnt && pScreenPixmap->refcnt < 3);
77    if (pParentPixmap)
78        assert(0 <= pParentPixmap->refcnt && pParentPixmap->refcnt < 3);
79    return WT_WALKCHILDREN;
80}
81
82void
83compCheckTree(ScreenPtr pScreen)
84{
85    WalkTree(pScreen, compCheckWindow, 0);
86}
87#endif
88
89typedef struct _compPixmapVisit {
90    WindowPtr pWindow;
91    PixmapPtr pPixmap;
92    int bw;
93} CompPixmapVisitRec, *CompPixmapVisitPtr;
94
95static Bool
96compRepaintBorder(ClientPtr pClient, void *closure)
97{
98    WindowPtr pWindow;
99    int rc =
100        dixLookupWindow(&pWindow, (XID) (intptr_t) closure, pClient,
101                        DixWriteAccess);
102
103    if (rc == Success) {
104        RegionRec exposed;
105
106        RegionNull(&exposed);
107        RegionSubtract(&exposed, &pWindow->borderClip, &pWindow->winSize);
108        pWindow->drawable.pScreen->PaintWindow(pWindow, &exposed, PW_BORDER);
109        RegionUninit(&exposed);
110    }
111    return TRUE;
112}
113
114static int
115compSetPixmapVisitWindow(WindowPtr pWindow, void *data)
116{
117    CompPixmapVisitPtr pVisit = (CompPixmapVisitPtr) data;
118    ScreenPtr pScreen = pWindow->drawable.pScreen;
119
120    if (pWindow != pVisit->pWindow && pWindow->redirectDraw != RedirectDrawNone)
121        return WT_DONTWALKCHILDREN;
122    (*pScreen->SetWindowPixmap) (pWindow, pVisit->pPixmap);
123    /*
124     * Recompute winSize and borderSize.  This is duplicate effort
125     * when resizing pixmaps, but necessary when changing redirection.
126     * Might be nice to fix this.
127     */
128    SetWinSize(pWindow);
129    SetBorderSize(pWindow);
130    if (pVisit->bw)
131        QueueWorkProc(compRepaintBorder, serverClient,
132                      (void *) (intptr_t) pWindow->drawable.id);
133    return WT_WALKCHILDREN;
134}
135
136void
137compSetPixmap(WindowPtr pWindow, PixmapPtr pPixmap, int bw)
138{
139    CompPixmapVisitRec visitRec;
140
141    visitRec.pWindow = pWindow;
142    visitRec.pPixmap = pPixmap;
143    visitRec.bw = bw;
144    TraverseTree(pWindow, compSetPixmapVisitWindow, (void *) &visitRec);
145    compCheckTree(pWindow->drawable.pScreen);
146}
147
148Bool
149compCheckRedirect(WindowPtr pWin)
150{
151    CompWindowPtr cw = GetCompWindow(pWin);
152    CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen);
153    Bool should;
154
155    should = pWin->realized && (pWin->drawable.class != InputOnly) &&
156        (cw != NULL) && (pWin->parent != NULL);
157
158    /* Never redirect the overlay window */
159    if (cs->pOverlayWin != NULL) {
160        if (pWin == cs->pOverlayWin) {
161            should = FALSE;
162        }
163    }
164
165    if (should != (pWin->redirectDraw != RedirectDrawNone)) {
166        if (should)
167            return compAllocPixmap(pWin);
168        else {
169            ScreenPtr pScreen = pWin->drawable.pScreen;
170            PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
171
172            compSetParentPixmap(pWin);
173            compRestoreWindow(pWin, pPixmap);
174            (*pScreen->DestroyPixmap) (pPixmap);
175        }
176    }
177    else if (should) {
178        if (cw->update == CompositeRedirectAutomatic)
179            pWin->redirectDraw = RedirectDrawAutomatic;
180        else
181            pWin->redirectDraw = RedirectDrawManual;
182    }
183    return TRUE;
184}
185
186static int
187updateOverlayWindow(ScreenPtr pScreen)
188{
189    CompScreenPtr cs;
190    WindowPtr pWin;             /* overlay window */
191    XID vlist[2];
192    int w = pScreen->width;
193    int h = pScreen->height;
194
195#ifdef PANORAMIX
196    if (!noPanoramiXExtension) {
197        w = PanoramiXPixWidth;
198        h = PanoramiXPixHeight;
199    }
200#endif
201
202    cs = GetCompScreen(pScreen);
203    if ((pWin = cs->pOverlayWin) != NULL) {
204        if ((pWin->drawable.width == w) && (pWin->drawable.height == h))
205            return Success;
206
207        /* Let's resize the overlay window. */
208        vlist[0] = w;
209        vlist[1] = h;
210        return ConfigureWindow(pWin, CWWidth | CWHeight, vlist, wClient(pWin));
211    }
212
213    /* Let's be on the safe side and not assume an overlay window is
214       always allocated. */
215    return Success;
216}
217
218Bool
219compPositionWindow(WindowPtr pWin, int x, int y)
220{
221    ScreenPtr pScreen = pWin->drawable.pScreen;
222    CompScreenPtr cs = GetCompScreen(pScreen);
223    Bool ret = TRUE;
224
225    pScreen->PositionWindow = cs->PositionWindow;
226    /*
227     * "Shouldn't need this as all possible places should be wrapped
228     *
229     compCheckRedirect (pWin);
230     */
231#ifdef COMPOSITE_DEBUG
232    if ((pWin->redirectDraw != RedirectDrawNone) !=
233        (pWin->viewable && (GetCompWindow(pWin) != NULL)))
234        OsAbort();
235#endif
236    if (pWin->redirectDraw != RedirectDrawNone) {
237        PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
238        int bw = wBorderWidth(pWin);
239        int nx = pWin->drawable.x - bw;
240        int ny = pWin->drawable.y - bw;
241
242        if (pPixmap->screen_x != nx || pPixmap->screen_y != ny) {
243            pPixmap->screen_x = nx;
244            pPixmap->screen_y = ny;
245            pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
246        }
247    }
248
249    if (!(*pScreen->PositionWindow) (pWin, x, y))
250        ret = FALSE;
251    cs->PositionWindow = pScreen->PositionWindow;
252    pScreen->PositionWindow = compPositionWindow;
253    compCheckTree(pWin->drawable.pScreen);
254    if (updateOverlayWindow(pScreen) != Success)
255        ret = FALSE;
256    return ret;
257}
258
259Bool
260compRealizeWindow(WindowPtr pWin)
261{
262    ScreenPtr pScreen = pWin->drawable.pScreen;
263    CompScreenPtr cs = GetCompScreen(pScreen);
264    Bool ret = TRUE;
265
266    pScreen->RealizeWindow = cs->RealizeWindow;
267    compCheckRedirect(pWin);
268    if (!(*pScreen->RealizeWindow) (pWin))
269        ret = FALSE;
270    cs->RealizeWindow = pScreen->RealizeWindow;
271    pScreen->RealizeWindow = compRealizeWindow;
272    compCheckTree(pWin->drawable.pScreen);
273    return ret;
274}
275
276Bool
277compUnrealizeWindow(WindowPtr pWin)
278{
279    ScreenPtr pScreen = pWin->drawable.pScreen;
280    CompScreenPtr cs = GetCompScreen(pScreen);
281    Bool ret = TRUE;
282
283    pScreen->UnrealizeWindow = cs->UnrealizeWindow;
284    compCheckRedirect(pWin);
285    if (!(*pScreen->UnrealizeWindow) (pWin))
286        ret = FALSE;
287    cs->UnrealizeWindow = pScreen->UnrealizeWindow;
288    pScreen->UnrealizeWindow = compUnrealizeWindow;
289    compCheckTree(pWin->drawable.pScreen);
290    return ret;
291}
292
293/*
294 * Called after the borderClip for the window has settled down
295 * We use this to make sure our extra borderClip has the right origin
296 */
297
298void
299compClipNotify(WindowPtr pWin, int dx, int dy)
300{
301    ScreenPtr pScreen = pWin->drawable.pScreen;
302    CompScreenPtr cs = GetCompScreen(pScreen);
303    CompWindowPtr cw = GetCompWindow(pWin);
304
305    if (cw) {
306        if (cw->borderClipX != pWin->drawable.x ||
307            cw->borderClipY != pWin->drawable.y) {
308            RegionTranslate(&cw->borderClip,
309                            pWin->drawable.x - cw->borderClipX,
310                            pWin->drawable.y - cw->borderClipY);
311            cw->borderClipX = pWin->drawable.x;
312            cw->borderClipY = pWin->drawable.y;
313        }
314    }
315    if (cs->ClipNotify) {
316        pScreen->ClipNotify = cs->ClipNotify;
317        (*pScreen->ClipNotify) (pWin, dx, dy);
318        cs->ClipNotify = pScreen->ClipNotify;
319        pScreen->ClipNotify = compClipNotify;
320    }
321}
322
323Bool
324compIsAlternateVisual(ScreenPtr pScreen, XID visual)
325{
326    CompScreenPtr cs = GetCompScreen(pScreen);
327    int i;
328
329    for (i = 0; cs && i < cs->numAlternateVisuals; i++)
330        if (cs->alternateVisuals[i] == visual)
331            return TRUE;
332    return FALSE;
333}
334
335static Bool
336compIsImplicitRedirectException(ScreenPtr pScreen,
337                                XID parentVisual, XID winVisual)
338{
339    CompScreenPtr cs = GetCompScreen(pScreen);
340    int i;
341
342    for (i = 0; i < cs->numImplicitRedirectExceptions; i++)
343        if (cs->implicitRedirectExceptions[i].parentVisual == parentVisual &&
344            cs->implicitRedirectExceptions[i].winVisual == winVisual)
345            return TRUE;
346
347    return FALSE;
348}
349
350static Bool
351compImplicitRedirect(WindowPtr pWin, WindowPtr pParent)
352{
353    if (pParent) {
354        ScreenPtr pScreen = pWin->drawable.pScreen;
355        XID winVisual = wVisual(pWin);
356        XID parentVisual = wVisual(pParent);
357
358        if (compIsImplicitRedirectException(pScreen, parentVisual, winVisual))
359            return FALSE;
360
361        if (winVisual != parentVisual &&
362            (compIsAlternateVisual(pScreen, winVisual) ||
363             compIsAlternateVisual(pScreen, parentVisual)))
364            return TRUE;
365    }
366    return FALSE;
367}
368
369static void
370compFreeOldPixmap(WindowPtr pWin)
371{
372    ScreenPtr pScreen = pWin->drawable.pScreen;
373
374    if (pWin->redirectDraw != RedirectDrawNone) {
375        CompWindowPtr cw = GetCompWindow(pWin);
376
377        if (cw->pOldPixmap) {
378            (*pScreen->DestroyPixmap) (cw->pOldPixmap);
379            cw->pOldPixmap = NullPixmap;
380        }
381    }
382}
383
384void
385compMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
386{
387    ScreenPtr pScreen = pWin->drawable.pScreen;
388    CompScreenPtr cs = GetCompScreen(pScreen);
389
390    pScreen->MoveWindow = cs->MoveWindow;
391    (*pScreen->MoveWindow) (pWin, x, y, pSib, kind);
392    cs->MoveWindow = pScreen->MoveWindow;
393    pScreen->MoveWindow = compMoveWindow;
394
395    compFreeOldPixmap(pWin);
396    compCheckTree(pScreen);
397}
398
399void
400compResizeWindow(WindowPtr pWin, int x, int y,
401                 unsigned int w, unsigned int h, WindowPtr pSib)
402{
403    ScreenPtr pScreen = pWin->drawable.pScreen;
404    CompScreenPtr cs = GetCompScreen(pScreen);
405
406    pScreen->ResizeWindow = cs->ResizeWindow;
407    (*pScreen->ResizeWindow) (pWin, x, y, w, h, pSib);
408    cs->ResizeWindow = pScreen->ResizeWindow;
409    pScreen->ResizeWindow = compResizeWindow;
410
411    compFreeOldPixmap(pWin);
412    compCheckTree(pWin->drawable.pScreen);
413}
414
415void
416compChangeBorderWidth(WindowPtr pWin, unsigned int bw)
417{
418    ScreenPtr pScreen = pWin->drawable.pScreen;
419    CompScreenPtr cs = GetCompScreen(pScreen);
420
421    pScreen->ChangeBorderWidth = cs->ChangeBorderWidth;
422    (*pScreen->ChangeBorderWidth) (pWin, bw);
423    cs->ChangeBorderWidth = pScreen->ChangeBorderWidth;
424    pScreen->ChangeBorderWidth = compChangeBorderWidth;
425
426    compFreeOldPixmap(pWin);
427    compCheckTree(pWin->drawable.pScreen);
428}
429
430void
431compReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
432{
433    ScreenPtr pScreen = pWin->drawable.pScreen;
434    CompScreenPtr cs = GetCompScreen(pScreen);
435    CompWindowPtr cw;
436
437    pScreen->ReparentWindow = cs->ReparentWindow;
438    /*
439     * Remove any implicit redirect due to synthesized visual
440     */
441    if (compImplicitRedirect(pWin, pPriorParent))
442        compUnredirectWindow(serverClient, pWin, CompositeRedirectAutomatic);
443    /*
444     * Handle subwindows redirection
445     */
446    compUnredirectOneSubwindow(pPriorParent, pWin);
447    compRedirectOneSubwindow(pWin->parent, pWin);
448    /*
449     * Add any implict redirect due to synthesized visual
450     */
451    if (compImplicitRedirect(pWin, pWin->parent))
452        compRedirectWindow(serverClient, pWin, CompositeRedirectAutomatic);
453
454    /*
455     * Allocate any necessary redirect pixmap
456     * (this actually should never be true; pWin is always unmapped)
457     */
458    compCheckRedirect(pWin);
459
460    /*
461     * Reset pixmap pointers as appropriate
462     */
463    if (pWin->parent && pWin->redirectDraw == RedirectDrawNone)
464        compSetPixmap(pWin, (*pScreen->GetWindowPixmap) (pWin->parent),
465                      pWin->borderWidth);
466    /*
467     * Call down to next function
468     */
469    if (pScreen->ReparentWindow)
470        (*pScreen->ReparentWindow) (pWin, pPriorParent);
471    cs->ReparentWindow = pScreen->ReparentWindow;
472    pScreen->ReparentWindow = compReparentWindow;
473
474    cw = GetCompWindow(pWin);
475    if (pWin->damagedDescendants || (cw && cw->damaged))
476        compMarkAncestors(pWin);
477
478    compCheckTree(pWin->drawable.pScreen);
479}
480
481void
482compCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
483{
484    ScreenPtr pScreen = pWin->drawable.pScreen;
485    CompScreenPtr cs = GetCompScreen(pScreen);
486    int dx = 0, dy = 0;
487
488    if (pWin->redirectDraw != RedirectDrawNone) {
489        PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
490        CompWindowPtr cw = GetCompWindow(pWin);
491
492        assert(cw->oldx != COMP_ORIGIN_INVALID);
493        assert(cw->oldy != COMP_ORIGIN_INVALID);
494        if (cw->pOldPixmap) {
495            /*
496             * Ok, the old bits are available in pOldPixmap and
497             * need to be copied to pNewPixmap.
498             */
499            RegionRec rgnDst;
500            GCPtr pGC;
501
502            dx = ptOldOrg.x - pWin->drawable.x;
503            dy = ptOldOrg.y - pWin->drawable.y;
504            RegionTranslate(prgnSrc, -dx, -dy);
505
506            RegionNull(&rgnDst);
507
508            RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
509
510            RegionTranslate(&rgnDst, -pPixmap->screen_x, -pPixmap->screen_y);
511
512            dx = dx + pPixmap->screen_x - cw->oldx;
513            dy = dy + pPixmap->screen_y - cw->oldy;
514            pGC = GetScratchGC(pPixmap->drawable.depth, pScreen);
515            if (pGC) {
516                BoxPtr pBox = RegionRects(&rgnDst);
517                int nBox = RegionNumRects(&rgnDst);
518
519                ValidateGC(&pPixmap->drawable, pGC);
520                while (nBox--) {
521                    (void) (*pGC->ops->CopyArea) (&cw->pOldPixmap->drawable,
522                                                  &pPixmap->drawable,
523                                                  pGC,
524                                                  pBox->x1 + dx, pBox->y1 + dy,
525                                                  pBox->x2 - pBox->x1,
526                                                  pBox->y2 - pBox->y1,
527                                                  pBox->x1, pBox->y1);
528                    pBox++;
529                }
530                FreeScratchGC(pGC);
531            }
532            RegionUninit(&rgnDst);
533            return;
534        }
535        dx = pPixmap->screen_x - cw->oldx;
536        dy = pPixmap->screen_y - cw->oldy;
537        ptOldOrg.x += dx;
538        ptOldOrg.y += dy;
539    }
540
541    pScreen->CopyWindow = cs->CopyWindow;
542    if (ptOldOrg.x != pWin->drawable.x || ptOldOrg.y != pWin->drawable.y) {
543        if (dx || dy)
544            RegionTranslate(prgnSrc, dx, dy);
545        (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc);
546        if (dx || dy)
547            RegionTranslate(prgnSrc, -dx, -dy);
548    }
549    else {
550        ptOldOrg.x -= dx;
551        ptOldOrg.y -= dy;
552        RegionTranslate(prgnSrc,
553                        pWin->drawable.x - ptOldOrg.x,
554                        pWin->drawable.y - ptOldOrg.y);
555        DamageDamageRegion(&pWin->drawable, prgnSrc);
556    }
557    cs->CopyWindow = pScreen->CopyWindow;
558    pScreen->CopyWindow = compCopyWindow;
559    compCheckTree(pWin->drawable.pScreen);
560}
561
562Bool
563compCreateWindow(WindowPtr pWin)
564{
565    ScreenPtr pScreen = pWin->drawable.pScreen;
566    CompScreenPtr cs = GetCompScreen(pScreen);
567    Bool ret;
568
569    pScreen->CreateWindow = cs->CreateWindow;
570    ret = (*pScreen->CreateWindow) (pWin);
571    if (pWin->parent && ret) {
572        CompSubwindowsPtr csw = GetCompSubwindows(pWin->parent);
573        CompClientWindowPtr ccw;
574        PixmapPtr parent_pixmap = (*pScreen->GetWindowPixmap)(pWin->parent);
575        PixmapPtr window_pixmap = (*pScreen->GetWindowPixmap)(pWin);
576
577        if (window_pixmap != parent_pixmap)
578            (*pScreen->SetWindowPixmap) (pWin, parent_pixmap);
579        if (csw)
580            for (ccw = csw->clients; ccw; ccw = ccw->next)
581                compRedirectWindow(clients[CLIENT_ID(ccw->id)],
582                                   pWin, ccw->update);
583        if (compImplicitRedirect(pWin, pWin->parent))
584            compRedirectWindow(serverClient, pWin, CompositeRedirectAutomatic);
585    }
586    cs->CreateWindow = pScreen->CreateWindow;
587    pScreen->CreateWindow = compCreateWindow;
588    compCheckTree(pWin->drawable.pScreen);
589    return ret;
590}
591
592Bool
593compDestroyWindow(WindowPtr pWin)
594{
595    ScreenPtr pScreen = pWin->drawable.pScreen;
596    CompScreenPtr cs = GetCompScreen(pScreen);
597    CompWindowPtr cw;
598    CompSubwindowsPtr csw;
599    Bool ret;
600
601    pScreen->DestroyWindow = cs->DestroyWindow;
602    while ((cw = GetCompWindow(pWin)))
603        FreeResource(cw->clients->id, RT_NONE);
604    while ((csw = GetCompSubwindows(pWin)))
605        FreeResource(csw->clients->id, RT_NONE);
606
607    if (pWin->redirectDraw != RedirectDrawNone) {
608        PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
609
610        compSetParentPixmap(pWin);
611        (*pScreen->DestroyPixmap) (pPixmap);
612    }
613    ret = (*pScreen->DestroyWindow) (pWin);
614    cs->DestroyWindow = pScreen->DestroyWindow;
615    pScreen->DestroyWindow = compDestroyWindow;
616/*    compCheckTree (pWin->drawable.pScreen); can't check -- tree isn't good*/
617    return ret;
618}
619
620void
621compSetRedirectBorderClip(WindowPtr pWin, RegionPtr pRegion)
622{
623    CompWindowPtr cw = GetCompWindow(pWin);
624    RegionRec damage;
625
626    RegionNull(&damage);
627    /*
628     * Align old border clip with new border clip
629     */
630    RegionTranslate(&cw->borderClip,
631                    pWin->drawable.x - cw->borderClipX,
632                    pWin->drawable.y - cw->borderClipY);
633    /*
634     * Compute newly visible portion of window for repaint
635     */
636    RegionSubtract(&damage, pRegion, &cw->borderClip);
637    /*
638     * Report that as damaged so it will be redrawn
639     */
640    DamageDamageRegion(&pWin->drawable, &damage);
641    RegionUninit(&damage);
642    /*
643     * Save the new border clip region
644     */
645    RegionCopy(&cw->borderClip, pRegion);
646    cw->borderClipX = pWin->drawable.x;
647    cw->borderClipY = pWin->drawable.y;
648}
649
650RegionPtr
651compGetRedirectBorderClip(WindowPtr pWin)
652{
653    CompWindowPtr cw = GetCompWindow(pWin);
654
655    return &cw->borderClip;
656}
657
658static void
659compWindowUpdateAutomatic(WindowPtr pWin)
660{
661    CompWindowPtr cw = GetCompWindow(pWin);
662    ScreenPtr pScreen = pWin->drawable.pScreen;
663    WindowPtr pParent = pWin->parent;
664    PixmapPtr pSrcPixmap = (*pScreen->GetWindowPixmap) (pWin);
665    PictFormatPtr pSrcFormat = PictureWindowFormat(pWin);
666    PictFormatPtr pDstFormat = PictureWindowFormat(pWin->parent);
667    int error;
668    RegionPtr pRegion = DamageRegion(cw->damage);
669    PicturePtr pSrcPicture = CreatePicture(0, &pSrcPixmap->drawable,
670                                           pSrcFormat,
671                                           0, 0,
672                                           serverClient,
673                                           &error);
674    XID subwindowMode = IncludeInferiors;
675    PicturePtr pDstPicture = CreatePicture(0, &pParent->drawable,
676                                           pDstFormat,
677                                           CPSubwindowMode,
678                                           &subwindowMode,
679                                           serverClient,
680                                           &error);
681
682    /*
683     * First move the region from window to screen coordinates
684     */
685    RegionTranslate(pRegion, pWin->drawable.x, pWin->drawable.y);
686
687    /*
688     * Clip against the "real" border clip
689     */
690    RegionIntersect(pRegion, pRegion, &cw->borderClip);
691
692    /*
693     * Now translate from screen to dest coordinates
694     */
695    RegionTranslate(pRegion, -pParent->drawable.x, -pParent->drawable.y);
696
697    /*
698     * Clip the picture
699     */
700    SetPictureClipRegion(pDstPicture, 0, 0, pRegion);
701
702    /*
703     * And paint
704     */
705    CompositePicture(PictOpSrc, pSrcPicture, 0, pDstPicture,
706                     0, 0,      /* src_x, src_y */
707                     0, 0,      /* msk_x, msk_y */
708                     pSrcPixmap->screen_x - pParent->drawable.x,
709                     pSrcPixmap->screen_y - pParent->drawable.y,
710                     pSrcPixmap->drawable.width, pSrcPixmap->drawable.height);
711    FreePicture(pSrcPicture, 0);
712    FreePicture(pDstPicture, 0);
713    /*
714     * Empty the damage region.  This has the nice effect of
715     * rendering the translations above harmless
716     */
717    DamageEmpty(cw->damage);
718}
719
720static void
721compPaintWindowToParent(WindowPtr pWin)
722{
723    compPaintChildrenToWindow(pWin);
724
725    if (pWin->redirectDraw != RedirectDrawNone) {
726        CompWindowPtr cw = GetCompWindow(pWin);
727
728        if (cw->damaged) {
729            compWindowUpdateAutomatic(pWin);
730            cw->damaged = FALSE;
731        }
732    }
733}
734
735void
736compPaintChildrenToWindow(WindowPtr pWin)
737{
738    WindowPtr pChild;
739
740    if (!pWin->damagedDescendants)
741        return;
742
743    for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
744        compPaintWindowToParent(pChild);
745
746    pWin->damagedDescendants = FALSE;
747}
748
749WindowPtr
750CompositeRealChildHead(WindowPtr pWin)
751{
752    WindowPtr pChild, pChildBefore;
753    CompScreenPtr cs;
754
755    if (!pWin->parent &&
756        (screenIsSaved == SCREEN_SAVER_ON) &&
757        (HasSaverWindow(pWin->drawable.pScreen))) {
758
759        /* First child is the screen saver; see if next child is the overlay */
760        pChildBefore = pWin->firstChild;
761        pChild = pChildBefore->nextSib;
762
763    }
764    else {
765        pChildBefore = NullWindow;
766        pChild = pWin->firstChild;
767    }
768
769    if (!pChild) {
770        return NullWindow;
771    }
772
773    cs = GetCompScreen(pWin->drawable.pScreen);
774    if (pChild == cs->pOverlayWin) {
775        return pChild;
776    }
777    else {
778        return pChildBefore;
779    }
780}
781
782int
783compConfigNotify(WindowPtr pWin, int x, int y, int w, int h,
784                 int bw, WindowPtr pSib)
785{
786    ScreenPtr pScreen = pWin->drawable.pScreen;
787    CompScreenPtr cs = GetCompScreen(pScreen);
788    Bool ret = 0;
789    WindowPtr pParent = pWin->parent;
790    int draw_x, draw_y;
791    Bool alloc_ret;
792
793    if (cs->ConfigNotify) {
794        pScreen->ConfigNotify = cs->ConfigNotify;
795        ret = (*pScreen->ConfigNotify) (pWin, x, y, w, h, bw, pSib);
796        cs->ConfigNotify = pScreen->ConfigNotify;
797        pScreen->ConfigNotify = compConfigNotify;
798
799        if (ret)
800            return ret;
801    }
802
803    if (pWin->redirectDraw == RedirectDrawNone)
804        return Success;
805
806    compCheckTree(pScreen);
807
808    draw_x = pParent->drawable.x + x + bw;
809    draw_y = pParent->drawable.y + y + bw;
810    alloc_ret = compReallocPixmap(pWin, draw_x, draw_y, w, h, bw);
811
812    if (alloc_ret == FALSE)
813        return BadAlloc;
814    return Success;
815}
816