105b261ecSmrg/*
29ace9065Smrg * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
305b261ecSmrg *
46747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a
56747b715Smrg * copy of this software and associated documentation files (the "Software"),
66747b715Smrg * to deal in the Software without restriction, including without limitation
76747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
86747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
96747b715Smrg * Software is furnished to do so, subject to the following conditions:
1005b261ecSmrg *
116747b715Smrg * The above copyright notice and this permission notice (including the next
126747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
136747b715Smrg * Software.
146747b715Smrg *
156747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
186747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
206747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
216747b715Smrg * DEALINGS IN THE SOFTWARE.
2205b261ecSmrg *
2305b261ecSmrg * Copyright © 2003 Keith Packard
2405b261ecSmrg *
2505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
2605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
2705b261ecSmrg * the above copyright notice appear in all copies and that both that
2805b261ecSmrg * copyright notice and this permission notice appear in supporting
2905b261ecSmrg * documentation, and that the name of Keith Packard not be used in
3005b261ecSmrg * advertising or publicity pertaining to distribution of the software without
3105b261ecSmrg * specific, written prior permission.  Keith Packard makes no
3205b261ecSmrg * representations about the suitability of this software for any purpose.  It
3305b261ecSmrg * is provided "as is" without express or implied warranty.
3405b261ecSmrg *
3505b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
3605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
3705b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
3805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
3905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
4005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
4105b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
4205b261ecSmrg */
4305b261ecSmrg
4405b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
4505b261ecSmrg#include <dix-config.h>
4605b261ecSmrg#endif
4705b261ecSmrg
4805b261ecSmrg#include "compint.h"
4905b261ecSmrg
501b5d61b8Smrgstatic Bool
511b5d61b8SmrgcompScreenUpdate(ClientPtr pClient, void *closure)
529ace9065Smrg{
531b5d61b8Smrg    ScreenPtr pScreen = closure;
541b5d61b8Smrg    CompScreenPtr cs = GetCompScreen(pScreen);
551b5d61b8Smrg
5635c4bbdfSmrg    compCheckTree(pScreen);
5735c4bbdfSmrg    compPaintChildrenToWindow(pScreen->root);
581b5d61b8Smrg
591b5d61b8Smrg    /* Next damage will restore the worker */
601b5d61b8Smrg    cs->pendingScreenUpdate = FALSE;
611b5d61b8Smrg    return TRUE;
629ace9065Smrg}
639ace9065Smrg
641b5d61b8Smrgvoid
651b5d61b8SmrgcompMarkAncestors(WindowPtr pWin)
669ace9065Smrg{
671b5d61b8Smrg    pWin = pWin->parent;
681b5d61b8Smrg    while (pWin) {
691b5d61b8Smrg        if (pWin->damagedDescendants)
701b5d61b8Smrg            return;
711b5d61b8Smrg        pWin->damagedDescendants = TRUE;
721b5d61b8Smrg        pWin = pWin->parent;
731b5d61b8Smrg    }
749ace9065Smrg}
759ace9065Smrg
7605b261ecSmrgstatic void
7735c4bbdfSmrgcompReportDamage(DamagePtr pDamage, RegionPtr pRegion, void *closure)
7805b261ecSmrg{
7935c4bbdfSmrg    WindowPtr pWin = (WindowPtr) closure;
8035c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
8135c4bbdfSmrg    CompScreenPtr cs = GetCompScreen(pScreen);
8235c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
8305b261ecSmrg
841b5d61b8Smrg    if (!cs->pendingScreenUpdate) {
851b5d61b8Smrg        QueueWorkProc(compScreenUpdate, serverClient, pScreen);
861b5d61b8Smrg        cs->pendingScreenUpdate = TRUE;
879ace9065Smrg    }
8805b261ecSmrg    cw->damaged = TRUE;
899ace9065Smrg
901b5d61b8Smrg    compMarkAncestors(pWin);
9105b261ecSmrg}
9205b261ecSmrg
9305b261ecSmrgstatic void
9435c4bbdfSmrgcompDestroyDamage(DamagePtr pDamage, void *closure)
9505b261ecSmrg{
9635c4bbdfSmrg    WindowPtr pWin = (WindowPtr) closure;
9735c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
9805b261ecSmrg
9905b261ecSmrg    cw->damage = 0;
100ed6184dfSmrg    cw->damaged = 0;
101ed6184dfSmrg    cw->damageRegistered = 0;
10205b261ecSmrg}
10305b261ecSmrg
10435c4bbdfSmrgstatic Bool
10535c4bbdfSmrgcompMarkWindows(WindowPtr pWin, WindowPtr *ppLayerWin)
10635c4bbdfSmrg{
10735c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
10835c4bbdfSmrg    WindowPtr pLayerWin = pWin;
10935c4bbdfSmrg
11035c4bbdfSmrg    if (!pWin->viewable)
11135c4bbdfSmrg        return FALSE;
11235c4bbdfSmrg
11335c4bbdfSmrg    (*pScreen->MarkOverlappedWindows) (pWin, pWin, &pLayerWin);
11435c4bbdfSmrg    (*pScreen->MarkWindow) (pLayerWin->parent);
11535c4bbdfSmrg
11635c4bbdfSmrg    *ppLayerWin = pLayerWin;
11735c4bbdfSmrg
11835c4bbdfSmrg    return TRUE;
11935c4bbdfSmrg}
12035c4bbdfSmrg
12135c4bbdfSmrgstatic void
12235c4bbdfSmrgcompHandleMarkedWindows(WindowPtr pWin, WindowPtr pLayerWin)
12335c4bbdfSmrg{
12435c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
12535c4bbdfSmrg
12635c4bbdfSmrg    (*pScreen->ValidateTree) (pLayerWin->parent, pLayerWin, VTOther);
12735c4bbdfSmrg    (*pScreen->HandleExposures) (pLayerWin->parent);
12835c4bbdfSmrg    if (pScreen->PostValidateTree)
12935c4bbdfSmrg        (*pScreen->PostValidateTree) (pLayerWin->parent, pLayerWin, VTOther);
13035c4bbdfSmrg}
13135c4bbdfSmrg
13205b261ecSmrg/*
13305b261ecSmrg * Redirect one window for one client
13405b261ecSmrg */
13505b261ecSmrgint
13635c4bbdfSmrgcompRedirectWindow(ClientPtr pClient, WindowPtr pWin, int update)
13705b261ecSmrg{
13835c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
13935c4bbdfSmrg    CompClientWindowPtr ccw;
14035c4bbdfSmrg    CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen);
14135c4bbdfSmrg    WindowPtr pLayerWin;
14235c4bbdfSmrg    Bool anyMarked = FALSE;
143f2346221Smrg    int status = Success;
14435c4bbdfSmrg
14505b261ecSmrg    if (pWin == cs->pOverlayWin) {
14635c4bbdfSmrg        return Success;
14705b261ecSmrg    }
14805b261ecSmrg
1494642e01fSmrg    if (!pWin->parent)
15035c4bbdfSmrg        return BadMatch;
1514642e01fSmrg
15205b261ecSmrg    /*
15305b261ecSmrg     * Only one Manual update is allowed
15405b261ecSmrg     */
15505b261ecSmrg    if (cw && update == CompositeRedirectManual)
15635c4bbdfSmrg        for (ccw = cw->clients; ccw; ccw = ccw->next)
15735c4bbdfSmrg            if (ccw->update == CompositeRedirectManual)
15835c4bbdfSmrg                return BadAccess;
15935c4bbdfSmrg
16005b261ecSmrg    /*
16135c4bbdfSmrg     * Allocate per-client per-window structure
16205b261ecSmrg     * The client *could* allocate multiple, but while supported,
16305b261ecSmrg     * it is not expected to be common
16405b261ecSmrg     */
16535c4bbdfSmrg    ccw = malloc(sizeof(CompClientWindowRec));
16605b261ecSmrg    if (!ccw)
16735c4bbdfSmrg        return BadAlloc;
16835c4bbdfSmrg    ccw->id = FakeClientID(pClient->index);
16905b261ecSmrg    ccw->update = update;
17005b261ecSmrg    /*
17105b261ecSmrg     * Now make sure there's a per-window structure to hang this from
17205b261ecSmrg     */
17335c4bbdfSmrg    if (!cw) {
17435c4bbdfSmrg        cw = malloc(sizeof(CompWindowRec));
17535c4bbdfSmrg        if (!cw) {
17635c4bbdfSmrg            free(ccw);
17735c4bbdfSmrg            return BadAlloc;
17835c4bbdfSmrg        }
17935c4bbdfSmrg        cw->damage = DamageCreate(compReportDamage,
18035c4bbdfSmrg                                  compDestroyDamage,
18135c4bbdfSmrg                                  DamageReportNonEmpty,
18235c4bbdfSmrg                                  FALSE, pWin->drawable.pScreen, pWin);
18335c4bbdfSmrg        if (!cw->damage) {
18435c4bbdfSmrg            free(ccw);
18535c4bbdfSmrg            free(cw);
18635c4bbdfSmrg            return BadAlloc;
18735c4bbdfSmrg        }
18835c4bbdfSmrg
18935c4bbdfSmrg        anyMarked = compMarkWindows(pWin, &pLayerWin);
19035c4bbdfSmrg
19135c4bbdfSmrg        RegionNull(&cw->borderClip);
19235c4bbdfSmrg        cw->update = CompositeRedirectAutomatic;
19335c4bbdfSmrg        cw->clients = 0;
19435c4bbdfSmrg        cw->oldx = COMP_ORIGIN_INVALID;
19535c4bbdfSmrg        cw->oldy = COMP_ORIGIN_INVALID;
19635c4bbdfSmrg        cw->damageRegistered = FALSE;
19735c4bbdfSmrg        cw->damaged = FALSE;
19835c4bbdfSmrg        cw->pOldPixmap = NullPixmap;
19935c4bbdfSmrg        dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw);
20005b261ecSmrg    }
20105b261ecSmrg    ccw->next = cw->clients;
20205b261ecSmrg    cw->clients = ccw;
20335c4bbdfSmrg    if (!AddResource(ccw->id, CompositeClientWindowType, pWin))
20435c4bbdfSmrg        return BadAlloc;
20535c4bbdfSmrg    if (ccw->update == CompositeRedirectManual) {
20635c4bbdfSmrg        if (!anyMarked)
20735c4bbdfSmrg            anyMarked = compMarkWindows(pWin, &pLayerWin);
20835c4bbdfSmrg
20935c4bbdfSmrg        if (cw->damageRegistered) {
21035c4bbdfSmrg            DamageUnregister(cw->damage);
21135c4bbdfSmrg            cw->damageRegistered = FALSE;
21235c4bbdfSmrg        }
21335c4bbdfSmrg        cw->update = CompositeRedirectManual;
21405b261ecSmrg    }
21535c4bbdfSmrg    else if (cw->update == CompositeRedirectAutomatic && !cw->damageRegistered) {
21635c4bbdfSmrg        if (!anyMarked)
21735c4bbdfSmrg            anyMarked = compMarkWindows(pWin, &pLayerWin);
21805b261ecSmrg    }
21935c4bbdfSmrg
22035c4bbdfSmrg    if (!compCheckRedirect(pWin)) {
22135c4bbdfSmrg        FreeResource(ccw->id, RT_NONE);
222f2346221Smrg        status = BadAlloc;
22305b261ecSmrg    }
22435c4bbdfSmrg
22535c4bbdfSmrg    if (anyMarked)
22635c4bbdfSmrg        compHandleMarkedWindows(pWin, pLayerWin);
22735c4bbdfSmrg
228f2346221Smrg    return status;
22905b261ecSmrg}
23005b261ecSmrg
23135c4bbdfSmrgvoid
23235c4bbdfSmrgcompRestoreWindow(WindowPtr pWin, PixmapPtr pPixmap)
23335c4bbdfSmrg{
23435c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
23535c4bbdfSmrg    WindowPtr pParent = pWin->parent;
23635c4bbdfSmrg
23735c4bbdfSmrg    if (pParent->drawable.depth == pWin->drawable.depth) {
23835c4bbdfSmrg        GCPtr pGC = GetScratchGC(pWin->drawable.depth, pScreen);
23935c4bbdfSmrg        int bw = (int) pWin->borderWidth;
24035c4bbdfSmrg        int x = bw;
24135c4bbdfSmrg        int y = bw;
24235c4bbdfSmrg        int w = pWin->drawable.width;
24335c4bbdfSmrg        int h = pWin->drawable.height;
24435c4bbdfSmrg
24535c4bbdfSmrg        if (pGC) {
24635c4bbdfSmrg            ChangeGCVal val;
24735c4bbdfSmrg
24835c4bbdfSmrg            val.val = IncludeInferiors;
24935c4bbdfSmrg            ChangeGC(NullClient, pGC, GCSubwindowMode, &val);
25035c4bbdfSmrg            ValidateGC(&pWin->drawable, pGC);
25135c4bbdfSmrg            (*pGC->ops->CopyArea) (&pPixmap->drawable,
25235c4bbdfSmrg                                   &pWin->drawable, pGC, x, y, w, h, 0, 0);
25335c4bbdfSmrg            FreeScratchGC(pGC);
25435c4bbdfSmrg        }
25535c4bbdfSmrg    }
25635c4bbdfSmrg}
25735c4bbdfSmrg
25805b261ecSmrg/*
25905b261ecSmrg * Free one of the per-client per-window resources, clearing
26005b261ecSmrg * redirect and the per-window pointer as appropriate
26105b261ecSmrg */
26205b261ecSmrgvoid
26335c4bbdfSmrgcompFreeClientWindow(WindowPtr pWin, XID id)
26405b261ecSmrg{
26535c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
26635c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
26735c4bbdfSmrg    CompClientWindowPtr ccw, *prev;
26835c4bbdfSmrg    Bool anyMarked = FALSE;
26935c4bbdfSmrg    WindowPtr pLayerWin;
27035c4bbdfSmrg    PixmapPtr pPixmap = NULL;
27105b261ecSmrg
27205b261ecSmrg    if (!cw)
27335c4bbdfSmrg        return;
27435c4bbdfSmrg    for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next) {
27535c4bbdfSmrg        if (ccw->id == id) {
27635c4bbdfSmrg            *prev = ccw->next;
27735c4bbdfSmrg            if (ccw->update == CompositeRedirectManual)
27835c4bbdfSmrg                cw->update = CompositeRedirectAutomatic;
27935c4bbdfSmrg            free(ccw);
28035c4bbdfSmrg            break;
28135c4bbdfSmrg        }
28205b261ecSmrg    }
28335c4bbdfSmrg    if (!cw->clients) {
28435c4bbdfSmrg        anyMarked = compMarkWindows(pWin, &pLayerWin);
28535c4bbdfSmrg
28635c4bbdfSmrg        if (pWin->redirectDraw != RedirectDrawNone) {
28735c4bbdfSmrg            pPixmap = (*pScreen->GetWindowPixmap) (pWin);
28835c4bbdfSmrg            compSetParentPixmap(pWin);
28935c4bbdfSmrg        }
29035c4bbdfSmrg
29135c4bbdfSmrg        if (cw->damage)
29235c4bbdfSmrg            DamageDestroy(cw->damage);
29335c4bbdfSmrg
29435c4bbdfSmrg        RegionUninit(&cw->borderClip);
29535c4bbdfSmrg
29635c4bbdfSmrg        dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL);
29735c4bbdfSmrg        free(cw);
29805b261ecSmrg    }
29905b261ecSmrg    else if (cw->update == CompositeRedirectAutomatic &&
30035c4bbdfSmrg             !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone) {
30135c4bbdfSmrg        anyMarked = compMarkWindows(pWin, &pLayerWin);
30235c4bbdfSmrg
30335c4bbdfSmrg        DamageRegister(&pWin->drawable, cw->damage);
30435c4bbdfSmrg        cw->damageRegistered = TRUE;
30535c4bbdfSmrg        pWin->redirectDraw = RedirectDrawAutomatic;
30635c4bbdfSmrg        DamageDamageRegion(&pWin->drawable, &pWin->borderSize);
30705b261ecSmrg    }
30835c4bbdfSmrg
30935c4bbdfSmrg    if (anyMarked)
31035c4bbdfSmrg        compHandleMarkedWindows(pWin, pLayerWin);
31135c4bbdfSmrg
31235c4bbdfSmrg    if (pPixmap) {
31335c4bbdfSmrg        compRestoreWindow(pWin, pPixmap);
31435c4bbdfSmrg        (*pScreen->DestroyPixmap) (pPixmap);
31505b261ecSmrg    }
31605b261ecSmrg}
31705b261ecSmrg
31805b261ecSmrg/*
31905b261ecSmrg * This is easy, just free the appropriate resource.
32005b261ecSmrg */
32105b261ecSmrg
32205b261ecSmrgint
32335c4bbdfSmrgcompUnredirectWindow(ClientPtr pClient, WindowPtr pWin, int update)
32405b261ecSmrg{
32535c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
32635c4bbdfSmrg    CompClientWindowPtr ccw;
32705b261ecSmrg
32805b261ecSmrg    if (!cw)
32935c4bbdfSmrg        return BadValue;
33005b261ecSmrg
33105b261ecSmrg    for (ccw = cw->clients; ccw; ccw = ccw->next)
33235c4bbdfSmrg        if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) {
33335c4bbdfSmrg            FreeResource(ccw->id, RT_NONE);
33435c4bbdfSmrg            return Success;
33535c4bbdfSmrg        }
33605b261ecSmrg    return BadValue;
33705b261ecSmrg}
33835c4bbdfSmrg
33905b261ecSmrg/*
34005b261ecSmrg * Redirect all subwindows for one client
34105b261ecSmrg */
34205b261ecSmrg
34305b261ecSmrgint
34435c4bbdfSmrgcompRedirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update)
34505b261ecSmrg{
34635c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pWin);
34735c4bbdfSmrg    CompClientWindowPtr ccw;
34835c4bbdfSmrg    WindowPtr pChild;
34905b261ecSmrg
35005b261ecSmrg    /*
35105b261ecSmrg     * Only one Manual update is allowed
35205b261ecSmrg     */
35305b261ecSmrg    if (csw && update == CompositeRedirectManual)
35435c4bbdfSmrg        for (ccw = csw->clients; ccw; ccw = ccw->next)
35535c4bbdfSmrg            if (ccw->update == CompositeRedirectManual)
35635c4bbdfSmrg                return BadAccess;
35705b261ecSmrg    /*
35835c4bbdfSmrg     * Allocate per-client per-window structure
35905b261ecSmrg     * The client *could* allocate multiple, but while supported,
36005b261ecSmrg     * it is not expected to be common
36105b261ecSmrg     */
36235c4bbdfSmrg    ccw = malloc(sizeof(CompClientWindowRec));
36305b261ecSmrg    if (!ccw)
36435c4bbdfSmrg        return BadAlloc;
36535c4bbdfSmrg    ccw->id = FakeClientID(pClient->index);
36605b261ecSmrg    ccw->update = update;
36705b261ecSmrg    /*
36805b261ecSmrg     * Now make sure there's a per-window structure to hang this from
36905b261ecSmrg     */
37035c4bbdfSmrg    if (!csw) {
37135c4bbdfSmrg        csw = malloc(sizeof(CompSubwindowsRec));
37235c4bbdfSmrg        if (!csw) {
37335c4bbdfSmrg            free(ccw);
37435c4bbdfSmrg            return BadAlloc;
37535c4bbdfSmrg        }
37635c4bbdfSmrg        csw->update = CompositeRedirectAutomatic;
37735c4bbdfSmrg        csw->clients = 0;
37835c4bbdfSmrg        dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw);
37905b261ecSmrg    }
38005b261ecSmrg    /*
38105b261ecSmrg     * Redirect all existing windows
38205b261ecSmrg     */
38335c4bbdfSmrg    for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) {
38435c4bbdfSmrg        int ret = compRedirectWindow(pClient, pChild, update);
38535c4bbdfSmrg
38635c4bbdfSmrg        if (ret != Success) {
38735c4bbdfSmrg            for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib)
38835c4bbdfSmrg                (void) compUnredirectWindow(pClient, pChild, update);
38935c4bbdfSmrg            if (!csw->clients) {
39035c4bbdfSmrg                free(csw);
39135c4bbdfSmrg                dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0);
39235c4bbdfSmrg            }
39335c4bbdfSmrg            free(ccw);
39435c4bbdfSmrg            return ret;
39535c4bbdfSmrg        }
39605b261ecSmrg    }
39705b261ecSmrg    /*
39805b261ecSmrg     * Hook into subwindows list
39905b261ecSmrg     */
40005b261ecSmrg    ccw->next = csw->clients;
40105b261ecSmrg    csw->clients = ccw;
40235c4bbdfSmrg    if (!AddResource(ccw->id, CompositeClientSubwindowsType, pWin))
40335c4bbdfSmrg        return BadAlloc;
40435c4bbdfSmrg    if (ccw->update == CompositeRedirectManual) {
40535c4bbdfSmrg        csw->update = CompositeRedirectManual;
40635c4bbdfSmrg        /*
40735c4bbdfSmrg         * tell damage extension that damage events for this client are
40835c4bbdfSmrg         * critical output
40935c4bbdfSmrg         */
41035c4bbdfSmrg        DamageExtSetCritical(pClient, TRUE);
41135c4bbdfSmrg        pWin->inhibitBGPaint = TRUE;
41205b261ecSmrg    }
41305b261ecSmrg    return Success;
41405b261ecSmrg}
41505b261ecSmrg
41605b261ecSmrg/*
41705b261ecSmrg * Free one of the per-client per-subwindows resources,
41805b261ecSmrg * which frees one redirect per subwindow
41905b261ecSmrg */
42005b261ecSmrgvoid
42135c4bbdfSmrgcompFreeClientSubwindows(WindowPtr pWin, XID id)
42205b261ecSmrg{
42335c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pWin);
42435c4bbdfSmrg    CompClientWindowPtr ccw, *prev;
42535c4bbdfSmrg    WindowPtr pChild;
42605b261ecSmrg
42705b261ecSmrg    if (!csw)
42835c4bbdfSmrg        return;
42935c4bbdfSmrg    for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next) {
43035c4bbdfSmrg        if (ccw->id == id) {
43135c4bbdfSmrg            ClientPtr pClient = clients[CLIENT_ID(id)];
43235c4bbdfSmrg
43335c4bbdfSmrg            *prev = ccw->next;
43435c4bbdfSmrg            if (ccw->update == CompositeRedirectManual) {
43535c4bbdfSmrg                /*
43635c4bbdfSmrg                 * tell damage extension that damage events for this client are
43735c4bbdfSmrg                 * critical output
43835c4bbdfSmrg                 */
43935c4bbdfSmrg                DamageExtSetCritical(pClient, FALSE);
44035c4bbdfSmrg                csw->update = CompositeRedirectAutomatic;
44135c4bbdfSmrg                pWin->inhibitBGPaint = FALSE;
44235c4bbdfSmrg                if (pWin->mapped)
44335c4bbdfSmrg                    (*pWin->drawable.pScreen->ClearToBackground) (pWin, 0, 0, 0,
44435c4bbdfSmrg                                                                  0, TRUE);
44535c4bbdfSmrg            }
44635c4bbdfSmrg
44735c4bbdfSmrg            /*
44835c4bbdfSmrg             * Unredirect all existing subwindows
44935c4bbdfSmrg             */
45035c4bbdfSmrg            for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
45135c4bbdfSmrg                (void) compUnredirectWindow(pClient, pChild, ccw->update);
45235c4bbdfSmrg
45335c4bbdfSmrg            free(ccw);
45435c4bbdfSmrg            break;
45535c4bbdfSmrg        }
45605b261ecSmrg    }
45705b261ecSmrg
45805b261ecSmrg    /*
45905b261ecSmrg     * Check if all of the per-client records are gone
46005b261ecSmrg     */
46135c4bbdfSmrg    if (!csw->clients) {
46235c4bbdfSmrg        dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL);
46335c4bbdfSmrg        free(csw);
46405b261ecSmrg    }
46505b261ecSmrg}
46605b261ecSmrg
46705b261ecSmrg/*
46805b261ecSmrg * This is easy, just free the appropriate resource.
46905b261ecSmrg */
47005b261ecSmrg
47105b261ecSmrgint
47235c4bbdfSmrgcompUnredirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update)
47305b261ecSmrg{
47435c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pWin);
47535c4bbdfSmrg    CompClientWindowPtr ccw;
47635c4bbdfSmrg
47705b261ecSmrg    if (!csw)
47835c4bbdfSmrg        return BadValue;
47905b261ecSmrg    for (ccw = csw->clients; ccw; ccw = ccw->next)
48035c4bbdfSmrg        if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) {
48135c4bbdfSmrg            FreeResource(ccw->id, RT_NONE);
48235c4bbdfSmrg            return Success;
48335c4bbdfSmrg        }
48405b261ecSmrg    return BadValue;
48505b261ecSmrg}
48605b261ecSmrg
48705b261ecSmrg/*
48805b261ecSmrg * Add redirection information for one subwindow (during reparent)
48905b261ecSmrg */
49005b261ecSmrg
49105b261ecSmrgint
49235c4bbdfSmrgcompRedirectOneSubwindow(WindowPtr pParent, WindowPtr pWin)
49305b261ecSmrg{
49435c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pParent);
49535c4bbdfSmrg    CompClientWindowPtr ccw;
49605b261ecSmrg
49705b261ecSmrg    if (!csw)
49835c4bbdfSmrg        return Success;
49935c4bbdfSmrg    for (ccw = csw->clients; ccw; ccw = ccw->next) {
50035c4bbdfSmrg        int ret = compRedirectWindow(clients[CLIENT_ID(ccw->id)],
50135c4bbdfSmrg                                     pWin, ccw->update);
50235c4bbdfSmrg
50335c4bbdfSmrg        if (ret != Success)
50435c4bbdfSmrg            return ret;
50505b261ecSmrg    }
50605b261ecSmrg    return Success;
50705b261ecSmrg}
50805b261ecSmrg
50905b261ecSmrg/*
51005b261ecSmrg * Remove redirection information for one subwindow (during reparent)
51105b261ecSmrg */
51205b261ecSmrg
51305b261ecSmrgint
51435c4bbdfSmrgcompUnredirectOneSubwindow(WindowPtr pParent, WindowPtr pWin)
51505b261ecSmrg{
51635c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pParent);
51735c4bbdfSmrg    CompClientWindowPtr ccw;
51805b261ecSmrg
51905b261ecSmrg    if (!csw)
52035c4bbdfSmrg        return Success;
52135c4bbdfSmrg    for (ccw = csw->clients; ccw; ccw = ccw->next) {
52235c4bbdfSmrg        int ret = compUnredirectWindow(clients[CLIENT_ID(ccw->id)],
52335c4bbdfSmrg                                       pWin, ccw->update);
52435c4bbdfSmrg
52535c4bbdfSmrg        if (ret != Success)
52635c4bbdfSmrg            return ret;
52705b261ecSmrg    }
52805b261ecSmrg    return Success;
52905b261ecSmrg}
53005b261ecSmrg
53105b261ecSmrgstatic PixmapPtr
53235c4bbdfSmrgcompNewPixmap(WindowPtr pWin, int x, int y, int w, int h)
53305b261ecSmrg{
53435c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
53535c4bbdfSmrg    WindowPtr pParent = pWin->parent;
53635c4bbdfSmrg    PixmapPtr pPixmap;
53705b261ecSmrg
5384642e01fSmrg    pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth,
53935c4bbdfSmrg                                        CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
54005b261ecSmrg
54105b261ecSmrg    if (!pPixmap)
54235c4bbdfSmrg        return 0;
54335c4bbdfSmrg
54405b261ecSmrg    pPixmap->screen_x = x;
54505b261ecSmrg    pPixmap->screen_y = y;
5469ace9065Smrg
54735c4bbdfSmrg    if (pParent->drawable.depth == pWin->drawable.depth) {
54835c4bbdfSmrg        GCPtr pGC = GetScratchGC(pWin->drawable.depth, pScreen);
54935c4bbdfSmrg
55035c4bbdfSmrg        if (pGC) {
55135c4bbdfSmrg            ChangeGCVal val;
55235c4bbdfSmrg
55335c4bbdfSmrg            val.val = IncludeInferiors;
55435c4bbdfSmrg            ChangeGC(NullClient, pGC, GCSubwindowMode, &val);
55535c4bbdfSmrg            ValidateGC(&pPixmap->drawable, pGC);
55635c4bbdfSmrg            (*pGC->ops->CopyArea) (&pParent->drawable,
55735c4bbdfSmrg                                   &pPixmap->drawable,
55835c4bbdfSmrg                                   pGC,
55935c4bbdfSmrg                                   x - pParent->drawable.x,
56035c4bbdfSmrg                                   y - pParent->drawable.y, w, h, 0, 0);
56135c4bbdfSmrg            FreeScratchGC(pGC);
56235c4bbdfSmrg        }
56305b261ecSmrg    }
56435c4bbdfSmrg    else {
56535c4bbdfSmrg        PictFormatPtr pSrcFormat = PictureWindowFormat(pParent);
56635c4bbdfSmrg        PictFormatPtr pDstFormat = PictureWindowFormat(pWin);
56735c4bbdfSmrg        XID inferiors = IncludeInferiors;
56835c4bbdfSmrg        int error;
56935c4bbdfSmrg
57035c4bbdfSmrg        PicturePtr pSrcPicture = CreatePicture(None,
57135c4bbdfSmrg                                               &pParent->drawable,
57235c4bbdfSmrg                                               pSrcFormat,
57335c4bbdfSmrg                                               CPSubwindowMode,
57435c4bbdfSmrg                                               &inferiors,
57535c4bbdfSmrg                                               serverClient, &error);
57635c4bbdfSmrg
57735c4bbdfSmrg        PicturePtr pDstPicture = CreatePicture(None,
57835c4bbdfSmrg                                               &pPixmap->drawable,
57935c4bbdfSmrg                                               pDstFormat,
58035c4bbdfSmrg                                               0, 0,
58135c4bbdfSmrg                                               serverClient, &error);
58235c4bbdfSmrg
58335c4bbdfSmrg        if (pSrcPicture && pDstPicture) {
58435c4bbdfSmrg            CompositePicture(PictOpSrc,
58535c4bbdfSmrg                             pSrcPicture,
58635c4bbdfSmrg                             NULL,
58735c4bbdfSmrg                             pDstPicture,
58835c4bbdfSmrg                             x - pParent->drawable.x,
58935c4bbdfSmrg                             y - pParent->drawable.y, 0, 0, 0, 0, w, h);
59035c4bbdfSmrg        }
59135c4bbdfSmrg        if (pSrcPicture)
59235c4bbdfSmrg            FreePicture(pSrcPicture, 0);
59335c4bbdfSmrg        if (pDstPicture)
59435c4bbdfSmrg            FreePicture(pDstPicture, 0);
59505b261ecSmrg    }
59605b261ecSmrg    return pPixmap;
59705b261ecSmrg}
59805b261ecSmrg
59905b261ecSmrgBool
60035c4bbdfSmrgcompAllocPixmap(WindowPtr pWin)
60105b261ecSmrg{
60235c4bbdfSmrg    int bw = (int) pWin->borderWidth;
60335c4bbdfSmrg    int x = pWin->drawable.x - bw;
60435c4bbdfSmrg    int y = pWin->drawable.y - bw;
60535c4bbdfSmrg    int w = pWin->drawable.width + (bw << 1);
60635c4bbdfSmrg    int h = pWin->drawable.height + (bw << 1);
60735c4bbdfSmrg    PixmapPtr pPixmap = compNewPixmap(pWin, x, y, w, h);
60835c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
609f2346221Smrg    Bool status;
61005b261ecSmrg
611f2346221Smrg    if (!pPixmap) {
612f2346221Smrg        status = FALSE;
613f2346221Smrg        goto out;
614f2346221Smrg    }
61505b261ecSmrg    if (cw->update == CompositeRedirectAutomatic)
61635c4bbdfSmrg        pWin->redirectDraw = RedirectDrawAutomatic;
61705b261ecSmrg    else
61835c4bbdfSmrg        pWin->redirectDraw = RedirectDrawManual;
61905b261ecSmrg
6201b5d61b8Smrg    compSetPixmap(pWin, pPixmap, bw);
62105b261ecSmrg    cw->oldx = COMP_ORIGIN_INVALID;
62205b261ecSmrg    cw->oldy = COMP_ORIGIN_INVALID;
62305b261ecSmrg    cw->damageRegistered = FALSE;
62435c4bbdfSmrg    if (cw->update == CompositeRedirectAutomatic) {
62535c4bbdfSmrg        DamageRegister(&pWin->drawable, cw->damage);
62635c4bbdfSmrg        cw->damageRegistered = TRUE;
62705b261ecSmrg    }
628f2346221Smrg    status = TRUE;
62935c4bbdfSmrg
630f2346221Smrgout:
63135c4bbdfSmrg    /* Make sure our borderClip is up to date */
63235c4bbdfSmrg    RegionUninit(&cw->borderClip);
63335c4bbdfSmrg    RegionCopy(&cw->borderClip, &pWin->borderClip);
63435c4bbdfSmrg    cw->borderClipX = pWin->drawable.x;
63535c4bbdfSmrg    cw->borderClipY = pWin->drawable.y;
63635c4bbdfSmrg
637f2346221Smrg    return status;
63805b261ecSmrg}
63905b261ecSmrg
64005b261ecSmrgvoid
64135c4bbdfSmrgcompSetParentPixmap(WindowPtr pWin)
64205b261ecSmrg{
64335c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
64435c4bbdfSmrg    PixmapPtr pParentPixmap;
64535c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
64635c4bbdfSmrg
64735c4bbdfSmrg    if (cw->damageRegistered) {
64835c4bbdfSmrg        DamageUnregister(cw->damage);
64935c4bbdfSmrg        cw->damageRegistered = FALSE;
65035c4bbdfSmrg        DamageEmpty(cw->damage);
65105b261ecSmrg    }
65205b261ecSmrg    /*
65305b261ecSmrg     * Move the parent-constrained border clip region back into
65405b261ecSmrg     * the window so that ValidateTree will handle the unmap
65505b261ecSmrg     * case correctly.  Unmap adds the window borderClip to the
65605b261ecSmrg     * parent exposed area; regions beyond the parent cause crashes
65705b261ecSmrg     */
6586747b715Smrg    RegionCopy(&pWin->borderClip, &cw->borderClip);
65905b261ecSmrg    pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent);
66005b261ecSmrg    pWin->redirectDraw = RedirectDrawNone;
6611b5d61b8Smrg    compSetPixmap(pWin, pParentPixmap, pWin->borderWidth);
66205b261ecSmrg}
66305b261ecSmrg
66405b261ecSmrg/*
66505b261ecSmrg * Make sure the pixmap is the right size and offset.  Allocate a new
66605b261ecSmrg * pixmap to change size, adjust origin to change offset, leaving the
66705b261ecSmrg * old pixmap in cw->pOldPixmap so bits can be recovered
66805b261ecSmrg */
66905b261ecSmrgBool
67035c4bbdfSmrgcompReallocPixmap(WindowPtr pWin, int draw_x, int draw_y,
67135c4bbdfSmrg                  unsigned int w, unsigned int h, int bw)
67205b261ecSmrg{
67335c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
67435c4bbdfSmrg    PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin);
67535c4bbdfSmrg    PixmapPtr pNew;
67635c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
67735c4bbdfSmrg    int pix_x, pix_y;
67835c4bbdfSmrg    int pix_w, pix_h;
67935c4bbdfSmrg
680ed6184dfSmrg    assert(cw);
681ed6184dfSmrg    assert(pWin->redirectDraw != RedirectDrawNone);
68205b261ecSmrg    cw->oldx = pOld->screen_x;
68305b261ecSmrg    cw->oldy = pOld->screen_y;
68405b261ecSmrg    pix_x = draw_x - bw;
68505b261ecSmrg    pix_y = draw_y - bw;
68605b261ecSmrg    pix_w = w + (bw << 1);
68705b261ecSmrg    pix_h = h + (bw << 1);
68835c4bbdfSmrg    if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height) {
68935c4bbdfSmrg        pNew = compNewPixmap(pWin, pix_x, pix_y, pix_w, pix_h);
69035c4bbdfSmrg        if (!pNew)
69135c4bbdfSmrg            return FALSE;
69235c4bbdfSmrg        cw->pOldPixmap = pOld;
6931b5d61b8Smrg        compSetPixmap(pWin, pNew, bw);
69405b261ecSmrg    }
69535c4bbdfSmrg    else {
69635c4bbdfSmrg        pNew = pOld;
69735c4bbdfSmrg        cw->pOldPixmap = 0;
69805b261ecSmrg    }
69905b261ecSmrg    pNew->screen_x = pix_x;
70005b261ecSmrg    pNew->screen_y = pix_y;
70105b261ecSmrg    return TRUE;
70205b261ecSmrg}
703