compalloc.c revision 1b5d61b8
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;
10005b261ecSmrg}
10105b261ecSmrg
10235c4bbdfSmrgstatic Bool
10335c4bbdfSmrgcompMarkWindows(WindowPtr pWin, WindowPtr *ppLayerWin)
10435c4bbdfSmrg{
10535c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
10635c4bbdfSmrg    WindowPtr pLayerWin = pWin;
10735c4bbdfSmrg
10835c4bbdfSmrg    if (!pWin->viewable)
10935c4bbdfSmrg        return FALSE;
11035c4bbdfSmrg
11135c4bbdfSmrg    (*pScreen->MarkOverlappedWindows) (pWin, pWin, &pLayerWin);
11235c4bbdfSmrg    (*pScreen->MarkWindow) (pLayerWin->parent);
11335c4bbdfSmrg
11435c4bbdfSmrg    *ppLayerWin = pLayerWin;
11535c4bbdfSmrg
11635c4bbdfSmrg    return TRUE;
11735c4bbdfSmrg}
11835c4bbdfSmrg
11935c4bbdfSmrgstatic void
12035c4bbdfSmrgcompHandleMarkedWindows(WindowPtr pWin, WindowPtr pLayerWin)
12135c4bbdfSmrg{
12235c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
12335c4bbdfSmrg
12435c4bbdfSmrg    (*pScreen->ValidateTree) (pLayerWin->parent, pLayerWin, VTOther);
12535c4bbdfSmrg    (*pScreen->HandleExposures) (pLayerWin->parent);
12635c4bbdfSmrg    if (pScreen->PostValidateTree)
12735c4bbdfSmrg        (*pScreen->PostValidateTree) (pLayerWin->parent, pLayerWin, VTOther);
12835c4bbdfSmrg}
12935c4bbdfSmrg
13005b261ecSmrg/*
13105b261ecSmrg * Redirect one window for one client
13205b261ecSmrg */
13305b261ecSmrgint
13435c4bbdfSmrgcompRedirectWindow(ClientPtr pClient, WindowPtr pWin, int update)
13505b261ecSmrg{
13635c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
13735c4bbdfSmrg    CompClientWindowPtr ccw;
13835c4bbdfSmrg    CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen);
13935c4bbdfSmrg    WindowPtr pLayerWin;
14035c4bbdfSmrg    Bool anyMarked = FALSE;
14135c4bbdfSmrg
14205b261ecSmrg    if (pWin == cs->pOverlayWin) {
14335c4bbdfSmrg        return Success;
14405b261ecSmrg    }
14505b261ecSmrg
1464642e01fSmrg    if (!pWin->parent)
14735c4bbdfSmrg        return BadMatch;
1484642e01fSmrg
14905b261ecSmrg    /*
15005b261ecSmrg     * Only one Manual update is allowed
15105b261ecSmrg     */
15205b261ecSmrg    if (cw && update == CompositeRedirectManual)
15335c4bbdfSmrg        for (ccw = cw->clients; ccw; ccw = ccw->next)
15435c4bbdfSmrg            if (ccw->update == CompositeRedirectManual)
15535c4bbdfSmrg                return BadAccess;
15635c4bbdfSmrg
15705b261ecSmrg    /*
15835c4bbdfSmrg     * Allocate per-client per-window structure
15905b261ecSmrg     * The client *could* allocate multiple, but while supported,
16005b261ecSmrg     * it is not expected to be common
16105b261ecSmrg     */
16235c4bbdfSmrg    ccw = malloc(sizeof(CompClientWindowRec));
16305b261ecSmrg    if (!ccw)
16435c4bbdfSmrg        return BadAlloc;
16535c4bbdfSmrg    ccw->id = FakeClientID(pClient->index);
16605b261ecSmrg    ccw->update = update;
16705b261ecSmrg    /*
16805b261ecSmrg     * Now make sure there's a per-window structure to hang this from
16905b261ecSmrg     */
17035c4bbdfSmrg    if (!cw) {
17135c4bbdfSmrg        cw = malloc(sizeof(CompWindowRec));
17235c4bbdfSmrg        if (!cw) {
17335c4bbdfSmrg            free(ccw);
17435c4bbdfSmrg            return BadAlloc;
17535c4bbdfSmrg        }
17635c4bbdfSmrg        cw->damage = DamageCreate(compReportDamage,
17735c4bbdfSmrg                                  compDestroyDamage,
17835c4bbdfSmrg                                  DamageReportNonEmpty,
17935c4bbdfSmrg                                  FALSE, pWin->drawable.pScreen, pWin);
18035c4bbdfSmrg        if (!cw->damage) {
18135c4bbdfSmrg            free(ccw);
18235c4bbdfSmrg            free(cw);
18335c4bbdfSmrg            return BadAlloc;
18435c4bbdfSmrg        }
18535c4bbdfSmrg
18635c4bbdfSmrg        anyMarked = compMarkWindows(pWin, &pLayerWin);
18735c4bbdfSmrg
18835c4bbdfSmrg        RegionNull(&cw->borderClip);
18935c4bbdfSmrg        cw->update = CompositeRedirectAutomatic;
19035c4bbdfSmrg        cw->clients = 0;
19135c4bbdfSmrg        cw->oldx = COMP_ORIGIN_INVALID;
19235c4bbdfSmrg        cw->oldy = COMP_ORIGIN_INVALID;
19335c4bbdfSmrg        cw->damageRegistered = FALSE;
19435c4bbdfSmrg        cw->damaged = FALSE;
19535c4bbdfSmrg        cw->pOldPixmap = NullPixmap;
19635c4bbdfSmrg        dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw);
19705b261ecSmrg    }
19805b261ecSmrg    ccw->next = cw->clients;
19905b261ecSmrg    cw->clients = ccw;
20035c4bbdfSmrg    if (!AddResource(ccw->id, CompositeClientWindowType, pWin))
20135c4bbdfSmrg        return BadAlloc;
20235c4bbdfSmrg    if (ccw->update == CompositeRedirectManual) {
20335c4bbdfSmrg        if (!anyMarked)
20435c4bbdfSmrg            anyMarked = compMarkWindows(pWin, &pLayerWin);
20535c4bbdfSmrg
20635c4bbdfSmrg        if (cw->damageRegistered) {
20735c4bbdfSmrg            DamageUnregister(cw->damage);
20835c4bbdfSmrg            cw->damageRegistered = FALSE;
20935c4bbdfSmrg        }
21035c4bbdfSmrg        cw->update = CompositeRedirectManual;
21105b261ecSmrg    }
21235c4bbdfSmrg    else if (cw->update == CompositeRedirectAutomatic && !cw->damageRegistered) {
21335c4bbdfSmrg        if (!anyMarked)
21435c4bbdfSmrg            anyMarked = compMarkWindows(pWin, &pLayerWin);
21505b261ecSmrg    }
21635c4bbdfSmrg
21735c4bbdfSmrg    if (!compCheckRedirect(pWin)) {
21835c4bbdfSmrg        FreeResource(ccw->id, RT_NONE);
21935c4bbdfSmrg        return BadAlloc;
22005b261ecSmrg    }
22135c4bbdfSmrg
22235c4bbdfSmrg    if (anyMarked)
22335c4bbdfSmrg        compHandleMarkedWindows(pWin, pLayerWin);
22435c4bbdfSmrg
22505b261ecSmrg    return Success;
22605b261ecSmrg}
22705b261ecSmrg
22835c4bbdfSmrgvoid
22935c4bbdfSmrgcompRestoreWindow(WindowPtr pWin, PixmapPtr pPixmap)
23035c4bbdfSmrg{
23135c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
23235c4bbdfSmrg    WindowPtr pParent = pWin->parent;
23335c4bbdfSmrg
23435c4bbdfSmrg    if (pParent->drawable.depth == pWin->drawable.depth) {
23535c4bbdfSmrg        GCPtr pGC = GetScratchGC(pWin->drawable.depth, pScreen);
23635c4bbdfSmrg        int bw = (int) pWin->borderWidth;
23735c4bbdfSmrg        int x = bw;
23835c4bbdfSmrg        int y = bw;
23935c4bbdfSmrg        int w = pWin->drawable.width;
24035c4bbdfSmrg        int h = pWin->drawable.height;
24135c4bbdfSmrg
24235c4bbdfSmrg        if (pGC) {
24335c4bbdfSmrg            ChangeGCVal val;
24435c4bbdfSmrg
24535c4bbdfSmrg            val.val = IncludeInferiors;
24635c4bbdfSmrg            ChangeGC(NullClient, pGC, GCSubwindowMode, &val);
24735c4bbdfSmrg            ValidateGC(&pWin->drawable, pGC);
24835c4bbdfSmrg            (*pGC->ops->CopyArea) (&pPixmap->drawable,
24935c4bbdfSmrg                                   &pWin->drawable, pGC, x, y, w, h, 0, 0);
25035c4bbdfSmrg            FreeScratchGC(pGC);
25135c4bbdfSmrg        }
25235c4bbdfSmrg    }
25335c4bbdfSmrg}
25435c4bbdfSmrg
25505b261ecSmrg/*
25605b261ecSmrg * Free one of the per-client per-window resources, clearing
25705b261ecSmrg * redirect and the per-window pointer as appropriate
25805b261ecSmrg */
25905b261ecSmrgvoid
26035c4bbdfSmrgcompFreeClientWindow(WindowPtr pWin, XID id)
26105b261ecSmrg{
26235c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
26335c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
26435c4bbdfSmrg    CompClientWindowPtr ccw, *prev;
26535c4bbdfSmrg    Bool anyMarked = FALSE;
26635c4bbdfSmrg    WindowPtr pLayerWin;
26735c4bbdfSmrg    PixmapPtr pPixmap = NULL;
26805b261ecSmrg
26905b261ecSmrg    if (!cw)
27035c4bbdfSmrg        return;
27135c4bbdfSmrg    for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next) {
27235c4bbdfSmrg        if (ccw->id == id) {
27335c4bbdfSmrg            *prev = ccw->next;
27435c4bbdfSmrg            if (ccw->update == CompositeRedirectManual)
27535c4bbdfSmrg                cw->update = CompositeRedirectAutomatic;
27635c4bbdfSmrg            free(ccw);
27735c4bbdfSmrg            break;
27835c4bbdfSmrg        }
27905b261ecSmrg    }
28035c4bbdfSmrg    if (!cw->clients) {
28135c4bbdfSmrg        anyMarked = compMarkWindows(pWin, &pLayerWin);
28235c4bbdfSmrg
28335c4bbdfSmrg        if (pWin->redirectDraw != RedirectDrawNone) {
28435c4bbdfSmrg            pPixmap = (*pScreen->GetWindowPixmap) (pWin);
28535c4bbdfSmrg            compSetParentPixmap(pWin);
28635c4bbdfSmrg        }
28735c4bbdfSmrg
28835c4bbdfSmrg        if (cw->damage)
28935c4bbdfSmrg            DamageDestroy(cw->damage);
29035c4bbdfSmrg
29135c4bbdfSmrg        RegionUninit(&cw->borderClip);
29235c4bbdfSmrg
29335c4bbdfSmrg        dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL);
29435c4bbdfSmrg        free(cw);
29505b261ecSmrg    }
29605b261ecSmrg    else if (cw->update == CompositeRedirectAutomatic &&
29735c4bbdfSmrg             !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone) {
29835c4bbdfSmrg        anyMarked = compMarkWindows(pWin, &pLayerWin);
29935c4bbdfSmrg
30035c4bbdfSmrg        DamageRegister(&pWin->drawable, cw->damage);
30135c4bbdfSmrg        cw->damageRegistered = TRUE;
30235c4bbdfSmrg        pWin->redirectDraw = RedirectDrawAutomatic;
30335c4bbdfSmrg        DamageDamageRegion(&pWin->drawable, &pWin->borderSize);
30405b261ecSmrg    }
30535c4bbdfSmrg
30635c4bbdfSmrg    if (anyMarked)
30735c4bbdfSmrg        compHandleMarkedWindows(pWin, pLayerWin);
30835c4bbdfSmrg
30935c4bbdfSmrg    if (pPixmap) {
31035c4bbdfSmrg        compRestoreWindow(pWin, pPixmap);
31135c4bbdfSmrg        (*pScreen->DestroyPixmap) (pPixmap);
31205b261ecSmrg    }
31305b261ecSmrg}
31405b261ecSmrg
31505b261ecSmrg/*
31605b261ecSmrg * This is easy, just free the appropriate resource.
31705b261ecSmrg */
31805b261ecSmrg
31905b261ecSmrgint
32035c4bbdfSmrgcompUnredirectWindow(ClientPtr pClient, WindowPtr pWin, int update)
32105b261ecSmrg{
32235c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
32335c4bbdfSmrg    CompClientWindowPtr ccw;
32405b261ecSmrg
32505b261ecSmrg    if (!cw)
32635c4bbdfSmrg        return BadValue;
32705b261ecSmrg
32805b261ecSmrg    for (ccw = cw->clients; ccw; ccw = ccw->next)
32935c4bbdfSmrg        if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) {
33035c4bbdfSmrg            FreeResource(ccw->id, RT_NONE);
33135c4bbdfSmrg            return Success;
33235c4bbdfSmrg        }
33305b261ecSmrg    return BadValue;
33405b261ecSmrg}
33535c4bbdfSmrg
33605b261ecSmrg/*
33705b261ecSmrg * Redirect all subwindows for one client
33805b261ecSmrg */
33905b261ecSmrg
34005b261ecSmrgint
34135c4bbdfSmrgcompRedirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update)
34205b261ecSmrg{
34335c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pWin);
34435c4bbdfSmrg    CompClientWindowPtr ccw;
34535c4bbdfSmrg    WindowPtr pChild;
34605b261ecSmrg
34705b261ecSmrg    /*
34805b261ecSmrg     * Only one Manual update is allowed
34905b261ecSmrg     */
35005b261ecSmrg    if (csw && update == CompositeRedirectManual)
35135c4bbdfSmrg        for (ccw = csw->clients; ccw; ccw = ccw->next)
35235c4bbdfSmrg            if (ccw->update == CompositeRedirectManual)
35335c4bbdfSmrg                return BadAccess;
35405b261ecSmrg    /*
35535c4bbdfSmrg     * Allocate per-client per-window structure
35605b261ecSmrg     * The client *could* allocate multiple, but while supported,
35705b261ecSmrg     * it is not expected to be common
35805b261ecSmrg     */
35935c4bbdfSmrg    ccw = malloc(sizeof(CompClientWindowRec));
36005b261ecSmrg    if (!ccw)
36135c4bbdfSmrg        return BadAlloc;
36235c4bbdfSmrg    ccw->id = FakeClientID(pClient->index);
36305b261ecSmrg    ccw->update = update;
36405b261ecSmrg    /*
36505b261ecSmrg     * Now make sure there's a per-window structure to hang this from
36605b261ecSmrg     */
36735c4bbdfSmrg    if (!csw) {
36835c4bbdfSmrg        csw = malloc(sizeof(CompSubwindowsRec));
36935c4bbdfSmrg        if (!csw) {
37035c4bbdfSmrg            free(ccw);
37135c4bbdfSmrg            return BadAlloc;
37235c4bbdfSmrg        }
37335c4bbdfSmrg        csw->update = CompositeRedirectAutomatic;
37435c4bbdfSmrg        csw->clients = 0;
37535c4bbdfSmrg        dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw);
37605b261ecSmrg    }
37705b261ecSmrg    /*
37805b261ecSmrg     * Redirect all existing windows
37905b261ecSmrg     */
38035c4bbdfSmrg    for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) {
38135c4bbdfSmrg        int ret = compRedirectWindow(pClient, pChild, update);
38235c4bbdfSmrg
38335c4bbdfSmrg        if (ret != Success) {
38435c4bbdfSmrg            for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib)
38535c4bbdfSmrg                (void) compUnredirectWindow(pClient, pChild, update);
38635c4bbdfSmrg            if (!csw->clients) {
38735c4bbdfSmrg                free(csw);
38835c4bbdfSmrg                dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0);
38935c4bbdfSmrg            }
39035c4bbdfSmrg            free(ccw);
39135c4bbdfSmrg            return ret;
39235c4bbdfSmrg        }
39305b261ecSmrg    }
39405b261ecSmrg    /*
39505b261ecSmrg     * Hook into subwindows list
39605b261ecSmrg     */
39705b261ecSmrg    ccw->next = csw->clients;
39805b261ecSmrg    csw->clients = ccw;
39935c4bbdfSmrg    if (!AddResource(ccw->id, CompositeClientSubwindowsType, pWin))
40035c4bbdfSmrg        return BadAlloc;
40135c4bbdfSmrg    if (ccw->update == CompositeRedirectManual) {
40235c4bbdfSmrg        csw->update = CompositeRedirectManual;
40335c4bbdfSmrg        /*
40435c4bbdfSmrg         * tell damage extension that damage events for this client are
40535c4bbdfSmrg         * critical output
40635c4bbdfSmrg         */
40735c4bbdfSmrg        DamageExtSetCritical(pClient, TRUE);
40835c4bbdfSmrg        pWin->inhibitBGPaint = TRUE;
40905b261ecSmrg    }
41005b261ecSmrg    return Success;
41105b261ecSmrg}
41205b261ecSmrg
41305b261ecSmrg/*
41405b261ecSmrg * Free one of the per-client per-subwindows resources,
41505b261ecSmrg * which frees one redirect per subwindow
41605b261ecSmrg */
41705b261ecSmrgvoid
41835c4bbdfSmrgcompFreeClientSubwindows(WindowPtr pWin, XID id)
41905b261ecSmrg{
42035c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pWin);
42135c4bbdfSmrg    CompClientWindowPtr ccw, *prev;
42235c4bbdfSmrg    WindowPtr pChild;
42305b261ecSmrg
42405b261ecSmrg    if (!csw)
42535c4bbdfSmrg        return;
42635c4bbdfSmrg    for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next) {
42735c4bbdfSmrg        if (ccw->id == id) {
42835c4bbdfSmrg            ClientPtr pClient = clients[CLIENT_ID(id)];
42935c4bbdfSmrg
43035c4bbdfSmrg            *prev = ccw->next;
43135c4bbdfSmrg            if (ccw->update == CompositeRedirectManual) {
43235c4bbdfSmrg                /*
43335c4bbdfSmrg                 * tell damage extension that damage events for this client are
43435c4bbdfSmrg                 * critical output
43535c4bbdfSmrg                 */
43635c4bbdfSmrg                DamageExtSetCritical(pClient, FALSE);
43735c4bbdfSmrg                csw->update = CompositeRedirectAutomatic;
43835c4bbdfSmrg                pWin->inhibitBGPaint = FALSE;
43935c4bbdfSmrg                if (pWin->mapped)
44035c4bbdfSmrg                    (*pWin->drawable.pScreen->ClearToBackground) (pWin, 0, 0, 0,
44135c4bbdfSmrg                                                                  0, TRUE);
44235c4bbdfSmrg            }
44335c4bbdfSmrg
44435c4bbdfSmrg            /*
44535c4bbdfSmrg             * Unredirect all existing subwindows
44635c4bbdfSmrg             */
44735c4bbdfSmrg            for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
44835c4bbdfSmrg                (void) compUnredirectWindow(pClient, pChild, ccw->update);
44935c4bbdfSmrg
45035c4bbdfSmrg            free(ccw);
45135c4bbdfSmrg            break;
45235c4bbdfSmrg        }
45305b261ecSmrg    }
45405b261ecSmrg
45505b261ecSmrg    /*
45605b261ecSmrg     * Check if all of the per-client records are gone
45705b261ecSmrg     */
45835c4bbdfSmrg    if (!csw->clients) {
45935c4bbdfSmrg        dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL);
46035c4bbdfSmrg        free(csw);
46105b261ecSmrg    }
46205b261ecSmrg}
46305b261ecSmrg
46405b261ecSmrg/*
46505b261ecSmrg * This is easy, just free the appropriate resource.
46605b261ecSmrg */
46705b261ecSmrg
46805b261ecSmrgint
46935c4bbdfSmrgcompUnredirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update)
47005b261ecSmrg{
47135c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pWin);
47235c4bbdfSmrg    CompClientWindowPtr ccw;
47335c4bbdfSmrg
47405b261ecSmrg    if (!csw)
47535c4bbdfSmrg        return BadValue;
47605b261ecSmrg    for (ccw = csw->clients; ccw; ccw = ccw->next)
47735c4bbdfSmrg        if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) {
47835c4bbdfSmrg            FreeResource(ccw->id, RT_NONE);
47935c4bbdfSmrg            return Success;
48035c4bbdfSmrg        }
48105b261ecSmrg    return BadValue;
48205b261ecSmrg}
48305b261ecSmrg
48405b261ecSmrg/*
48505b261ecSmrg * Add redirection information for one subwindow (during reparent)
48605b261ecSmrg */
48705b261ecSmrg
48805b261ecSmrgint
48935c4bbdfSmrgcompRedirectOneSubwindow(WindowPtr pParent, WindowPtr pWin)
49005b261ecSmrg{
49135c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pParent);
49235c4bbdfSmrg    CompClientWindowPtr ccw;
49305b261ecSmrg
49405b261ecSmrg    if (!csw)
49535c4bbdfSmrg        return Success;
49635c4bbdfSmrg    for (ccw = csw->clients; ccw; ccw = ccw->next) {
49735c4bbdfSmrg        int ret = compRedirectWindow(clients[CLIENT_ID(ccw->id)],
49835c4bbdfSmrg                                     pWin, ccw->update);
49935c4bbdfSmrg
50035c4bbdfSmrg        if (ret != Success)
50135c4bbdfSmrg            return ret;
50205b261ecSmrg    }
50305b261ecSmrg    return Success;
50405b261ecSmrg}
50505b261ecSmrg
50605b261ecSmrg/*
50705b261ecSmrg * Remove redirection information for one subwindow (during reparent)
50805b261ecSmrg */
50905b261ecSmrg
51005b261ecSmrgint
51135c4bbdfSmrgcompUnredirectOneSubwindow(WindowPtr pParent, WindowPtr pWin)
51205b261ecSmrg{
51335c4bbdfSmrg    CompSubwindowsPtr csw = GetCompSubwindows(pParent);
51435c4bbdfSmrg    CompClientWindowPtr ccw;
51505b261ecSmrg
51605b261ecSmrg    if (!csw)
51735c4bbdfSmrg        return Success;
51835c4bbdfSmrg    for (ccw = csw->clients; ccw; ccw = ccw->next) {
51935c4bbdfSmrg        int ret = compUnredirectWindow(clients[CLIENT_ID(ccw->id)],
52035c4bbdfSmrg                                       pWin, ccw->update);
52135c4bbdfSmrg
52235c4bbdfSmrg        if (ret != Success)
52335c4bbdfSmrg            return ret;
52405b261ecSmrg    }
52505b261ecSmrg    return Success;
52605b261ecSmrg}
52705b261ecSmrg
52805b261ecSmrgstatic PixmapPtr
52935c4bbdfSmrgcompNewPixmap(WindowPtr pWin, int x, int y, int w, int h)
53005b261ecSmrg{
53135c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
53235c4bbdfSmrg    WindowPtr pParent = pWin->parent;
53335c4bbdfSmrg    PixmapPtr pPixmap;
53405b261ecSmrg
5354642e01fSmrg    pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth,
53635c4bbdfSmrg                                        CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
53705b261ecSmrg
53805b261ecSmrg    if (!pPixmap)
53935c4bbdfSmrg        return 0;
54035c4bbdfSmrg
54105b261ecSmrg    pPixmap->screen_x = x;
54205b261ecSmrg    pPixmap->screen_y = y;
5439ace9065Smrg
54435c4bbdfSmrg    if (pParent->drawable.depth == pWin->drawable.depth) {
54535c4bbdfSmrg        GCPtr pGC = GetScratchGC(pWin->drawable.depth, pScreen);
54635c4bbdfSmrg
54735c4bbdfSmrg        if (pGC) {
54835c4bbdfSmrg            ChangeGCVal val;
54935c4bbdfSmrg
55035c4bbdfSmrg            val.val = IncludeInferiors;
55135c4bbdfSmrg            ChangeGC(NullClient, pGC, GCSubwindowMode, &val);
55235c4bbdfSmrg            ValidateGC(&pPixmap->drawable, pGC);
55335c4bbdfSmrg            (*pGC->ops->CopyArea) (&pParent->drawable,
55435c4bbdfSmrg                                   &pPixmap->drawable,
55535c4bbdfSmrg                                   pGC,
55635c4bbdfSmrg                                   x - pParent->drawable.x,
55735c4bbdfSmrg                                   y - pParent->drawable.y, w, h, 0, 0);
55835c4bbdfSmrg            FreeScratchGC(pGC);
55935c4bbdfSmrg        }
56005b261ecSmrg    }
56135c4bbdfSmrg    else {
56235c4bbdfSmrg        PictFormatPtr pSrcFormat = PictureWindowFormat(pParent);
56335c4bbdfSmrg        PictFormatPtr pDstFormat = PictureWindowFormat(pWin);
56435c4bbdfSmrg        XID inferiors = IncludeInferiors;
56535c4bbdfSmrg        int error;
56635c4bbdfSmrg
56735c4bbdfSmrg        PicturePtr pSrcPicture = CreatePicture(None,
56835c4bbdfSmrg                                               &pParent->drawable,
56935c4bbdfSmrg                                               pSrcFormat,
57035c4bbdfSmrg                                               CPSubwindowMode,
57135c4bbdfSmrg                                               &inferiors,
57235c4bbdfSmrg                                               serverClient, &error);
57335c4bbdfSmrg
57435c4bbdfSmrg        PicturePtr pDstPicture = CreatePicture(None,
57535c4bbdfSmrg                                               &pPixmap->drawable,
57635c4bbdfSmrg                                               pDstFormat,
57735c4bbdfSmrg                                               0, 0,
57835c4bbdfSmrg                                               serverClient, &error);
57935c4bbdfSmrg
58035c4bbdfSmrg        if (pSrcPicture && pDstPicture) {
58135c4bbdfSmrg            CompositePicture(PictOpSrc,
58235c4bbdfSmrg                             pSrcPicture,
58335c4bbdfSmrg                             NULL,
58435c4bbdfSmrg                             pDstPicture,
58535c4bbdfSmrg                             x - pParent->drawable.x,
58635c4bbdfSmrg                             y - pParent->drawable.y, 0, 0, 0, 0, w, h);
58735c4bbdfSmrg        }
58835c4bbdfSmrg        if (pSrcPicture)
58935c4bbdfSmrg            FreePicture(pSrcPicture, 0);
59035c4bbdfSmrg        if (pDstPicture)
59135c4bbdfSmrg            FreePicture(pDstPicture, 0);
59205b261ecSmrg    }
59305b261ecSmrg    return pPixmap;
59405b261ecSmrg}
59505b261ecSmrg
59605b261ecSmrgBool
59735c4bbdfSmrgcompAllocPixmap(WindowPtr pWin)
59805b261ecSmrg{
59935c4bbdfSmrg    int bw = (int) pWin->borderWidth;
60035c4bbdfSmrg    int x = pWin->drawable.x - bw;
60135c4bbdfSmrg    int y = pWin->drawable.y - bw;
60235c4bbdfSmrg    int w = pWin->drawable.width + (bw << 1);
60335c4bbdfSmrg    int h = pWin->drawable.height + (bw << 1);
60435c4bbdfSmrg    PixmapPtr pPixmap = compNewPixmap(pWin, x, y, w, h);
60535c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
60605b261ecSmrg
60705b261ecSmrg    if (!pPixmap)
60835c4bbdfSmrg        return FALSE;
60905b261ecSmrg    if (cw->update == CompositeRedirectAutomatic)
61035c4bbdfSmrg        pWin->redirectDraw = RedirectDrawAutomatic;
61105b261ecSmrg    else
61235c4bbdfSmrg        pWin->redirectDraw = RedirectDrawManual;
61305b261ecSmrg
6141b5d61b8Smrg    compSetPixmap(pWin, pPixmap, bw);
61505b261ecSmrg    cw->oldx = COMP_ORIGIN_INVALID;
61605b261ecSmrg    cw->oldy = COMP_ORIGIN_INVALID;
61705b261ecSmrg    cw->damageRegistered = FALSE;
61835c4bbdfSmrg    if (cw->update == CompositeRedirectAutomatic) {
61935c4bbdfSmrg        DamageRegister(&pWin->drawable, cw->damage);
62035c4bbdfSmrg        cw->damageRegistered = TRUE;
62105b261ecSmrg    }
62235c4bbdfSmrg
62335c4bbdfSmrg    /* Make sure our borderClip is up to date */
62435c4bbdfSmrg    RegionUninit(&cw->borderClip);
62535c4bbdfSmrg    RegionCopy(&cw->borderClip, &pWin->borderClip);
62635c4bbdfSmrg    cw->borderClipX = pWin->drawable.x;
62735c4bbdfSmrg    cw->borderClipY = pWin->drawable.y;
62835c4bbdfSmrg
62905b261ecSmrg    return TRUE;
63005b261ecSmrg}
63105b261ecSmrg
63205b261ecSmrgvoid
63335c4bbdfSmrgcompSetParentPixmap(WindowPtr pWin)
63405b261ecSmrg{
63535c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
63635c4bbdfSmrg    PixmapPtr pParentPixmap;
63735c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
63835c4bbdfSmrg
63935c4bbdfSmrg    if (cw->damageRegistered) {
64035c4bbdfSmrg        DamageUnregister(cw->damage);
64135c4bbdfSmrg        cw->damageRegistered = FALSE;
64235c4bbdfSmrg        DamageEmpty(cw->damage);
64305b261ecSmrg    }
64405b261ecSmrg    /*
64505b261ecSmrg     * Move the parent-constrained border clip region back into
64605b261ecSmrg     * the window so that ValidateTree will handle the unmap
64705b261ecSmrg     * case correctly.  Unmap adds the window borderClip to the
64805b261ecSmrg     * parent exposed area; regions beyond the parent cause crashes
64905b261ecSmrg     */
6506747b715Smrg    RegionCopy(&pWin->borderClip, &cw->borderClip);
65105b261ecSmrg    pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent);
65205b261ecSmrg    pWin->redirectDraw = RedirectDrawNone;
6531b5d61b8Smrg    compSetPixmap(pWin, pParentPixmap, pWin->borderWidth);
65405b261ecSmrg}
65505b261ecSmrg
65605b261ecSmrg/*
65705b261ecSmrg * Make sure the pixmap is the right size and offset.  Allocate a new
65805b261ecSmrg * pixmap to change size, adjust origin to change offset, leaving the
65905b261ecSmrg * old pixmap in cw->pOldPixmap so bits can be recovered
66005b261ecSmrg */
66105b261ecSmrgBool
66235c4bbdfSmrgcompReallocPixmap(WindowPtr pWin, int draw_x, int draw_y,
66335c4bbdfSmrg                  unsigned int w, unsigned int h, int bw)
66405b261ecSmrg{
66535c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
66635c4bbdfSmrg    PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin);
66735c4bbdfSmrg    PixmapPtr pNew;
66835c4bbdfSmrg    CompWindowPtr cw = GetCompWindow(pWin);
66935c4bbdfSmrg    int pix_x, pix_y;
67035c4bbdfSmrg    int pix_w, pix_h;
67135c4bbdfSmrg
67235c4bbdfSmrg    assert(cw && pWin->redirectDraw != RedirectDrawNone);
67305b261ecSmrg    cw->oldx = pOld->screen_x;
67405b261ecSmrg    cw->oldy = pOld->screen_y;
67505b261ecSmrg    pix_x = draw_x - bw;
67605b261ecSmrg    pix_y = draw_y - bw;
67705b261ecSmrg    pix_w = w + (bw << 1);
67805b261ecSmrg    pix_h = h + (bw << 1);
67935c4bbdfSmrg    if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height) {
68035c4bbdfSmrg        pNew = compNewPixmap(pWin, pix_x, pix_y, pix_w, pix_h);
68135c4bbdfSmrg        if (!pNew)
68235c4bbdfSmrg            return FALSE;
68335c4bbdfSmrg        cw->pOldPixmap = pOld;
6841b5d61b8Smrg        compSetPixmap(pWin, pNew, bw);
68505b261ecSmrg    }
68635c4bbdfSmrg    else {
68735c4bbdfSmrg        pNew = pOld;
68835c4bbdfSmrg        cw->pOldPixmap = 0;
68905b261ecSmrg    }
69005b261ecSmrg    pNew->screen_x = pix_x;
69105b261ecSmrg    pNew->screen_y = pix_y;
69205b261ecSmrg    return TRUE;
69305b261ecSmrg}
694