rootlessWindow.c revision 05b261ec
105b261ecSmrg/*
205b261ecSmrg * Rootless window management
305b261ecSmrg */
405b261ecSmrg/*
505b261ecSmrg * Copyright (c) 2001 Greg Parker. All Rights Reserved.
605b261ecSmrg * Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved.
705b261ecSmrg * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
805b261ecSmrg *
905b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
1005b261ecSmrg * copy of this software and associated documentation files (the "Software"),
1105b261ecSmrg * to deal in the Software without restriction, including without limitation
1205b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1305b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the
1405b261ecSmrg * Software is furnished to do so, subject to the following conditions:
1505b261ecSmrg *
1605b261ecSmrg * The above copyright notice and this permission notice shall be included in
1705b261ecSmrg * all copies or substantial portions of the Software.
1805b261ecSmrg *
1905b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2005b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2105b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2205b261ecSmrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
2305b261ecSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2405b261ecSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2505b261ecSmrg * DEALINGS IN THE SOFTWARE.
2605b261ecSmrg *
2705b261ecSmrg * Except as contained in this notice, the name(s) of the above copyright
2805b261ecSmrg * holders shall not be used in advertising or otherwise to promote the sale,
2905b261ecSmrg * use or other dealings in this Software without prior written authorization.
3005b261ecSmrg */
3105b261ecSmrg
3205b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3305b261ecSmrg#include <dix-config.h>
3405b261ecSmrg#endif
3505b261ecSmrg
3605b261ecSmrg#include <stddef.h> /* For NULL */
3705b261ecSmrg#include <limits.h> /* For CHAR_BIT */
3805b261ecSmrg#include <assert.h>
3905b261ecSmrg
4005b261ecSmrg#include "rootlessCommon.h"
4105b261ecSmrg#include "rootlessWindow.h"
4205b261ecSmrg
4305b261ecSmrg#include "fb.h"
4405b261ecSmrg
4505b261ecSmrg
4605b261ecSmrg#ifdef ROOTLESS_GLOBAL_COORDS
4705b261ecSmrg#define SCREEN_TO_GLOBAL_X \
4805b261ecSmrg    (dixScreenOrigins[pScreen->myNum].x + rootlessGlobalOffsetX)
4905b261ecSmrg#define SCREEN_TO_GLOBAL_Y \
5005b261ecSmrg    (dixScreenOrigins[pScreen->myNum].y + rootlessGlobalOffsetY)
5105b261ecSmrg#else
5205b261ecSmrg#define SCREEN_TO_GLOBAL_X 0
5305b261ecSmrg#define SCREEN_TO_GLOBAL_Y 0
5405b261ecSmrg#endif
5505b261ecSmrg
5605b261ecSmrg
5705b261ecSmrg/*
5805b261ecSmrg * RootlessCreateWindow
5905b261ecSmrg *  For now, don't create a physical window until either the window is
6005b261ecSmrg *  realized, or we really need it (e.g. to attach VRAM surfaces to).
6105b261ecSmrg *  Do reset the window size so it's not clipped by the root window.
6205b261ecSmrg */
6305b261ecSmrgBool
6405b261ecSmrgRootlessCreateWindow(WindowPtr pWin)
6505b261ecSmrg{
6605b261ecSmrg    Bool result;
6705b261ecSmrg    RegionRec saveRoot;
6805b261ecSmrg
6905b261ecSmrg    WINREC(pWin) = NULL;
7005b261ecSmrg
7105b261ecSmrg    SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow);
7205b261ecSmrg
7305b261ecSmrg    if (!IsRoot(pWin)) {
7405b261ecSmrg        /* win/border size set by DIX, not by wrapped CreateWindow, so
7505b261ecSmrg           correct it here. Don't HUGE_ROOT when pWin is the root! */
7605b261ecSmrg
7705b261ecSmrg        HUGE_ROOT(pWin);
7805b261ecSmrg        SetWinSize(pWin);
7905b261ecSmrg        SetBorderSize(pWin);
8005b261ecSmrg    }
8105b261ecSmrg
8205b261ecSmrg    result = pWin->drawable.pScreen->CreateWindow(pWin);
8305b261ecSmrg
8405b261ecSmrg    if (pWin->parent) {
8505b261ecSmrg        NORMAL_ROOT(pWin);
8605b261ecSmrg    }
8705b261ecSmrg
8805b261ecSmrg    SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow);
8905b261ecSmrg
9005b261ecSmrg    return result;
9105b261ecSmrg}
9205b261ecSmrg
9305b261ecSmrg
9405b261ecSmrg/*
9505b261ecSmrg * RootlessDestroyFrame
9605b261ecSmrg *  Destroy the physical window associated with the given window.
9705b261ecSmrg */
9805b261ecSmrgstatic void
9905b261ecSmrgRootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec)
10005b261ecSmrg{
10105b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
10205b261ecSmrg
10305b261ecSmrg    SCREENREC(pScreen)->imp->DestroyFrame(winRec->wid);
10405b261ecSmrg
10505b261ecSmrg#ifdef ROOTLESS_TRACK_DAMAGE
10605b261ecSmrg    REGION_UNINIT(pScreen, &winRec->damage);
10705b261ecSmrg#endif
10805b261ecSmrg
10905b261ecSmrg    xfree(winRec);
11005b261ecSmrg    WINREC(pWin) = NULL;
11105b261ecSmrg}
11205b261ecSmrg
11305b261ecSmrg
11405b261ecSmrg/*
11505b261ecSmrg * RootlessDestroyWindow
11605b261ecSmrg *  Destroy the physical window associated with the given window.
11705b261ecSmrg */
11805b261ecSmrgBool
11905b261ecSmrgRootlessDestroyWindow(WindowPtr pWin)
12005b261ecSmrg{
12105b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
12205b261ecSmrg    Bool result;
12305b261ecSmrg
12405b261ecSmrg    if (winRec != NULL) {
12505b261ecSmrg        RootlessDestroyFrame(pWin, winRec);
12605b261ecSmrg    }
12705b261ecSmrg
12805b261ecSmrg    SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow);
12905b261ecSmrg    result = pWin->drawable.pScreen->DestroyWindow(pWin);
13005b261ecSmrg    SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow);
13105b261ecSmrg
13205b261ecSmrg    return result;
13305b261ecSmrg}
13405b261ecSmrg
13505b261ecSmrg
13605b261ecSmrg#ifdef SHAPE
13705b261ecSmrg
13805b261ecSmrgstatic Bool
13905b261ecSmrgRootlessGetShape(WindowPtr pWin, RegionPtr pShape)
14005b261ecSmrg{
14105b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
14205b261ecSmrg
14305b261ecSmrg    if (wBoundingShape(pWin) == NULL)
14405b261ecSmrg        return FALSE;
14505b261ecSmrg
14605b261ecSmrg    /* wBoundingShape is relative to *inner* origin of window.
14705b261ecSmrg       Translate by borderWidth to get the outside-relative position. */
14805b261ecSmrg
14905b261ecSmrg    REGION_NULL(pScreen, pShape);
15005b261ecSmrg    REGION_COPY(pScreen, pShape, wBoundingShape(pWin));
15105b261ecSmrg    REGION_TRANSLATE(pScreen, pShape, pWin->borderWidth, pWin->borderWidth);
15205b261ecSmrg
15305b261ecSmrg    return TRUE;
15405b261ecSmrg}
15505b261ecSmrg
15605b261ecSmrg
15705b261ecSmrg/*
15805b261ecSmrg * RootlessReshapeFrame
15905b261ecSmrg *  Set the frame shape.
16005b261ecSmrg */
16105b261ecSmrgstatic void RootlessReshapeFrame(WindowPtr pWin)
16205b261ecSmrg{
16305b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
16405b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
16505b261ecSmrg    RegionRec newShape;
16605b261ecSmrg    RegionPtr pShape;
16705b261ecSmrg
16805b261ecSmrg    // If the window is not yet framed, do nothing
16905b261ecSmrg    if (winRec == NULL)
17005b261ecSmrg        return;
17105b261ecSmrg
17205b261ecSmrg    if (IsRoot(pWin))
17305b261ecSmrg        return;
17405b261ecSmrg
17505b261ecSmrg    RootlessStopDrawing(pWin, FALSE);
17605b261ecSmrg
17705b261ecSmrg    pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL;
17805b261ecSmrg
17905b261ecSmrg#ifdef ROOTLESSDEBUG
18005b261ecSmrg    RL_DEBUG_MSG("reshaping...");
18105b261ecSmrg    if (pShape != NULL) {
18205b261ecSmrg        RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ",
18305b261ecSmrg                     REGION_NUM_RECTS(&newShape),
18405b261ecSmrg                     newShape.extents.x1, newShape.extents.y1,
18505b261ecSmrg                     newShape.extents.x2, newShape.extents.y2);
18605b261ecSmrg    } else {
18705b261ecSmrg        RL_DEBUG_MSG("no shape ");
18805b261ecSmrg    }
18905b261ecSmrg#endif
19005b261ecSmrg
19105b261ecSmrg    SCREENREC(pScreen)->imp->ReshapeFrame(winRec->wid, pShape);
19205b261ecSmrg
19305b261ecSmrg    if (pShape != NULL)
19405b261ecSmrg        REGION_UNINIT(pScreen, &newShape);
19505b261ecSmrg}
19605b261ecSmrg
19705b261ecSmrg
19805b261ecSmrg/*
19905b261ecSmrg * RootlessSetShape
20005b261ecSmrg *  Shape is usually set before a window is mapped and the window will
20105b261ecSmrg *  not have a frame associated with it. In this case, the frame will be
20205b261ecSmrg *  shaped when the window is framed.
20305b261ecSmrg */
20405b261ecSmrgvoid
20505b261ecSmrgRootlessSetShape(WindowPtr pWin)
20605b261ecSmrg{
20705b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
20805b261ecSmrg
20905b261ecSmrg    SCREEN_UNWRAP(pScreen, SetShape);
21005b261ecSmrg    pScreen->SetShape(pWin);
21105b261ecSmrg    SCREEN_WRAP(pScreen, SetShape);
21205b261ecSmrg
21305b261ecSmrg    RootlessReshapeFrame(pWin);
21405b261ecSmrg}
21505b261ecSmrg
21605b261ecSmrg#endif // SHAPE
21705b261ecSmrg
21805b261ecSmrg
21905b261ecSmrg/* Disallow ParentRelative background on top-level windows
22005b261ecSmrg   because the root window doesn't really have the right background
22105b261ecSmrg   and fb will try to draw on the root instead of on the window.
22205b261ecSmrg   ParentRelative prevention is also in PaintWindowBackground/Border()
22305b261ecSmrg   so it is no longer really needed here. */
22405b261ecSmrgBool
22505b261ecSmrgRootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask)
22605b261ecSmrg{
22705b261ecSmrg    Bool result;
22805b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
22905b261ecSmrg
23005b261ecSmrg    RL_DEBUG_MSG("change window attributes start ");
23105b261ecSmrg
23205b261ecSmrg    SCREEN_UNWRAP(pScreen, ChangeWindowAttributes);
23305b261ecSmrg    result = pScreen->ChangeWindowAttributes(pWin, vmask);
23405b261ecSmrg    SCREEN_WRAP(pScreen, ChangeWindowAttributes);
23505b261ecSmrg
23605b261ecSmrg    if (WINREC(pWin)) {
23705b261ecSmrg        // disallow ParentRelative background state
23805b261ecSmrg        if (pWin->backgroundState == ParentRelative) {
23905b261ecSmrg            XID pixel = 0;
24005b261ecSmrg            ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
24105b261ecSmrg        }
24205b261ecSmrg    }
24305b261ecSmrg
24405b261ecSmrg    RL_DEBUG_MSG("change window attributes end\n");
24505b261ecSmrg    return result;
24605b261ecSmrg}
24705b261ecSmrg
24805b261ecSmrg
24905b261ecSmrg/*
25005b261ecSmrg * RootlessPositionWindow
25105b261ecSmrg *  This is a hook for when DIX moves or resizes a window.
25205b261ecSmrg *  Update the frame position now although the physical window is moved
25305b261ecSmrg *  in RootlessMoveWindow. (x, y) are *inside* position. After this,
25405b261ecSmrg *  mi and fb are expecting the pixmap to be at the new location.
25505b261ecSmrg */
25605b261ecSmrgBool
25705b261ecSmrgRootlessPositionWindow(WindowPtr pWin, int x, int y)
25805b261ecSmrg{
25905b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
26005b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
26105b261ecSmrg    Bool result;
26205b261ecSmrg
26305b261ecSmrg    RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y);
26405b261ecSmrg
26505b261ecSmrg    if (winRec) {
26605b261ecSmrg        if (winRec->is_drawing) {
26705b261ecSmrg            // Reset frame's pixmap and move it to the new position.
26805b261ecSmrg            int bw = wBorderWidth(pWin);
26905b261ecSmrg
27005b261ecSmrg            winRec->pixmap->devPrivate.ptr = winRec->pixelData;
27105b261ecSmrg            SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw);
27205b261ecSmrg
27305b261ecSmrg#ifdef ROOTLESS_TRACK_DAMAGE
27405b261ecSmrg            // Move damaged region to correspond to new window position
27505b261ecSmrg            if (REGION_NOTEMPTY(pScreen, &winRec->damage)) {
27605b261ecSmrg                REGION_TRANSLATE(pScreen, &winRec->damage,
27705b261ecSmrg                                 x - bw - winRec->x,
27805b261ecSmrg                                 y - bw - winRec->y);
27905b261ecSmrg            }
28005b261ecSmrg#endif
28105b261ecSmrg        }
28205b261ecSmrg    }
28305b261ecSmrg
28405b261ecSmrg    SCREEN_UNWRAP(pScreen, PositionWindow);
28505b261ecSmrg    result = pScreen->PositionWindow(pWin, x, y);
28605b261ecSmrg    SCREEN_WRAP(pScreen, PositionWindow);
28705b261ecSmrg
28805b261ecSmrg    RL_DEBUG_MSG("positionwindow end\n");
28905b261ecSmrg    return result;
29005b261ecSmrg}
29105b261ecSmrg
29205b261ecSmrg
29305b261ecSmrg/*
29405b261ecSmrg * RootlessInitializeFrame
29505b261ecSmrg *  Initialize some basic attributes of the frame. Note that winRec
29605b261ecSmrg *  may already have valid data in it, so don't overwrite anything
29705b261ecSmrg *  valuable.
29805b261ecSmrg */
29905b261ecSmrgstatic void
30005b261ecSmrgRootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec *winRec)
30105b261ecSmrg{
30205b261ecSmrg    DrawablePtr d = &pWin->drawable;
30305b261ecSmrg    int bw = wBorderWidth(pWin);
30405b261ecSmrg
30505b261ecSmrg    winRec->win = pWin;
30605b261ecSmrg
30705b261ecSmrg    winRec->x = d->x - bw;
30805b261ecSmrg    winRec->y = d->y - bw;
30905b261ecSmrg    winRec->width = d->width + 2*bw;
31005b261ecSmrg    winRec->height = d->height + 2*bw;
31105b261ecSmrg    winRec->borderWidth = bw;
31205b261ecSmrg
31305b261ecSmrg#ifdef ROOTLESS_TRACK_DAMAGE
31405b261ecSmrg    REGION_NULL(pScreen, &winRec->damage);
31505b261ecSmrg#endif
31605b261ecSmrg}
31705b261ecSmrg
31805b261ecSmrg
31905b261ecSmrg/*
32005b261ecSmrg * RootlessEnsureFrame
32105b261ecSmrg *  Make sure the given window is framed. If the window doesn't have a
32205b261ecSmrg *  physical window associated with it, attempt to create one. If that
32305b261ecSmrg *  is unsuccessful, return NULL.
32405b261ecSmrg */
32505b261ecSmrgstatic RootlessWindowRec *
32605b261ecSmrgRootlessEnsureFrame(WindowPtr pWin)
32705b261ecSmrg{
32805b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
32905b261ecSmrg    RootlessWindowRec *winRec;
33005b261ecSmrg#ifdef SHAPE
33105b261ecSmrg    RegionRec shape;
33205b261ecSmrg#endif
33305b261ecSmrg    RegionPtr pShape = NULL;
33405b261ecSmrg
33505b261ecSmrg    if (WINREC(pWin) != NULL)
33605b261ecSmrg        return WINREC(pWin);
33705b261ecSmrg
33805b261ecSmrg    if (!IsTopLevel(pWin))
33905b261ecSmrg        return NULL;
34005b261ecSmrg
34105b261ecSmrg    if (pWin->drawable.class != InputOutput)
34205b261ecSmrg        return NULL;
34305b261ecSmrg
34405b261ecSmrg    winRec = xalloc(sizeof(RootlessWindowRec));
34505b261ecSmrg
34605b261ecSmrg    if (!winRec)
34705b261ecSmrg        return NULL;
34805b261ecSmrg
34905b261ecSmrg    RootlessInitializeFrame(pWin, winRec);
35005b261ecSmrg
35105b261ecSmrg    winRec->is_drawing = FALSE;
35205b261ecSmrg    winRec->is_reorder_pending = FALSE;
35305b261ecSmrg    winRec->pixmap = NULL;
35405b261ecSmrg    winRec->wid = NULL;
35505b261ecSmrg
35605b261ecSmrg    WINREC(pWin) = winRec;
35705b261ecSmrg
35805b261ecSmrg#ifdef SHAPE
35905b261ecSmrg    // Set the frame's shape if the window is shaped
36005b261ecSmrg    if (RootlessGetShape(pWin, &shape))
36105b261ecSmrg        pShape = &shape;
36205b261ecSmrg#endif
36305b261ecSmrg
36405b261ecSmrg    RL_DEBUG_MSG("creating frame ");
36505b261ecSmrg
36605b261ecSmrg    if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen,
36705b261ecSmrg                                              winRec->x + SCREEN_TO_GLOBAL_X,
36805b261ecSmrg                                              winRec->y + SCREEN_TO_GLOBAL_Y,
36905b261ecSmrg                                              pShape))
37005b261ecSmrg    {
37105b261ecSmrg        RL_DEBUG_MSG("implementation failed to create frame!\n");
37205b261ecSmrg        xfree(winRec);
37305b261ecSmrg        WINREC(pWin) = NULL;
37405b261ecSmrg        return NULL;
37505b261ecSmrg    }
37605b261ecSmrg
37705b261ecSmrg#ifdef SHAPE
37805b261ecSmrg    if (pShape != NULL)
37905b261ecSmrg        REGION_UNINIT(pScreen, &shape);
38005b261ecSmrg#endif
38105b261ecSmrg
38205b261ecSmrg    return winRec;
38305b261ecSmrg}
38405b261ecSmrg
38505b261ecSmrg
38605b261ecSmrg/*
38705b261ecSmrg * RootlessRealizeWindow
38805b261ecSmrg *  The frame is usually created here and not in CreateWindow so that
38905b261ecSmrg *  windows do not eat memory until they are realized.
39005b261ecSmrg */
39105b261ecSmrgBool
39205b261ecSmrgRootlessRealizeWindow(WindowPtr pWin)
39305b261ecSmrg{
39405b261ecSmrg    Bool result;
39505b261ecSmrg    RegionRec saveRoot;
39605b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
39705b261ecSmrg
39805b261ecSmrg    RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin);
39905b261ecSmrg
40005b261ecSmrg    if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) {
40105b261ecSmrg        RootlessWindowRec *winRec;
40205b261ecSmrg
40305b261ecSmrg        winRec = RootlessEnsureFrame(pWin);
40405b261ecSmrg        if (winRec == NULL)
40505b261ecSmrg            return FALSE;
40605b261ecSmrg
40705b261ecSmrg        winRec->is_reorder_pending = TRUE;
40805b261ecSmrg
40905b261ecSmrg        RL_DEBUG_MSG("Top level window ");
41005b261ecSmrg
41105b261ecSmrg        // Disallow ParentRelative background state on top-level windows.
41205b261ecSmrg        // This might have been set before the window was mapped.
41305b261ecSmrg        if (pWin->backgroundState == ParentRelative) {
41405b261ecSmrg            XID pixel = 0;
41505b261ecSmrg            ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
41605b261ecSmrg        }
41705b261ecSmrg    }
41805b261ecSmrg
41905b261ecSmrg    if (!IsRoot(pWin)) HUGE_ROOT(pWin);
42005b261ecSmrg    SCREEN_UNWRAP(pScreen, RealizeWindow);
42105b261ecSmrg    result = pScreen->RealizeWindow(pWin);
42205b261ecSmrg    SCREEN_WRAP(pScreen, RealizeWindow);
42305b261ecSmrg    if (!IsRoot(pWin)) NORMAL_ROOT(pWin);
42405b261ecSmrg
42505b261ecSmrg    RL_DEBUG_MSG("realizewindow end\n");
42605b261ecSmrg    return result;
42705b261ecSmrg}
42805b261ecSmrg
42905b261ecSmrg
43005b261ecSmrg/*
43105b261ecSmrg * RootlessFrameForWindow
43205b261ecSmrg *  Returns the frame ID for the physical window displaying the given window.
43305b261ecSmrg *  If CREATE is true and the window has no frame, attempt to create one.
43405b261ecSmrg */
43505b261ecSmrgRootlessFrameID
43605b261ecSmrgRootlessFrameForWindow(WindowPtr pWin, Bool create)
43705b261ecSmrg{
43805b261ecSmrg    WindowPtr pTopWin;
43905b261ecSmrg    RootlessWindowRec *winRec;
44005b261ecSmrg
44105b261ecSmrg    pTopWin = TopLevelParent(pWin);
44205b261ecSmrg    if (pTopWin == NULL)
44305b261ecSmrg        return NULL;
44405b261ecSmrg
44505b261ecSmrg    winRec = WINREC(pTopWin);
44605b261ecSmrg
44705b261ecSmrg    if (winRec == NULL && create && pWin->drawable.class == InputOutput) {
44805b261ecSmrg        winRec = RootlessEnsureFrame(pTopWin);
44905b261ecSmrg    }
45005b261ecSmrg
45105b261ecSmrg    if (winRec == NULL)
45205b261ecSmrg        return NULL;
45305b261ecSmrg
45405b261ecSmrg    return winRec->wid;
45505b261ecSmrg}
45605b261ecSmrg
45705b261ecSmrg
45805b261ecSmrg/*
45905b261ecSmrg * RootlessUnrealizeWindow
46005b261ecSmrg *  Unmap the physical window.
46105b261ecSmrg */
46205b261ecSmrgBool
46305b261ecSmrgRootlessUnrealizeWindow(WindowPtr pWin)
46405b261ecSmrg{
46505b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
46605b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
46705b261ecSmrg    Bool result;
46805b261ecSmrg
46905b261ecSmrg    RL_DEBUG_MSG("unrealizewindow start ");
47005b261ecSmrg
47105b261ecSmrg    if (winRec) {
47205b261ecSmrg        RootlessStopDrawing(pWin, FALSE);
47305b261ecSmrg
47405b261ecSmrg        SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
47505b261ecSmrg
47605b261ecSmrg        winRec->is_reorder_pending = FALSE;
47705b261ecSmrg    }
47805b261ecSmrg
47905b261ecSmrg    SCREEN_UNWRAP(pScreen, UnrealizeWindow);
48005b261ecSmrg    result = pScreen->UnrealizeWindow(pWin);
48105b261ecSmrg    SCREEN_WRAP(pScreen, UnrealizeWindow);
48205b261ecSmrg
48305b261ecSmrg    RL_DEBUG_MSG("unrealizewindow end\n");
48405b261ecSmrg    return result;
48505b261ecSmrg}
48605b261ecSmrg
48705b261ecSmrg
48805b261ecSmrg/*
48905b261ecSmrg * RootlessReorderWindow
49005b261ecSmrg *  Reorder the frame associated with the given window so that it's
49105b261ecSmrg *  physically above the window below it in the X stacking order.
49205b261ecSmrg */
49305b261ecSmrgvoid
49405b261ecSmrgRootlessReorderWindow(WindowPtr pWin)
49505b261ecSmrg{
49605b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
49705b261ecSmrg
49805b261ecSmrg    if (winRec != NULL && !winRec->is_reorder_pending) {
49905b261ecSmrg        WindowPtr newPrevW;
50005b261ecSmrg        RootlessWindowRec *newPrev;
50105b261ecSmrg        RootlessFrameID newPrevID;
50205b261ecSmrg        ScreenPtr pScreen = pWin->drawable.pScreen;
50305b261ecSmrg
50405b261ecSmrg        /* Check if the implementation wants the frame to not be reordered
50505b261ecSmrg           even though the X11 window is restacked. This can be useful if
50605b261ecSmrg           frames are ordered-in with animation so that the reordering is not
50705b261ecSmrg           done until the animation is complete. */
50805b261ecSmrg        if (SCREENREC(pScreen)->imp->DoReorderWindow) {
50905b261ecSmrg            if (!SCREENREC(pScreen)->imp->DoReorderWindow(winRec))
51005b261ecSmrg                return;
51105b261ecSmrg        }
51205b261ecSmrg
51305b261ecSmrg        RootlessStopDrawing(pWin, FALSE);
51405b261ecSmrg
51505b261ecSmrg        /* Find the next window above this one that has a mapped frame. */
51605b261ecSmrg
51705b261ecSmrg        newPrevW = pWin->prevSib;
51805b261ecSmrg        while (newPrevW && (WINREC(newPrevW) == NULL || !newPrevW->realized))
51905b261ecSmrg            newPrevW = newPrevW->prevSib;
52005b261ecSmrg
52105b261ecSmrg        newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL;
52205b261ecSmrg        newPrevID = newPrev != NULL ? newPrev->wid : 0;
52305b261ecSmrg
52405b261ecSmrg        /* If it exists, reorder the frame above us first. */
52505b261ecSmrg
52605b261ecSmrg        if (newPrev && newPrev->is_reorder_pending) {
52705b261ecSmrg            newPrev->is_reorder_pending = FALSE;
52805b261ecSmrg            RootlessReorderWindow(newPrevW);
52905b261ecSmrg        }
53005b261ecSmrg
53105b261ecSmrg        SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID);
53205b261ecSmrg    }
53305b261ecSmrg}
53405b261ecSmrg
53505b261ecSmrg
53605b261ecSmrg/*
53705b261ecSmrg * RootlessRestackWindow
53805b261ecSmrg *  This is a hook for when DIX changes the window stacking order.
53905b261ecSmrg *  The window has already been inserted into its new position in the
54005b261ecSmrg *  DIX window stack. We need to change the order of the physical
54105b261ecSmrg *  window to match.
54205b261ecSmrg */
54305b261ecSmrgvoid
54405b261ecSmrgRootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib)
54505b261ecSmrg{
54605b261ecSmrg    RegionRec saveRoot;
54705b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
54805b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
54905b261ecSmrg
55005b261ecSmrg    RL_DEBUG_MSG("restackwindow start ");
55105b261ecSmrg    if (winRec)
55205b261ecSmrg        RL_DEBUG_MSG("restack top level \n");
55305b261ecSmrg
55405b261ecSmrg    HUGE_ROOT(pWin);
55505b261ecSmrg    SCREEN_UNWRAP(pScreen, RestackWindow);
55605b261ecSmrg
55705b261ecSmrg    if (pScreen->RestackWindow)
55805b261ecSmrg        pScreen->RestackWindow(pWin, pOldNextSib);
55905b261ecSmrg
56005b261ecSmrg    SCREEN_WRAP(pScreen, RestackWindow);
56105b261ecSmrg    NORMAL_ROOT(pWin);
56205b261ecSmrg
56305b261ecSmrg    if (winRec && pWin->viewable) {
56405b261ecSmrg        RootlessReorderWindow(pWin);
56505b261ecSmrg    }
56605b261ecSmrg
56705b261ecSmrg    RL_DEBUG_MSG("restackwindow end\n");
56805b261ecSmrg}
56905b261ecSmrg
57005b261ecSmrg
57105b261ecSmrg/*
57205b261ecSmrg * Specialized window copy procedures
57305b261ecSmrg */
57405b261ecSmrg
57505b261ecSmrg// Globals needed during window resize and move.
57605b261ecSmrgstatic pointer gResizeDeathBits = NULL;
57705b261ecSmrgstatic int gResizeDeathCount = 0;
57805b261ecSmrgstatic PixmapPtr gResizeDeathPix[2] = {NULL, NULL};
57905b261ecSmrgstatic BoxRec gResizeDeathBounds[2];
58005b261ecSmrgstatic CopyWindowProcPtr gResizeOldCopyWindowProc = NULL;
58105b261ecSmrg
58205b261ecSmrg/*
58305b261ecSmrg * RootlessNoCopyWindow
58405b261ecSmrg *  CopyWindow() that doesn't do anything. For MoveWindow() of
58505b261ecSmrg *  top-level windows.
58605b261ecSmrg */
58705b261ecSmrgstatic void
58805b261ecSmrgRootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
58905b261ecSmrg                     RegionPtr prgnSrc)
59005b261ecSmrg{
59105b261ecSmrg    // some code expects the region to be translated
59205b261ecSmrg    int dx = ptOldOrg.x - pWin->drawable.x;
59305b261ecSmrg    int dy = ptOldOrg.y - pWin->drawable.y;
59405b261ecSmrg
59505b261ecSmrg    RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW ");
59605b261ecSmrg
59705b261ecSmrg    REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
59805b261ecSmrg}
59905b261ecSmrg
60005b261ecSmrg
60105b261ecSmrg/*
60205b261ecSmrg * RootlessResizeCopyWindow
60305b261ecSmrg *  CopyWindow used during ResizeWindow for gravity moves. Based on
60405b261ecSmrg *  fbCopyWindow. The original always draws on the root pixmap, which
60505b261ecSmrg *  we don't have. Instead, draw on the parent window's pixmap.
60605b261ecSmrg *  Resize version: the old location's pixels are in gResizeCopyWindowSource.
60705b261ecSmrg */
60805b261ecSmrgstatic void
60905b261ecSmrgRootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
61005b261ecSmrg                         RegionPtr prgnSrc)
61105b261ecSmrg{
61205b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
61305b261ecSmrg    RegionRec   rgnDst;
61405b261ecSmrg    int         dx, dy;
61505b261ecSmrg
61605b261ecSmrg    RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin);
61705b261ecSmrg
61805b261ecSmrg    /* Don't unwrap pScreen->CopyWindow.
61905b261ecSmrg       The bogus rewrap with RootlessCopyWindow causes a crash if
62005b261ecSmrg       CopyWindow is called again during the same resize. */
62105b261ecSmrg
62205b261ecSmrg    if (gResizeDeathCount == 0)
62305b261ecSmrg        return;
62405b261ecSmrg
62505b261ecSmrg    RootlessStartDrawing(pWin);
62605b261ecSmrg
62705b261ecSmrg    dx = ptOldOrg.x - pWin->drawable.x;
62805b261ecSmrg    dy = ptOldOrg.y - pWin->drawable.y;
62905b261ecSmrg    REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);
63005b261ecSmrg    REGION_NULL(pScreen, &rgnDst);
63105b261ecSmrg    REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
63205b261ecSmrg
63305b261ecSmrg    if (gResizeDeathCount == 1) {
63405b261ecSmrg        /* Simple case, we only have a single source pixmap. */
63505b261ecSmrg
63605b261ecSmrg        fbCopyRegion(&gResizeDeathPix[0]->drawable,
63705b261ecSmrg                     &pScreen->GetWindowPixmap(pWin)->drawable, 0,
63805b261ecSmrg                     &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
63905b261ecSmrg    }
64005b261ecSmrg    else {
64105b261ecSmrg        int i;
64205b261ecSmrg        RegionRec clip, clipped;
64305b261ecSmrg
64405b261ecSmrg        /* More complex case, N source pixmaps (usually two). So we
64505b261ecSmrg           intersect the destination with each source and copy those bits. */
64605b261ecSmrg
64705b261ecSmrg        for (i = 0; i < gResizeDeathCount; i++) {
64805b261ecSmrg            REGION_INIT(pScreen, &clip, gResizeDeathBounds + 0, 1);
64905b261ecSmrg            REGION_NULL(pScreen, &clipped);
65005b261ecSmrg            REGION_INTERSECT(pScreen, &rgnDst, &clip, &clipped);
65105b261ecSmrg
65205b261ecSmrg            fbCopyRegion(&gResizeDeathPix[i]->drawable,
65305b261ecSmrg                         &pScreen->GetWindowPixmap(pWin)->drawable, 0,
65405b261ecSmrg                         &clipped, dx, dy, fbCopyWindowProc, 0, 0);
65505b261ecSmrg
65605b261ecSmrg            REGION_UNINIT(pScreen, &clipped);
65705b261ecSmrg            REGION_UNINIT(pScreen, &clip);
65805b261ecSmrg        }
65905b261ecSmrg    }
66005b261ecSmrg
66105b261ecSmrg    /* Don't update - resize will update everything */
66205b261ecSmrg    REGION_UNINIT(pScreen, &rgnDst);
66305b261ecSmrg
66405b261ecSmrg    fbValidateDrawable(&pWin->drawable);
66505b261ecSmrg
66605b261ecSmrg    RL_DEBUG_MSG("resizecopywindowFB end\n");
66705b261ecSmrg}
66805b261ecSmrg
66905b261ecSmrg
67005b261ecSmrg/*
67105b261ecSmrg * RootlessCopyWindow
67205b261ecSmrg *  Update *new* location of window. Old location is redrawn with
67305b261ecSmrg *  PaintWindowBackground/Border. Cloned from fbCopyWindow.
67405b261ecSmrg *  The original always draws on the root pixmap, which we don't have.
67505b261ecSmrg *  Instead, draw on the parent window's pixmap.
67605b261ecSmrg */
67705b261ecSmrgvoid
67805b261ecSmrgRootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
67905b261ecSmrg{
68005b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
68105b261ecSmrg    RegionRec   rgnDst;
68205b261ecSmrg    int         dx, dy;
68305b261ecSmrg    BoxPtr extents;
68405b261ecSmrg    int area;
68505b261ecSmrg
68605b261ecSmrg    RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin);
68705b261ecSmrg
68805b261ecSmrg    SCREEN_UNWRAP(pScreen, CopyWindow);
68905b261ecSmrg
69005b261ecSmrg    dx = ptOldOrg.x - pWin->drawable.x;
69105b261ecSmrg    dy = ptOldOrg.y - pWin->drawable.y;
69205b261ecSmrg    REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);
69305b261ecSmrg
69405b261ecSmrg    REGION_NULL(pScreen, &rgnDst);
69505b261ecSmrg    REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
69605b261ecSmrg
69705b261ecSmrg    extents = REGION_EXTENTS(pScreen, &rgnDst);
69805b261ecSmrg    area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1);
69905b261ecSmrg
70005b261ecSmrg    /* If the area exceeds threshold, use the implementation's
70105b261ecSmrg       accelerated version. */
70205b261ecSmrg    if (area > rootless_CopyWindow_threshold &&
70305b261ecSmrg        SCREENREC(pScreen)->imp->CopyWindow)
70405b261ecSmrg    {
70505b261ecSmrg        RootlessWindowRec *winRec;
70605b261ecSmrg        WindowPtr top;
70705b261ecSmrg
70805b261ecSmrg        top = TopLevelParent(pWin);
70905b261ecSmrg        if (top == NULL) {
71005b261ecSmrg            RL_DEBUG_MSG("no parent\n");
71105b261ecSmrg            return;
71205b261ecSmrg        }
71305b261ecSmrg
71405b261ecSmrg        winRec = WINREC(top);
71505b261ecSmrg        if (winRec == NULL) {
71605b261ecSmrg            RL_DEBUG_MSG("not framed\n");
71705b261ecSmrg            return;
71805b261ecSmrg        }
71905b261ecSmrg
72005b261ecSmrg        /* Move region to window local coords */
72105b261ecSmrg        REGION_TRANSLATE(pScreen, &rgnDst, -winRec->x, -winRec->y);
72205b261ecSmrg
72305b261ecSmrg        RootlessStopDrawing(pWin, FALSE);
72405b261ecSmrg
72505b261ecSmrg        SCREENREC(pScreen)->imp->CopyWindow(winRec->wid,
72605b261ecSmrg                                            REGION_NUM_RECTS(&rgnDst),
72705b261ecSmrg                                            REGION_RECTS(&rgnDst),
72805b261ecSmrg                                            dx, dy);
72905b261ecSmrg    }
73005b261ecSmrg    else {
73105b261ecSmrg        RootlessStartDrawing(pWin);
73205b261ecSmrg
73305b261ecSmrg        fbCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin,
73405b261ecSmrg                     0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
73505b261ecSmrg
73605b261ecSmrg        /* prgnSrc has been translated to dst position */
73705b261ecSmrg        RootlessDamageRegion(pWin, prgnSrc);
73805b261ecSmrg    }
73905b261ecSmrg
74005b261ecSmrg    REGION_UNINIT(pScreen, &rgnDst);
74105b261ecSmrg    fbValidateDrawable(&pWin->drawable);
74205b261ecSmrg
74305b261ecSmrg    SCREEN_WRAP(pScreen, CopyWindow);
74405b261ecSmrg
74505b261ecSmrg    RL_DEBUG_MSG("copywindowFB end\n");
74605b261ecSmrg}
74705b261ecSmrg
74805b261ecSmrg
74905b261ecSmrg/*
75005b261ecSmrg * Window resize procedures
75105b261ecSmrg */
75205b261ecSmrg
75305b261ecSmrgenum {
75405b261ecSmrg    WIDTH_SMALLER = 1,
75505b261ecSmrg    HEIGHT_SMALLER = 2,
75605b261ecSmrg};
75705b261ecSmrg
75805b261ecSmrg
75905b261ecSmrg/*
76005b261ecSmrg * ResizeWeighting
76105b261ecSmrg *  Choose gravity to avoid local copies. Do that by looking for
76205b261ecSmrg *  a corner that doesn't move _relative to the screen_.
76305b261ecSmrg */
76405b261ecSmrgstatic inline unsigned int
76505b261ecSmrgResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
76605b261ecSmrg                int newX1, int newY1, int newX2, int newY2, int newBW)
76705b261ecSmrg{
76805b261ecSmrg#ifdef ROOTLESS_RESIZE_GRAVITY
76905b261ecSmrg    if (newBW != oldBW)
77005b261ecSmrg        return RL_GRAVITY_NONE;
77105b261ecSmrg
77205b261ecSmrg    if (newX1 == oldX1 && newY1 == oldY1)
77305b261ecSmrg        return RL_GRAVITY_NORTH_WEST;
77405b261ecSmrg    else if (newX1 == oldX1 && newY2 == oldY2)
77505b261ecSmrg        return RL_GRAVITY_SOUTH_WEST;
77605b261ecSmrg    else if (newX2 == oldX2 && newY2 == oldY2)
77705b261ecSmrg        return RL_GRAVITY_SOUTH_EAST;
77805b261ecSmrg    else if (newX2 == oldX2 && newY1 == oldY1)
77905b261ecSmrg        return RL_GRAVITY_NORTH_EAST;
78005b261ecSmrg    else
78105b261ecSmrg        return RL_GRAVITY_NONE;
78205b261ecSmrg#else
78305b261ecSmrg    return RL_GRAVITY_NONE;
78405b261ecSmrg#endif
78505b261ecSmrg}
78605b261ecSmrg
78705b261ecSmrg
78805b261ecSmrg/*
78905b261ecSmrg * StartFrameResize
79005b261ecSmrg *  Prepare to resize a top-level window. The old window's pixels are
79105b261ecSmrg *  saved and the implementation is told to change the window size.
79205b261ecSmrg *  (x,y,w,h) is outer frame of window (outside border)
79305b261ecSmrg */
79405b261ecSmrgstatic Bool
79505b261ecSmrgStartFrameResize(WindowPtr pWin, Bool gravity,
79605b261ecSmrg                 int oldX, int oldY, int oldW, int oldH, int oldBW,
79705b261ecSmrg                 int newX, int newY, int newW, int newH, int newBW)
79805b261ecSmrg{
79905b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
80005b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
80105b261ecSmrg    Bool need_window_source = FALSE, resize_after = FALSE;
80205b261ecSmrg
80305b261ecSmrg    BoxRec rect;
80405b261ecSmrg    int oldX2, newX2;
80505b261ecSmrg    int oldY2, newY2;
80605b261ecSmrg    unsigned int weight;
80705b261ecSmrg
80805b261ecSmrg    oldX2 = oldX + oldW, newX2 = newX + newW;
80905b261ecSmrg    oldY2 = oldY + oldH, newY2 = newY + newH;
81005b261ecSmrg
81105b261ecSmrg    /* Decide which resize weighting to use */
81205b261ecSmrg    weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
81305b261ecSmrg                             newX, newY, newW, newH, newBW);
81405b261ecSmrg
81505b261ecSmrg    /* Compute intersection between old and new rects */
81605b261ecSmrg    rect.x1 = max(oldX, newX);
81705b261ecSmrg    rect.y1 = max(oldY, newY);
81805b261ecSmrg    rect.x2 = min(oldX2, newX2);
81905b261ecSmrg    rect.y2 = min(oldY2, newY2);
82005b261ecSmrg
82105b261ecSmrg    RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
82205b261ecSmrg    RL_DEBUG_MSG("%d %d %d %d %d   %d %d %d %d %d\n",
82305b261ecSmrg                 oldX, oldY, oldW, oldH, oldBW,
82405b261ecSmrg                 newX, newY, newW, newH, newBW);
82505b261ecSmrg
82605b261ecSmrg    RootlessRedisplay(pWin);
82705b261ecSmrg
82805b261ecSmrg    /* If gravity is true, then we need to have a way of recovering all
82905b261ecSmrg       the original bits in the window for when X rearranges the contents
83005b261ecSmrg       based on the various gravity settings. The obvious way is to just
83105b261ecSmrg       snapshot the entire backing store before resizing it, but that
83205b261ecSmrg       it slow on large windows.
83305b261ecSmrg
83405b261ecSmrg       So the optimization here is to use the implementation's resize
83505b261ecSmrg       weighting options (if available) to allow us to reason about what
83605b261ecSmrg       is left in the backing store after the resize. We can then only
83705b261ecSmrg       copy what won't be there after the resize, and do a two-stage copy
83805b261ecSmrg       operation.
83905b261ecSmrg
84005b261ecSmrg       Most of these optimizations are only applied when the top-left
84105b261ecSmrg       corner of the window is fixed, since that's the common case. They
84205b261ecSmrg       could probably be extended with some thought. */
84305b261ecSmrg
84405b261ecSmrg    gResizeDeathCount = 0;
84505b261ecSmrg
84605b261ecSmrg    if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
84705b261ecSmrg        unsigned int code = 0;
84805b261ecSmrg
84905b261ecSmrg        /* Top left corner is anchored. We never need to copy the
85005b261ecSmrg           entire window. */
85105b261ecSmrg
85205b261ecSmrg        need_window_source = TRUE;
85305b261ecSmrg
85405b261ecSmrg        /* These comparisons were chosen to avoid setting bits when the sizes
85505b261ecSmrg        are the same. (So the fastest case automatically gets taken when
85605b261ecSmrg        dimensions are unchanging.) */
85705b261ecSmrg
85805b261ecSmrg        if (newW < oldW)
85905b261ecSmrg            code |= WIDTH_SMALLER;
86005b261ecSmrg        if (newH < oldH)
86105b261ecSmrg            code |= HEIGHT_SMALLER;
86205b261ecSmrg
86305b261ecSmrg        if (((code ^ (code >> 1)) & 1) == 0) {
86405b261ecSmrg            /* Both dimensions are either getting larger, or both
86505b261ecSmrg               are getting smaller. No need to copy anything. */
86605b261ecSmrg
86705b261ecSmrg            if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) {
86805b261ecSmrg                /* Since the window is getting smaller, we can do gravity
86905b261ecSmrg                   repair on it with it's current size, then resize it
87005b261ecSmrg                   afterwards. */
87105b261ecSmrg
87205b261ecSmrg                resize_after = TRUE;
87305b261ecSmrg            }
87405b261ecSmrg
87505b261ecSmrg            gResizeDeathCount = 1;
87605b261ecSmrg        }
87705b261ecSmrg        else {
87805b261ecSmrg            unsigned int copy_rowbytes, Bpp;
87905b261ecSmrg            unsigned int copy_rect_width, copy_rect_height;
88005b261ecSmrg            BoxRec copy_rect;
88105b261ecSmrg
88205b261ecSmrg            /* We can get away with a partial copy. 'rect' is the
88305b261ecSmrg               intersection between old and new bounds, so copy
88405b261ecSmrg               everything to the right of or below the intersection. */
88505b261ecSmrg
88605b261ecSmrg            RootlessStartDrawing(pWin);
88705b261ecSmrg
88805b261ecSmrg            if (code == WIDTH_SMALLER) {
88905b261ecSmrg                copy_rect.x1 = rect.x2;
89005b261ecSmrg                copy_rect.y1 = rect.y1;
89105b261ecSmrg                copy_rect.x2 = oldX2;
89205b261ecSmrg                copy_rect.y2 = oldY2;
89305b261ecSmrg            }
89405b261ecSmrg            else if (code == HEIGHT_SMALLER) {
89505b261ecSmrg                copy_rect.x1 = rect.x1;
89605b261ecSmrg                copy_rect.y1 = rect.y2;
89705b261ecSmrg                copy_rect.x2 = oldX2;
89805b261ecSmrg                copy_rect.y2 = oldY2;
89905b261ecSmrg            }
90005b261ecSmrg            else
90105b261ecSmrg                abort();
90205b261ecSmrg
90305b261ecSmrg            Bpp = winRec->win->drawable.bitsPerPixel / 8;
90405b261ecSmrg            copy_rect_width = copy_rect.x2 - copy_rect.x1;
90505b261ecSmrg            copy_rect_height = copy_rect.y2 - copy_rect.y1;
90605b261ecSmrg            copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31;
90705b261ecSmrg            gResizeDeathBits = xalloc(copy_rowbytes
90805b261ecSmrg                                      * copy_rect_height);
90905b261ecSmrg
91005b261ecSmrg            if (copy_rect_width * copy_rect_height >
91105b261ecSmrg                        rootless_CopyBytes_threshold &&
91205b261ecSmrg                SCREENREC(pScreen)->imp->CopyBytes)
91305b261ecSmrg            {
91405b261ecSmrg                SCREENREC(pScreen)->imp->CopyBytes(
91505b261ecSmrg                    copy_rect_width * Bpp, copy_rect_height,
91605b261ecSmrg                    ((char *) winRec->pixelData)
91705b261ecSmrg                    + ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
91805b261ecSmrg                    + (copy_rect.x1 - oldX) * Bpp, winRec->bytesPerRow,
91905b261ecSmrg                    gResizeDeathBits, copy_rowbytes);
92005b261ecSmrg            } else {
92105b261ecSmrg                fbBlt((FbBits *) (winRec->pixelData
92205b261ecSmrg                      + ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
92305b261ecSmrg                      + (copy_rect.x1 - oldX) * Bpp),
92405b261ecSmrg                      winRec->bytesPerRow / sizeof(FbBits), 0,
92505b261ecSmrg                      (FbBits *) gResizeDeathBits,
92605b261ecSmrg                      copy_rowbytes / sizeof(FbBits), 0,
92705b261ecSmrg                      copy_rect_width * Bpp, copy_rect_height,
92805b261ecSmrg                      GXcopy, FB_ALLONES, Bpp, 0, 0);
92905b261ecSmrg            }
93005b261ecSmrg
93105b261ecSmrg            gResizeDeathBounds[1] = copy_rect;
93205b261ecSmrg            gResizeDeathPix[1]
93305b261ecSmrg                = GetScratchPixmapHeader(pScreen, copy_rect_width,
93405b261ecSmrg                                         copy_rect_height,
93505b261ecSmrg                                         winRec->win->drawable.depth,
93605b261ecSmrg                                         winRec->win->drawable.bitsPerPixel,
93705b261ecSmrg                                         winRec->bytesPerRow,
93805b261ecSmrg                                         (void *) gResizeDeathBits);
93905b261ecSmrg
94005b261ecSmrg            SetPixmapBaseToScreen(gResizeDeathPix[1],
94105b261ecSmrg                                  copy_rect.x1, copy_rect.y1);
94205b261ecSmrg
94305b261ecSmrg            gResizeDeathCount = 2;
94405b261ecSmrg        }
94505b261ecSmrg    }
94605b261ecSmrg    else if (gravity) {
94705b261ecSmrg        /* The general case. Just copy everything. */
94805b261ecSmrg
94905b261ecSmrg        RootlessStartDrawing(pWin);
95005b261ecSmrg
95105b261ecSmrg        gResizeDeathBits = xalloc(winRec->bytesPerRow * winRec->height);
95205b261ecSmrg
95305b261ecSmrg        memcpy(gResizeDeathBits, winRec->pixelData,
95405b261ecSmrg               winRec->bytesPerRow * winRec->height);
95505b261ecSmrg
95605b261ecSmrg        gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
95705b261ecSmrg        gResizeDeathPix[0]
95805b261ecSmrg            = GetScratchPixmapHeader(pScreen, winRec->width,
95905b261ecSmrg                                     winRec->height,
96005b261ecSmrg                                     winRec->win->drawable.depth,
96105b261ecSmrg                                     winRec->win->drawable.bitsPerPixel,
96205b261ecSmrg                                     winRec->bytesPerRow,
96305b261ecSmrg                                     (void *) gResizeDeathBits);
96405b261ecSmrg
96505b261ecSmrg        SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
96605b261ecSmrg        gResizeDeathCount = 1;
96705b261ecSmrg    }
96805b261ecSmrg
96905b261ecSmrg    RootlessStopDrawing(pWin, FALSE);
97005b261ecSmrg
97105b261ecSmrg    winRec->x = newX;
97205b261ecSmrg    winRec->y = newY;
97305b261ecSmrg    winRec->width = newW;
97405b261ecSmrg    winRec->height = newH;
97505b261ecSmrg    winRec->borderWidth = newBW;
97605b261ecSmrg
97705b261ecSmrg    /* Unless both dimensions are getting smaller, Resize the frame
97805b261ecSmrg       before doing gravity repair */
97905b261ecSmrg
98005b261ecSmrg    if (!resize_after) {
98105b261ecSmrg        SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
98205b261ecSmrg                                             newX + SCREEN_TO_GLOBAL_X,
98305b261ecSmrg                                             newY + SCREEN_TO_GLOBAL_Y,
98405b261ecSmrg                                             newW, newH, weight);
98505b261ecSmrg    }
98605b261ecSmrg
98705b261ecSmrg    RootlessStartDrawing(pWin);
98805b261ecSmrg
98905b261ecSmrg    /* If necessary, create a source pixmap pointing at the current
99005b261ecSmrg       window bits. */
99105b261ecSmrg
99205b261ecSmrg    if (need_window_source) {
99305b261ecSmrg        gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
99405b261ecSmrg        gResizeDeathPix[0]
99505b261ecSmrg            = GetScratchPixmapHeader(pScreen, oldW, oldH,
99605b261ecSmrg                                     winRec->win->drawable.depth,
99705b261ecSmrg                                     winRec->win->drawable.bitsPerPixel,
99805b261ecSmrg                                     winRec->bytesPerRow, winRec->pixelData);
99905b261ecSmrg
100005b261ecSmrg        SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
100105b261ecSmrg    }
100205b261ecSmrg
100305b261ecSmrg    /* Use custom CopyWindow when moving gravity bits around
100405b261ecSmrg       ResizeWindow assumes the old window contents are in the same
100505b261ecSmrg       pixmap, but here they're in deathPix instead. */
100605b261ecSmrg
100705b261ecSmrg    if (gravity) {
100805b261ecSmrg        gResizeOldCopyWindowProc = pScreen->CopyWindow;
100905b261ecSmrg        pScreen->CopyWindow = RootlessResizeCopyWindow;
101005b261ecSmrg    }
101105b261ecSmrg
101205b261ecSmrg    /* If we can't rely on the window server preserving the bits we
101305b261ecSmrg       need in the position we need, copy the pixels in the
101405b261ecSmrg       intersection from src to dst. ResizeWindow assumes these pixels
101505b261ecSmrg       are already present when making gravity adjustments. pWin
101605b261ecSmrg       currently has new-sized pixmap but is in old position.
101705b261ecSmrg
101805b261ecSmrg       FIXME: border width change! (?) */
101905b261ecSmrg
102005b261ecSmrg    if (gravity && weight == RL_GRAVITY_NONE) {
102105b261ecSmrg        PixmapPtr src, dst;
102205b261ecSmrg
102305b261ecSmrg        assert(gResizeDeathCount == 1);
102405b261ecSmrg
102505b261ecSmrg        src = gResizeDeathPix[0];
102605b261ecSmrg        dst = pScreen->GetWindowPixmap(pWin);
102705b261ecSmrg
102805b261ecSmrg        RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
102905b261ecSmrg                     rect.x1, rect.y1, rect.x2, rect.y2);
103005b261ecSmrg
103105b261ecSmrg        /* rect is the intersection of the old location and new location */
103205b261ecSmrg        if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) {
103305b261ecSmrg            /* The window drawable still has the old frame position, which
103405b261ecSmrg               means that DST doesn't actually point at the origin of our
103505b261ecSmrg               physical backing store when adjusted by the drawable.x,y
103605b261ecSmrg               position. So sneakily adjust it temporarily while copying.. */
103705b261ecSmrg
103805b261ecSmrg            ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
103905b261ecSmrg            SetPixmapBaseToScreen(dst, newX, newY);
104005b261ecSmrg
104105b261ecSmrg            fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
104205b261ecSmrg                             &rect, 1, 0, 0, FALSE, FALSE, 0, 0);
104305b261ecSmrg
104405b261ecSmrg            ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
104505b261ecSmrg            SetPixmapBaseToScreen(dst, oldX, oldY);
104605b261ecSmrg        }
104705b261ecSmrg    }
104805b261ecSmrg
104905b261ecSmrg    return resize_after;
105005b261ecSmrg}
105105b261ecSmrg
105205b261ecSmrg
105305b261ecSmrgstatic void
105405b261ecSmrgFinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY,
105505b261ecSmrg                  unsigned int oldW, unsigned int oldH, unsigned int oldBW,
105605b261ecSmrg                  int newX, int newY, unsigned int newW, unsigned int newH,
105705b261ecSmrg                  unsigned int newBW, Bool resize_now)
105805b261ecSmrg{
105905b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
106005b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
106105b261ecSmrg    int i;
106205b261ecSmrg
106305b261ecSmrg    RootlessStopDrawing(pWin, FALSE);
106405b261ecSmrg
106505b261ecSmrg    if (resize_now) {
106605b261ecSmrg        unsigned int weight;
106705b261ecSmrg
106805b261ecSmrg        /* We didn't resize anything earlier, so do it now, now that
106905b261ecSmrg           we've finished gravitating the bits. */
107005b261ecSmrg
107105b261ecSmrg        weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
107205b261ecSmrg                                 newX, newY, newW, newH, newBW);
107305b261ecSmrg
107405b261ecSmrg        SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
107505b261ecSmrg                                             newX + SCREEN_TO_GLOBAL_X,
107605b261ecSmrg                                             newY + SCREEN_TO_GLOBAL_Y,
107705b261ecSmrg                                             newW, newH, weight);
107805b261ecSmrg    }
107905b261ecSmrg
108005b261ecSmrg    /* Redraw everything. FIXME: there must be times when we don't need
108105b261ecSmrg       to do this. Perhaps when top-left weighting and no gravity? */
108205b261ecSmrg
108305b261ecSmrg    RootlessDamageRect(pWin, -newBW, -newBW, newW, newH);
108405b261ecSmrg
108505b261ecSmrg    for (i = 0; i < 2; i++) {
108605b261ecSmrg        if (gResizeDeathPix[i] != NULL) {
108705b261ecSmrg            FreeScratchPixmapHeader(gResizeDeathPix[i]);
108805b261ecSmrg            gResizeDeathPix[i] = NULL;
108905b261ecSmrg        }
109005b261ecSmrg    }
109105b261ecSmrg
109205b261ecSmrg    if (gResizeDeathBits != NULL) {
109305b261ecSmrg        xfree(gResizeDeathBits);
109405b261ecSmrg        gResizeDeathBits = NULL;
109505b261ecSmrg    }
109605b261ecSmrg
109705b261ecSmrg    if (gravity) {
109805b261ecSmrg        pScreen->CopyWindow = gResizeOldCopyWindowProc;
109905b261ecSmrg    }
110005b261ecSmrg}
110105b261ecSmrg
110205b261ecSmrg
110305b261ecSmrg/*
110405b261ecSmrg * RootlessMoveWindow
110505b261ecSmrg *  If kind==VTOther, window border is resizing (and borderWidth is
110605b261ecSmrg *  already changed!!@#$)  This case works like window resize, not move.
110705b261ecSmrg */
110805b261ecSmrgvoid
110905b261ecSmrgRootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
111005b261ecSmrg{
111105b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
111205b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
111305b261ecSmrg    CopyWindowProcPtr oldCopyWindowProc = NULL;
111405b261ecSmrg    int oldX = 0, oldY = 0, newX = 0, newY = 0;
111505b261ecSmrg    unsigned int oldW = 0, oldH = 0, oldBW = 0;
111605b261ecSmrg    unsigned int newW = 0, newH = 0, newBW = 0;
111705b261ecSmrg    Bool resize_after = FALSE;
111805b261ecSmrg    RegionRec saveRoot;
111905b261ecSmrg
112005b261ecSmrg    RL_DEBUG_MSG("movewindow start \n");
112105b261ecSmrg
112205b261ecSmrg    if (winRec) {
112305b261ecSmrg        if (kind == VTMove) {
112405b261ecSmrg            oldX = winRec->x;
112505b261ecSmrg            oldY = winRec->y;
112605b261ecSmrg            RootlessRedisplay(pWin);
112705b261ecSmrg            RootlessStartDrawing(pWin);
112805b261ecSmrg        } else {
112905b261ecSmrg            RL_DEBUG_MSG("movewindow border resizing ");
113005b261ecSmrg
113105b261ecSmrg            oldBW = winRec->borderWidth;
113205b261ecSmrg            oldX = winRec->x;
113305b261ecSmrg            oldY = winRec->y;
113405b261ecSmrg            oldW = winRec->width;
113505b261ecSmrg            oldH = winRec->height;
113605b261ecSmrg
113705b261ecSmrg            newBW = wBorderWidth(pWin);
113805b261ecSmrg            newX = x;
113905b261ecSmrg            newY = y;
114005b261ecSmrg            newW = pWin->drawable.width  + 2*newBW;
114105b261ecSmrg            newH = pWin->drawable.height + 2*newBW;
114205b261ecSmrg
114305b261ecSmrg            resize_after = StartFrameResize(pWin, FALSE,
114405b261ecSmrg                                            oldX, oldY, oldW, oldH, oldBW,
114505b261ecSmrg                                            newX, newY, newW, newH, newBW);
114605b261ecSmrg        }
114705b261ecSmrg    }
114805b261ecSmrg
114905b261ecSmrg    HUGE_ROOT(pWin);
115005b261ecSmrg    SCREEN_UNWRAP(pScreen, MoveWindow);
115105b261ecSmrg
115205b261ecSmrg    if (winRec) {
115305b261ecSmrg        oldCopyWindowProc = pScreen->CopyWindow;
115405b261ecSmrg        pScreen->CopyWindow = RootlessNoCopyWindow;
115505b261ecSmrg    }
115605b261ecSmrg    pScreen->MoveWindow(pWin, x, y, pSib, kind);
115705b261ecSmrg    if (winRec) {
115805b261ecSmrg        pScreen->CopyWindow = oldCopyWindowProc;
115905b261ecSmrg    }
116005b261ecSmrg
116105b261ecSmrg    NORMAL_ROOT(pWin);
116205b261ecSmrg    SCREEN_WRAP(pScreen, MoveWindow);
116305b261ecSmrg
116405b261ecSmrg    if (winRec) {
116505b261ecSmrg        if (kind == VTMove) {
116605b261ecSmrg            winRec->x = x;
116705b261ecSmrg            winRec->y = y;
116805b261ecSmrg            RootlessStopDrawing(pWin, FALSE);
116905b261ecSmrg            SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
117005b261ecSmrg                                               x + SCREEN_TO_GLOBAL_X,
117105b261ecSmrg                                               y + SCREEN_TO_GLOBAL_Y);
117205b261ecSmrg        } else {
117305b261ecSmrg            FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
117405b261ecSmrg                              newX, newY, newW, newH, newBW, resize_after);
117505b261ecSmrg        }
117605b261ecSmrg    }
117705b261ecSmrg
117805b261ecSmrg    RL_DEBUG_MSG("movewindow end\n");
117905b261ecSmrg}
118005b261ecSmrg
118105b261ecSmrg
118205b261ecSmrg/*
118305b261ecSmrg * RootlessResizeWindow
118405b261ecSmrg *  Note: (x, y, w, h) as passed to this procedure don't match the frame
118505b261ecSmrg *  definition. (x,y) is corner of very outer edge, *outside* border.
118605b261ecSmrg *  w,h is width and height *inside* border, *ignoring* border width.
118705b261ecSmrg *  The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw)
118805b261ecSmrg *  is total rect and (x+bw, y+bw, w, h) is inner rect.
118905b261ecSmrg */
119005b261ecSmrgvoid
119105b261ecSmrgRootlessResizeWindow(WindowPtr pWin, int x, int y,
119205b261ecSmrg                     unsigned int w, unsigned int h, WindowPtr pSib)
119305b261ecSmrg{
119405b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
119505b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
119605b261ecSmrg    int oldX = 0, oldY = 0, newX = 0, newY = 0;
119705b261ecSmrg    unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0;
119805b261ecSmrg    Bool resize_after = FALSE;
119905b261ecSmrg    RegionRec saveRoot;
120005b261ecSmrg
120105b261ecSmrg    RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin);
120205b261ecSmrg
120305b261ecSmrg    if (winRec) {
120405b261ecSmrg        oldBW = winRec->borderWidth;
120505b261ecSmrg        oldX = winRec->x;
120605b261ecSmrg        oldY = winRec->y;
120705b261ecSmrg        oldW = winRec->width;
120805b261ecSmrg        oldH = winRec->height;
120905b261ecSmrg
121005b261ecSmrg        newBW = oldBW;
121105b261ecSmrg        newX = x;
121205b261ecSmrg        newY = y;
121305b261ecSmrg        newW = w + 2*newBW;
121405b261ecSmrg        newH = h + 2*newBW;
121505b261ecSmrg
121605b261ecSmrg        resize_after = StartFrameResize(pWin, TRUE,
121705b261ecSmrg                                        oldX, oldY, oldW, oldH, oldBW,
121805b261ecSmrg                                        newX, newY, newW, newH, newBW);
121905b261ecSmrg    }
122005b261ecSmrg
122105b261ecSmrg    HUGE_ROOT(pWin);
122205b261ecSmrg    SCREEN_UNWRAP(pScreen, ResizeWindow);
122305b261ecSmrg    pScreen->ResizeWindow(pWin, x, y, w, h, pSib);
122405b261ecSmrg    SCREEN_WRAP(pScreen, ResizeWindow);
122505b261ecSmrg    NORMAL_ROOT(pWin);
122605b261ecSmrg
122705b261ecSmrg    if (winRec) {
122805b261ecSmrg        FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
122905b261ecSmrg                          newX, newY, newW, newH, newBW, resize_after);
123005b261ecSmrg    }
123105b261ecSmrg
123205b261ecSmrg    RL_DEBUG_MSG("resizewindow end\n");
123305b261ecSmrg}
123405b261ecSmrg
123505b261ecSmrg
123605b261ecSmrg/*
123705b261ecSmrg * RootlessRepositionWindow
123805b261ecSmrg *  Called by the implementation when a window needs to be repositioned to
123905b261ecSmrg *  its correct location on the screen. This routine is typically needed
124005b261ecSmrg *  due to changes in the underlying window system, such as a screen layout
124105b261ecSmrg *  change.
124205b261ecSmrg */
124305b261ecSmrgvoid
124405b261ecSmrgRootlessRepositionWindow(WindowPtr pWin)
124505b261ecSmrg{
124605b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
124705b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
124805b261ecSmrg
124905b261ecSmrg    if (winRec == NULL)
125005b261ecSmrg        return;
125105b261ecSmrg
125205b261ecSmrg    RootlessStopDrawing(pWin, FALSE);
125305b261ecSmrg    SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
125405b261ecSmrg                                       winRec->x + SCREEN_TO_GLOBAL_X,
125505b261ecSmrg                                       winRec->y + SCREEN_TO_GLOBAL_Y);
125605b261ecSmrg
125705b261ecSmrg    RootlessReorderWindow(pWin);
125805b261ecSmrg}
125905b261ecSmrg
126005b261ecSmrg
126105b261ecSmrg/*
126205b261ecSmrg * RootlessReparentWindow
126305b261ecSmrg *  Called after a window has been reparented. Generally windows are not
126405b261ecSmrg *  framed until they are mapped. However, a window may be framed early by the
126505b261ecSmrg *  implementation calling RootlessFrameForWindow. (e.g. this could be needed
126605b261ecSmrg *  to attach a VRAM surface to it.) If the window is subsequently reparented
126705b261ecSmrg *  by the window manager before being mapped, we need to give the frame to
126805b261ecSmrg *  the new top-level window.
126905b261ecSmrg */
127005b261ecSmrgvoid
127105b261ecSmrgRootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
127205b261ecSmrg{
127305b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
127405b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
127505b261ecSmrg    WindowPtr pTopWin;
127605b261ecSmrg
127705b261ecSmrg    /* Check that window is not top-level now, but used to be. */
127805b261ecSmrg    if (IsRoot(pWin) || IsRoot(pWin->parent)
127905b261ecSmrg        || IsTopLevel(pWin) || winRec == NULL)
128005b261ecSmrg    {
128105b261ecSmrg        goto out;
128205b261ecSmrg    }
128305b261ecSmrg
128405b261ecSmrg    /* If the formerly top-level window has a frame, we want to give the
128505b261ecSmrg       frame to its new top-level parent. If we can't do that, we'll just
128605b261ecSmrg       have to jettison it... */
128705b261ecSmrg
128805b261ecSmrg    pTopWin = TopLevelParent(pWin);
128905b261ecSmrg    assert(pTopWin != pWin);
129005b261ecSmrg
129105b261ecSmrg    if (WINREC(pTopWin) != NULL) {
129205b261ecSmrg        /* We're screwed. */
129305b261ecSmrg        RootlessDestroyFrame(pWin, winRec);
129405b261ecSmrg    } else {
129505b261ecSmrg        if (!pTopWin->realized && pWin->realized) {
129605b261ecSmrg            SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
129705b261ecSmrg        }
129805b261ecSmrg
129905b261ecSmrg        /* Switch the frame record from one to the other. */
130005b261ecSmrg
130105b261ecSmrg        WINREC(pWin) = NULL;
130205b261ecSmrg        WINREC(pTopWin) = winRec;
130305b261ecSmrg
130405b261ecSmrg        RootlessInitializeFrame(pTopWin, winRec);
130505b261ecSmrg        RootlessReshapeFrame(pTopWin);
130605b261ecSmrg
130705b261ecSmrg        SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
130805b261ecSmrg                                             winRec->x + SCREEN_TO_GLOBAL_X,
130905b261ecSmrg                                             winRec->y + SCREEN_TO_GLOBAL_Y,
131005b261ecSmrg                                             winRec->width, winRec->height,
131105b261ecSmrg                                             RL_GRAVITY_NONE);
131205b261ecSmrg
131305b261ecSmrg        if (SCREENREC(pScreen)->imp->SwitchWindow) {
131405b261ecSmrg            SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
131505b261ecSmrg        }
131605b261ecSmrg
131705b261ecSmrg        if (pTopWin->realized && !pWin->realized)
131805b261ecSmrg            winRec->is_reorder_pending = TRUE;
131905b261ecSmrg    }
132005b261ecSmrg
132105b261ecSmrgout:
132205b261ecSmrg    if (SCREENREC(pScreen)->ReparentWindow) {
132305b261ecSmrg        SCREEN_UNWRAP(pScreen, ReparentWindow);
132405b261ecSmrg        pScreen->ReparentWindow(pWin, pPriorParent);
132505b261ecSmrg        SCREEN_WRAP(pScreen, ReparentWindow);
132605b261ecSmrg    }
132705b261ecSmrg}
132805b261ecSmrg
132905b261ecSmrg
133005b261ecSmrg/*
133105b261ecSmrg * SetPixmapOfAncestors
133205b261ecSmrg *  Set the Pixmaps on all ParentRelative windows up the ancestor chain.
133305b261ecSmrg */
133405b261ecSmrgstatic void
133505b261ecSmrgSetPixmapOfAncestors(WindowPtr pWin)
133605b261ecSmrg{
133705b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
133805b261ecSmrg    WindowPtr topWin = TopLevelParent(pWin);
133905b261ecSmrg    RootlessWindowRec *topWinRec = WINREC(topWin);
134005b261ecSmrg
134105b261ecSmrg    while (pWin->backgroundState == ParentRelative) {
134205b261ecSmrg        if (pWin == topWin) {
134305b261ecSmrg            // disallow ParentRelative background state on top level
134405b261ecSmrg            XID pixel = 0;
134505b261ecSmrg            ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
134605b261ecSmrg            RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
134705b261ecSmrg            break;
134805b261ecSmrg        }
134905b261ecSmrg
135005b261ecSmrg        pWin = pWin->parent;
135105b261ecSmrg        pScreen->SetWindowPixmap(pWin, topWinRec->pixmap);
135205b261ecSmrg    }
135305b261ecSmrg}
135405b261ecSmrg
135505b261ecSmrg
135605b261ecSmrg/*
135705b261ecSmrg * RootlessPaintWindowBackground
135805b261ecSmrg */
135905b261ecSmrgvoid
136005b261ecSmrgRootlessPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what)
136105b261ecSmrg{
136205b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
136305b261ecSmrg
136405b261ecSmrg    if (IsRoot(pWin))
136505b261ecSmrg        return;
136605b261ecSmrg
136705b261ecSmrg    RL_DEBUG_MSG("paintwindowbackground start (win 0x%x, framed %i) ",
136805b261ecSmrg                 pWin, IsFramedWindow(pWin));
136905b261ecSmrg
137005b261ecSmrg    if (IsFramedWindow(pWin)) {
137105b261ecSmrg        RootlessStartDrawing(pWin);
137205b261ecSmrg        RootlessDamageRegion(pWin, pRegion);
137305b261ecSmrg
137405b261ecSmrg        // For ParentRelative windows, we have to make sure the window
137505b261ecSmrg        // pixmap is set correctly all the way up the ancestor chain.
137605b261ecSmrg        if (pWin->backgroundState == ParentRelative) {
137705b261ecSmrg            SetPixmapOfAncestors(pWin);
137805b261ecSmrg        }
137905b261ecSmrg    }
138005b261ecSmrg
138105b261ecSmrg    SCREEN_UNWRAP(pScreen, PaintWindowBackground);
138205b261ecSmrg    pScreen->PaintWindowBackground(pWin, pRegion, what);
138305b261ecSmrg    SCREEN_WRAP(pScreen, PaintWindowBackground);
138405b261ecSmrg
138505b261ecSmrg    RL_DEBUG_MSG("paintwindowbackground end\n");
138605b261ecSmrg}
138705b261ecSmrg
138805b261ecSmrg
138905b261ecSmrg/*
139005b261ecSmrg * RootlessPaintWindowBorder
139105b261ecSmrg */
139205b261ecSmrgvoid
139305b261ecSmrgRootlessPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what)
139405b261ecSmrg{
139505b261ecSmrg    RL_DEBUG_MSG("paintwindowborder start (win 0x%x) ", pWin);
139605b261ecSmrg
139705b261ecSmrg    if (IsFramedWindow(pWin)) {
139805b261ecSmrg        RootlessStartDrawing(pWin);
139905b261ecSmrg        RootlessDamageRegion(pWin, pRegion);
140005b261ecSmrg
140105b261ecSmrg        // For ParentRelative windows with tiled borders, we have to make
140205b261ecSmrg        // sure the window pixmap is set correctly all the way up the
140305b261ecSmrg        // ancestor chain.
140405b261ecSmrg        if (!pWin->borderIsPixel &&
140505b261ecSmrg            pWin->backgroundState == ParentRelative)
140605b261ecSmrg        {
140705b261ecSmrg            SetPixmapOfAncestors(pWin);
140805b261ecSmrg        }
140905b261ecSmrg    }
141005b261ecSmrg
141105b261ecSmrg    SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder);
141205b261ecSmrg    pWin->drawable.pScreen->PaintWindowBorder(pWin, pRegion, what);
141305b261ecSmrg    SCREEN_WRAP(pWin->drawable.pScreen, PaintWindowBorder);
141405b261ecSmrg
141505b261ecSmrg    RL_DEBUG_MSG("paintwindowborder end\n");
141605b261ecSmrg}
141705b261ecSmrg
141805b261ecSmrg
141905b261ecSmrg/*
142005b261ecSmrg * RootlessChangeBorderWidth
142105b261ecSmrg *  FIXME: untested!
142205b261ecSmrg *  pWin inside corner stays the same; pWin->drawable.[xy] stays the same
142305b261ecSmrg *  Frame moves and resizes.
142405b261ecSmrg */
142505b261ecSmrgvoid
142605b261ecSmrgRootlessChangeBorderWidth(WindowPtr pWin, unsigned int width)
142705b261ecSmrg{
142805b261ecSmrg    RegionRec saveRoot;
142905b261ecSmrg    Bool resize_after = FALSE;
143005b261ecSmrg
143105b261ecSmrg    RL_DEBUG_MSG("change border width ");
143205b261ecSmrg
143305b261ecSmrg    if (width != wBorderWidth(pWin)) {
143405b261ecSmrg        RootlessWindowRec *winRec = WINREC(pWin);
143505b261ecSmrg        int oldX = 0, oldY = 0, newX = 0, newY = 0;
143605b261ecSmrg        unsigned int oldW = 0, oldH = 0, oldBW = 0;
143705b261ecSmrg        unsigned int newW = 0, newH = 0, newBW = 0;
143805b261ecSmrg
143905b261ecSmrg        if (winRec) {
144005b261ecSmrg            oldBW = winRec->borderWidth;
144105b261ecSmrg            oldX = winRec->x;
144205b261ecSmrg            oldY = winRec->y;
144305b261ecSmrg            oldW = winRec->width;
144405b261ecSmrg            oldH = winRec->height;
144505b261ecSmrg
144605b261ecSmrg            newBW = width;
144705b261ecSmrg            newX = pWin->drawable.x - newBW;
144805b261ecSmrg            newY = pWin->drawable.y - newBW;
144905b261ecSmrg            newW = pWin->drawable.width  + 2*newBW;
145005b261ecSmrg            newH = pWin->drawable.height + 2*newBW;
145105b261ecSmrg
145205b261ecSmrg            resize_after = StartFrameResize(pWin, FALSE,
145305b261ecSmrg                                            oldX, oldY, oldW, oldH, oldBW,
145405b261ecSmrg                                            newX, newY, newW, newH, newBW);
145505b261ecSmrg        }
145605b261ecSmrg
145705b261ecSmrg        HUGE_ROOT(pWin);
145805b261ecSmrg        SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth);
145905b261ecSmrg        pWin->drawable.pScreen->ChangeBorderWidth(pWin, width);
146005b261ecSmrg        SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth);
146105b261ecSmrg        NORMAL_ROOT(pWin);
146205b261ecSmrg
146305b261ecSmrg        if (winRec) {
146405b261ecSmrg            FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
146505b261ecSmrg                              newX, newY, newW, newH, newBW, resize_after);
146605b261ecSmrg        }
146705b261ecSmrg    }
146805b261ecSmrg
146905b261ecSmrg    RL_DEBUG_MSG("change border width end\n");
147005b261ecSmrg}
1471