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
3635c4bbdfSmrg#include <stddef.h>             /* For NULL */
3735c4bbdfSmrg#include <limits.h>             /* For CHAR_BIT */
3805b261ecSmrg#include <assert.h>
394642e01fSmrg#include <X11/Xatom.h>
406747b715Smrg#ifdef __APPLE__
416747b715Smrg#include <Xplugin.h>
424642e01fSmrg#include "mi.h"
434642e01fSmrg#include "pixmapstr.h"
444642e01fSmrg#include "windowstr.h"
454642e01fSmrg//#include <X11/extensions/applewm.h>
464642e01fSmrgextern int darwinMainScreenX, darwinMainScreenY;
476747b715Smrgextern Bool no_configure_window;
484642e01fSmrg#endif
494642e01fSmrg#include "fb.h"
504642e01fSmrg
5105b261ecSmrg#include "rootlessCommon.h"
5205b261ecSmrg#include "rootlessWindow.h"
5305b261ecSmrg
5405b261ecSmrg#define SCREEN_TO_GLOBAL_X \
556747b715Smrg    (pScreen->x + rootlessGlobalOffsetX)
5605b261ecSmrg#define SCREEN_TO_GLOBAL_Y \
576747b715Smrg    (pScreen->y + rootlessGlobalOffsetY)
5805b261ecSmrg
594642e01fSmrg#define DEFINE_ATOM_HELPER(func,atom_name)                      \
604642e01fSmrg  static Atom func (void) {                                       \
614642e01fSmrg    static unsigned int generation = 0;                             \
624642e01fSmrg    static Atom atom;                                           \
634642e01fSmrg    if (generation != serverGeneration) {                       \
644642e01fSmrg      generation = serverGeneration;                          \
654642e01fSmrg      atom = MakeAtom (atom_name, strlen (atom_name), TRUE);  \
664642e01fSmrg    }                                                           \
674642e01fSmrg    return atom;                                                \
684642e01fSmrg  }
694642e01fSmrg
7035c4bbdfSmrgDEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID")
714642e01fSmrg
724642e01fSmrgstatic Bool windows_hidden;
7335c4bbdfSmrg
744642e01fSmrg// TODO - abstract xp functions
754642e01fSmrg
766747b715Smrg#ifdef __APPLE__
774642e01fSmrg
786747b715Smrg// XXX: identical to x_cvt_vptr_to_uint ?
796747b715Smrg#define MAKE_WINDOW_ID(x)		((xp_window_id)((size_t)(x)))
804642e01fSmrg
814642e01fSmrgvoid
8235c4bbdfSmrgRootlessNativeWindowStateChanged(WindowPtr pWin, unsigned int state)
834642e01fSmrg{
8435c4bbdfSmrg    RootlessWindowRec *winRec;
854642e01fSmrg
8635c4bbdfSmrg    if (pWin == NULL)
8735c4bbdfSmrg        return;
884642e01fSmrg
8935c4bbdfSmrg    winRec = WINREC(pWin);
9035c4bbdfSmrg    if (winRec == NULL)
9135c4bbdfSmrg        return;
924642e01fSmrg
9335c4bbdfSmrg    winRec->is_offscreen = ((state & XP_WINDOW_STATE_OFFSCREEN) != 0);
9435c4bbdfSmrg    winRec->is_obscured = ((state & XP_WINDOW_STATE_OBSCURED) != 0);
9535c4bbdfSmrg    pWin->unhittable = winRec->is_offscreen;
964642e01fSmrg}
974642e01fSmrg
9835c4bbdfSmrgvoid
9935c4bbdfSmrgRootlessNativeWindowMoved(WindowPtr pWin)
10035c4bbdfSmrg{
1014642e01fSmrg    xp_box bounds;
1024642e01fSmrg    int sx, sy, err;
1034642e01fSmrg    XID vlist[2];
1044642e01fSmrg    Mask mask;
1054642e01fSmrg    ClientPtr pClient;
1064642e01fSmrg    RootlessWindowRec *winRec;
10735c4bbdfSmrg
1084642e01fSmrg    winRec = WINREC(pWin);
10935c4bbdfSmrg
11035c4bbdfSmrg    if (xp_get_window_bounds(MAKE_WINDOW_ID(winRec->wid), &bounds) != Success)
11135c4bbdfSmrg        return;
11235c4bbdfSmrg
1136747b715Smrg    sx = pWin->drawable.pScreen->x + darwinMainScreenX;
1146747b715Smrg    sy = pWin->drawable.pScreen->y + darwinMainScreenY;
11535c4bbdfSmrg
1164642e01fSmrg    /* Fake up a ConfigureWindow packet to resize the window to the current bounds. */
1174642e01fSmrg    vlist[0] = (INT16) bounds.x1 - sx;
1184642e01fSmrg    vlist[1] = (INT16) bounds.y1 - sy;
1194642e01fSmrg    mask = CWX | CWY;
12035c4bbdfSmrg
1214642e01fSmrg    /* pretend we're the owner of the window! */
12235c4bbdfSmrg    err =
12335c4bbdfSmrg        dixLookupClient(&pClient, pWin->drawable.id, serverClient,
12435c4bbdfSmrg                        DixUnknownAccess);
12535c4bbdfSmrg    if (err != Success) {
12635c4bbdfSmrg        ErrorF("RootlessNativeWindowMoved(): Failed to lookup window: 0x%x\n",
12735c4bbdfSmrg               (unsigned int) pWin->drawable.id);
1284642e01fSmrg        return;
1294642e01fSmrg    }
13035c4bbdfSmrg
13135c4bbdfSmrg    /* Don't want to do anything to the physical window (avoids
13235c4bbdfSmrg       notification-response feedback loops) */
13335c4bbdfSmrg
1344642e01fSmrg    no_configure_window = TRUE;
13535c4bbdfSmrg    ConfigureWindow(pWin, mask, vlist, pClient);
1364642e01fSmrg    no_configure_window = FALSE;
1374642e01fSmrg}
1384642e01fSmrg
13935c4bbdfSmrg#endif                          /* __APPLE__ */
14005b261ecSmrg
14105b261ecSmrg/*
14205b261ecSmrg * RootlessCreateWindow
14305b261ecSmrg *  For now, don't create a physical window until either the window is
14405b261ecSmrg *  realized, or we really need it (e.g. to attach VRAM surfaces to).
14505b261ecSmrg *  Do reset the window size so it's not clipped by the root window.
14605b261ecSmrg */
14705b261ecSmrgBool
14805b261ecSmrgRootlessCreateWindow(WindowPtr pWin)
14905b261ecSmrg{
15005b261ecSmrg    Bool result;
15105b261ecSmrg    RegionRec saveRoot;
15205b261ecSmrg
1534642e01fSmrg    SETWINREC(pWin, NULL);
1544642e01fSmrg    dixSetPrivate(&pWin->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL);
15505b261ecSmrg
15605b261ecSmrg    SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow);
15705b261ecSmrg
15805b261ecSmrg    if (!IsRoot(pWin)) {
15905b261ecSmrg        /* win/border size set by DIX, not by wrapped CreateWindow, so
16005b261ecSmrg           correct it here. Don't HUGE_ROOT when pWin is the root! */
16105b261ecSmrg
16205b261ecSmrg        HUGE_ROOT(pWin);
16305b261ecSmrg        SetWinSize(pWin);
16405b261ecSmrg        SetBorderSize(pWin);
16505b261ecSmrg    }
16605b261ecSmrg
16705b261ecSmrg    result = pWin->drawable.pScreen->CreateWindow(pWin);
16805b261ecSmrg
16905b261ecSmrg    if (pWin->parent) {
17005b261ecSmrg        NORMAL_ROOT(pWin);
17105b261ecSmrg    }
17205b261ecSmrg
17305b261ecSmrg    SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow);
17405b261ecSmrg
17505b261ecSmrg    return result;
17605b261ecSmrg}
17705b261ecSmrg
17805b261ecSmrg/*
17905b261ecSmrg * RootlessDestroyFrame
18005b261ecSmrg *  Destroy the physical window associated with the given window.
18105b261ecSmrg */
18205b261ecSmrgstatic void
18305b261ecSmrgRootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec)
18405b261ecSmrg{
1856747b715Smrg    SCREENREC(pWin->drawable.pScreen)->imp->DestroyFrame(winRec->wid);
1866747b715Smrg    free(winRec);
1874642e01fSmrg    SETWINREC(pWin, NULL);
18805b261ecSmrg}
18905b261ecSmrg
19005b261ecSmrg/*
19105b261ecSmrg * RootlessDestroyWindow
19205b261ecSmrg *  Destroy the physical window associated with the given window.
19305b261ecSmrg */
19405b261ecSmrgBool
19505b261ecSmrgRootlessDestroyWindow(WindowPtr pWin)
19605b261ecSmrg{
19705b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
19805b261ecSmrg    Bool result;
19905b261ecSmrg
20005b261ecSmrg    if (winRec != NULL) {
20105b261ecSmrg        RootlessDestroyFrame(pWin, winRec);
20205b261ecSmrg    }
20305b261ecSmrg
20405b261ecSmrg    SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow);
20505b261ecSmrg    result = pWin->drawable.pScreen->DestroyWindow(pWin);
20605b261ecSmrg    SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow);
20705b261ecSmrg
20805b261ecSmrg    return result;
20905b261ecSmrg}
21005b261ecSmrg
21105b261ecSmrgstatic Bool
21205b261ecSmrgRootlessGetShape(WindowPtr pWin, RegionPtr pShape)
21305b261ecSmrg{
21405b261ecSmrg    if (wBoundingShape(pWin) == NULL)
21505b261ecSmrg        return FALSE;
21605b261ecSmrg
21705b261ecSmrg    /* wBoundingShape is relative to *inner* origin of window.
21805b261ecSmrg       Translate by borderWidth to get the outside-relative position. */
21905b261ecSmrg
2206747b715Smrg    RegionNull(pShape);
2216747b715Smrg    RegionCopy(pShape, wBoundingShape(pWin));
2226747b715Smrg    RegionTranslate(pShape, pWin->borderWidth, pWin->borderWidth);
22305b261ecSmrg
22405b261ecSmrg    return TRUE;
22505b261ecSmrg}
22605b261ecSmrg
22705b261ecSmrg/*
22805b261ecSmrg * RootlessReshapeFrame
22905b261ecSmrg *  Set the frame shape.
23005b261ecSmrg */
23135c4bbdfSmrgstatic void
23235c4bbdfSmrgRootlessReshapeFrame(WindowPtr pWin)
23305b261ecSmrg{
23405b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
23505b261ecSmrg    RegionRec newShape;
23605b261ecSmrg    RegionPtr pShape;
23705b261ecSmrg
23805b261ecSmrg    // If the window is not yet framed, do nothing
23905b261ecSmrg    if (winRec == NULL)
24005b261ecSmrg        return;
24105b261ecSmrg
24205b261ecSmrg    if (IsRoot(pWin))
24305b261ecSmrg        return;
24405b261ecSmrg
24505b261ecSmrg    RootlessStopDrawing(pWin, FALSE);
24605b261ecSmrg
24705b261ecSmrg    pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL;
24805b261ecSmrg
24905b261ecSmrg#ifdef ROOTLESSDEBUG
25005b261ecSmrg    RL_DEBUG_MSG("reshaping...");
25105b261ecSmrg    if (pShape != NULL) {
25205b261ecSmrg        RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ",
2536747b715Smrg                     RegionNumRects(&newShape),
25405b261ecSmrg                     newShape.extents.x1, newShape.extents.y1,
25505b261ecSmrg                     newShape.extents.x2, newShape.extents.y2);
25635c4bbdfSmrg    }
25735c4bbdfSmrg    else {
25805b261ecSmrg        RL_DEBUG_MSG("no shape ");
25905b261ecSmrg    }
26005b261ecSmrg#endif
26105b261ecSmrg
2626747b715Smrg    SCREENREC(pWin->drawable.pScreen)->imp->ReshapeFrame(winRec->wid, pShape);
26305b261ecSmrg
26405b261ecSmrg    if (pShape != NULL)
2656747b715Smrg        RegionUninit(&newShape);
26605b261ecSmrg}
26705b261ecSmrg
26805b261ecSmrg/*
26905b261ecSmrg * RootlessSetShape
27005b261ecSmrg *  Shape is usually set before a window is mapped and the window will
27105b261ecSmrg *  not have a frame associated with it. In this case, the frame will be
27205b261ecSmrg *  shaped when the window is framed.
27305b261ecSmrg */
27405b261ecSmrgvoid
2756747b715SmrgRootlessSetShape(WindowPtr pWin, int kind)
27605b261ecSmrg{
27705b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
27805b261ecSmrg
27905b261ecSmrg    SCREEN_UNWRAP(pScreen, SetShape);
2806747b715Smrg    pScreen->SetShape(pWin, kind);
28105b261ecSmrg    SCREEN_WRAP(pScreen, SetShape);
28205b261ecSmrg
28305b261ecSmrg    RootlessReshapeFrame(pWin);
28405b261ecSmrg}
28505b261ecSmrg
28605b261ecSmrg/* Disallow ParentRelative background on top-level windows
2874642e01fSmrg   because the root window doesn't really have the right background.
2884642e01fSmrg */
28905b261ecSmrgBool
29005b261ecSmrgRootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask)
29105b261ecSmrg{
29205b261ecSmrg    Bool result;
29305b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
29405b261ecSmrg
29505b261ecSmrg    RL_DEBUG_MSG("change window attributes start ");
29605b261ecSmrg
29705b261ecSmrg    SCREEN_UNWRAP(pScreen, ChangeWindowAttributes);
29805b261ecSmrg    result = pScreen->ChangeWindowAttributes(pWin, vmask);
29905b261ecSmrg    SCREEN_WRAP(pScreen, ChangeWindowAttributes);
30005b261ecSmrg
30105b261ecSmrg    if (WINREC(pWin)) {
30205b261ecSmrg        // disallow ParentRelative background state
30305b261ecSmrg        if (pWin->backgroundState == ParentRelative) {
30405b261ecSmrg            XID pixel = 0;
30535c4bbdfSmrg
30605b261ecSmrg            ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
30705b261ecSmrg        }
30805b261ecSmrg    }
30905b261ecSmrg
31005b261ecSmrg    RL_DEBUG_MSG("change window attributes end\n");
31105b261ecSmrg    return result;
31205b261ecSmrg}
31305b261ecSmrg
31405b261ecSmrg/*
31505b261ecSmrg * RootlessPositionWindow
31605b261ecSmrg *  This is a hook for when DIX moves or resizes a window.
31705b261ecSmrg *  Update the frame position now although the physical window is moved
31805b261ecSmrg *  in RootlessMoveWindow. (x, y) are *inside* position. After this,
31905b261ecSmrg *  mi and fb are expecting the pixmap to be at the new location.
32005b261ecSmrg */
32105b261ecSmrgBool
32205b261ecSmrgRootlessPositionWindow(WindowPtr pWin, int x, int y)
32305b261ecSmrg{
32405b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
32505b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
32605b261ecSmrg    Bool result;
32705b261ecSmrg
32805b261ecSmrg    RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y);
32905b261ecSmrg
33005b261ecSmrg    if (winRec) {
33105b261ecSmrg        if (winRec->is_drawing) {
33205b261ecSmrg            // Reset frame's pixmap and move it to the new position.
33305b261ecSmrg            int bw = wBorderWidth(pWin);
33405b261ecSmrg
33505b261ecSmrg            winRec->pixmap->devPrivate.ptr = winRec->pixelData;
33605b261ecSmrg            SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw);
33705b261ecSmrg        }
33805b261ecSmrg    }
33905b261ecSmrg
34005b261ecSmrg    SCREEN_UNWRAP(pScreen, PositionWindow);
34105b261ecSmrg    result = pScreen->PositionWindow(pWin, x, y);
34205b261ecSmrg    SCREEN_WRAP(pScreen, PositionWindow);
34305b261ecSmrg
34405b261ecSmrg    RL_DEBUG_MSG("positionwindow end\n");
34505b261ecSmrg    return result;
34605b261ecSmrg}
34705b261ecSmrg
34805b261ecSmrg/*
34905b261ecSmrg * RootlessInitializeFrame
35005b261ecSmrg *  Initialize some basic attributes of the frame. Note that winRec
35105b261ecSmrg *  may already have valid data in it, so don't overwrite anything
35205b261ecSmrg *  valuable.
35305b261ecSmrg */
35405b261ecSmrgstatic void
35535c4bbdfSmrgRootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec * winRec)
35605b261ecSmrg{
35705b261ecSmrg    DrawablePtr d = &pWin->drawable;
35805b261ecSmrg    int bw = wBorderWidth(pWin);
35905b261ecSmrg
36005b261ecSmrg    winRec->win = pWin;
36105b261ecSmrg
36205b261ecSmrg    winRec->x = d->x - bw;
36305b261ecSmrg    winRec->y = d->y - bw;
36435c4bbdfSmrg    winRec->width = d->width + 2 * bw;
36535c4bbdfSmrg    winRec->height = d->height + 2 * bw;
36605b261ecSmrg    winRec->borderWidth = bw;
36705b261ecSmrg}
36805b261ecSmrg
36905b261ecSmrg/*
37005b261ecSmrg * RootlessEnsureFrame
37105b261ecSmrg *  Make sure the given window is framed. If the window doesn't have a
37205b261ecSmrg *  physical window associated with it, attempt to create one. If that
37305b261ecSmrg *  is unsuccessful, return NULL.
37405b261ecSmrg */
37505b261ecSmrgstatic RootlessWindowRec *
37605b261ecSmrgRootlessEnsureFrame(WindowPtr pWin)
37705b261ecSmrg{
37805b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
37905b261ecSmrg    RootlessWindowRec *winRec;
38005b261ecSmrg    RegionRec shape;
38105b261ecSmrg    RegionPtr pShape = NULL;
38205b261ecSmrg
38305b261ecSmrg    if (WINREC(pWin) != NULL)
38405b261ecSmrg        return WINREC(pWin);
38505b261ecSmrg
3864642e01fSmrg    if (!IsTopLevel(pWin) && !IsRoot(pWin))
38705b261ecSmrg        return NULL;
38805b261ecSmrg
38905b261ecSmrg    if (pWin->drawable.class != InputOutput)
39005b261ecSmrg        return NULL;
39105b261ecSmrg
3926747b715Smrg    winRec = malloc(sizeof(RootlessWindowRec));
39305b261ecSmrg
39405b261ecSmrg    if (!winRec)
39505b261ecSmrg        return NULL;
39605b261ecSmrg
39705b261ecSmrg    RootlessInitializeFrame(pWin, winRec);
39805b261ecSmrg
39905b261ecSmrg    winRec->is_drawing = FALSE;
40005b261ecSmrg    winRec->is_reorder_pending = FALSE;
40105b261ecSmrg    winRec->pixmap = NULL;
40205b261ecSmrg    winRec->wid = NULL;
4036747b715Smrg    winRec->level = 0;
40405b261ecSmrg
4054642e01fSmrg    SETWINREC(pWin, winRec);
40605b261ecSmrg
40705b261ecSmrg    // Set the frame's shape if the window is shaped
40805b261ecSmrg    if (RootlessGetShape(pWin, &shape))
40905b261ecSmrg        pShape = &shape;
41005b261ecSmrg
41105b261ecSmrg    RL_DEBUG_MSG("creating frame ");
41205b261ecSmrg
41305b261ecSmrg    if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen,
41405b261ecSmrg                                              winRec->x + SCREEN_TO_GLOBAL_X,
41505b261ecSmrg                                              winRec->y + SCREEN_TO_GLOBAL_Y,
41635c4bbdfSmrg                                              pShape)) {
41705b261ecSmrg        RL_DEBUG_MSG("implementation failed to create frame!\n");
4186747b715Smrg        free(winRec);
4194642e01fSmrg        SETWINREC(pWin, NULL);
42005b261ecSmrg        return NULL;
42105b261ecSmrg    }
42205b261ecSmrg
4234642e01fSmrg    if (pWin->drawable.depth == 8)
42435c4bbdfSmrg        RootlessFlushWindowColormap(pWin);
4254642e01fSmrg
42605b261ecSmrg    if (pShape != NULL)
4276747b715Smrg        RegionUninit(&shape);
42805b261ecSmrg
42905b261ecSmrg    return winRec;
43005b261ecSmrg}
43105b261ecSmrg
43205b261ecSmrg/*
43305b261ecSmrg * RootlessRealizeWindow
43405b261ecSmrg *  The frame is usually created here and not in CreateWindow so that
43505b261ecSmrg *  windows do not eat memory until they are realized.
43605b261ecSmrg */
43705b261ecSmrgBool
43805b261ecSmrgRootlessRealizeWindow(WindowPtr pWin)
43905b261ecSmrg{
44005b261ecSmrg    Bool result;
44105b261ecSmrg    RegionRec saveRoot;
44205b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
44305b261ecSmrg
44405b261ecSmrg    RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin);
44505b261ecSmrg
44605b261ecSmrg    if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) {
44705b261ecSmrg        RootlessWindowRec *winRec;
44805b261ecSmrg
44905b261ecSmrg        winRec = RootlessEnsureFrame(pWin);
45005b261ecSmrg        if (winRec == NULL)
45105b261ecSmrg            return FALSE;
45205b261ecSmrg
45305b261ecSmrg        winRec->is_reorder_pending = TRUE;
45405b261ecSmrg
45505b261ecSmrg        RL_DEBUG_MSG("Top level window ");
45605b261ecSmrg
45705b261ecSmrg        // Disallow ParentRelative background state on top-level windows.
45805b261ecSmrg        // This might have been set before the window was mapped.
45905b261ecSmrg        if (pWin->backgroundState == ParentRelative) {
46005b261ecSmrg            XID pixel = 0;
46135c4bbdfSmrg
46205b261ecSmrg            ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
46305b261ecSmrg        }
46405b261ecSmrg    }
46505b261ecSmrg
46635c4bbdfSmrg    if (!IsRoot(pWin))
46735c4bbdfSmrg        HUGE_ROOT(pWin);
46805b261ecSmrg    SCREEN_UNWRAP(pScreen, RealizeWindow);
46905b261ecSmrg    result = pScreen->RealizeWindow(pWin);
47005b261ecSmrg    SCREEN_WRAP(pScreen, RealizeWindow);
47135c4bbdfSmrg    if (!IsRoot(pWin))
47235c4bbdfSmrg        NORMAL_ROOT(pWin);
47305b261ecSmrg
47405b261ecSmrg    RL_DEBUG_MSG("realizewindow end\n");
47505b261ecSmrg    return result;
47605b261ecSmrg}
47705b261ecSmrg
47805b261ecSmrg/*
47905b261ecSmrg * RootlessFrameForWindow
48035c4bbdfSmrg *  Returns the frame ID for the physical window displaying the given window.
48105b261ecSmrg *  If CREATE is true and the window has no frame, attempt to create one.
48205b261ecSmrg */
48305b261ecSmrgRootlessFrameID
48405b261ecSmrgRootlessFrameForWindow(WindowPtr pWin, Bool create)
48505b261ecSmrg{
48605b261ecSmrg    WindowPtr pTopWin;
48705b261ecSmrg    RootlessWindowRec *winRec;
48805b261ecSmrg
48905b261ecSmrg    pTopWin = TopLevelParent(pWin);
49005b261ecSmrg    if (pTopWin == NULL)
49105b261ecSmrg        return NULL;
49205b261ecSmrg
49305b261ecSmrg    winRec = WINREC(pTopWin);
49405b261ecSmrg
49505b261ecSmrg    if (winRec == NULL && create && pWin->drawable.class == InputOutput) {
49605b261ecSmrg        winRec = RootlessEnsureFrame(pTopWin);
49705b261ecSmrg    }
49805b261ecSmrg
49905b261ecSmrg    if (winRec == NULL)
50005b261ecSmrg        return NULL;
50105b261ecSmrg
50205b261ecSmrg    return winRec->wid;
50305b261ecSmrg}
50405b261ecSmrg
50505b261ecSmrg/*
50605b261ecSmrg * RootlessUnrealizeWindow
50705b261ecSmrg *  Unmap the physical window.
50805b261ecSmrg */
50905b261ecSmrgBool
51005b261ecSmrgRootlessUnrealizeWindow(WindowPtr pWin)
51105b261ecSmrg{
51205b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
51305b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
51405b261ecSmrg    Bool result;
51505b261ecSmrg
51605b261ecSmrg    RL_DEBUG_MSG("unrealizewindow start ");
51705b261ecSmrg
51805b261ecSmrg    if (winRec) {
51905b261ecSmrg        RootlessStopDrawing(pWin, FALSE);
52005b261ecSmrg
52105b261ecSmrg        SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
52205b261ecSmrg
52305b261ecSmrg        winRec->is_reorder_pending = FALSE;
52405b261ecSmrg    }
52505b261ecSmrg
52605b261ecSmrg    SCREEN_UNWRAP(pScreen, UnrealizeWindow);
52705b261ecSmrg    result = pScreen->UnrealizeWindow(pWin);
52805b261ecSmrg    SCREEN_WRAP(pScreen, UnrealizeWindow);
52905b261ecSmrg
53005b261ecSmrg    RL_DEBUG_MSG("unrealizewindow end\n");
53105b261ecSmrg    return result;
53205b261ecSmrg}
53305b261ecSmrg
53405b261ecSmrg/*
53505b261ecSmrg * RootlessReorderWindow
53605b261ecSmrg *  Reorder the frame associated with the given window so that it's
53705b261ecSmrg *  physically above the window below it in the X stacking order.
53805b261ecSmrg */
53905b261ecSmrgvoid
54005b261ecSmrgRootlessReorderWindow(WindowPtr pWin)
54105b261ecSmrg{
54205b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
54305b261ecSmrg
54435c4bbdfSmrg    if (pWin->realized && winRec != NULL && !winRec->is_reorder_pending &&
54535c4bbdfSmrg        !windows_hidden) {
54605b261ecSmrg        WindowPtr newPrevW;
54705b261ecSmrg        RootlessWindowRec *newPrev;
54805b261ecSmrg        RootlessFrameID newPrevID;
54905b261ecSmrg        ScreenPtr pScreen = pWin->drawable.pScreen;
55005b261ecSmrg
55105b261ecSmrg        /* Check if the implementation wants the frame to not be reordered
55205b261ecSmrg           even though the X11 window is restacked. This can be useful if
55305b261ecSmrg           frames are ordered-in with animation so that the reordering is not
55405b261ecSmrg           done until the animation is complete. */
55505b261ecSmrg        if (SCREENREC(pScreen)->imp->DoReorderWindow) {
55605b261ecSmrg            if (!SCREENREC(pScreen)->imp->DoReorderWindow(winRec))
55705b261ecSmrg                return;
55805b261ecSmrg        }
55905b261ecSmrg
56005b261ecSmrg        RootlessStopDrawing(pWin, FALSE);
56105b261ecSmrg
56235c4bbdfSmrg        /* Find the next window above this one that has a mapped frame.
5636747b715Smrg         * Only include cases where the windows are in the same category of
564ed6184dfSmrg         * hittability to ensure offscreen windows don't get restacked
5656747b715Smrg         * relative to onscreen ones (but that the offscreen ones maintain
566ed6184dfSmrg         * their stacking order if they are explicitly asked to Reorder).
5676747b715Smrg         */
56805b261ecSmrg
56905b261ecSmrg        newPrevW = pWin->prevSib;
57035c4bbdfSmrg        while (newPrevW &&
57135c4bbdfSmrg               (WINREC(newPrevW) == NULL || !newPrevW->realized ||
57235c4bbdfSmrg                newPrevW->unhittable != pWin->unhittable))
57305b261ecSmrg            newPrevW = newPrevW->prevSib;
57405b261ecSmrg
57505b261ecSmrg        newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL;
57605b261ecSmrg        newPrevID = newPrev != NULL ? newPrev->wid : 0;
57705b261ecSmrg
57805b261ecSmrg        /* If it exists, reorder the frame above us first. */
57905b261ecSmrg
58005b261ecSmrg        if (newPrev && newPrev->is_reorder_pending) {
58105b261ecSmrg            newPrev->is_reorder_pending = FALSE;
58205b261ecSmrg            RootlessReorderWindow(newPrevW);
58305b261ecSmrg        }
58405b261ecSmrg
58505b261ecSmrg        SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID);
58605b261ecSmrg    }
58705b261ecSmrg}
58805b261ecSmrg
58905b261ecSmrg/*
59005b261ecSmrg * RootlessRestackWindow
59105b261ecSmrg *  This is a hook for when DIX changes the window stacking order.
59205b261ecSmrg *  The window has already been inserted into its new position in the
59305b261ecSmrg *  DIX window stack. We need to change the order of the physical
59405b261ecSmrg *  window to match.
59505b261ecSmrg */
59605b261ecSmrgvoid
59705b261ecSmrgRootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib)
59805b261ecSmrg{
59905b261ecSmrg    RegionRec saveRoot;
60005b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
60105b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
60205b261ecSmrg
60305b261ecSmrg    RL_DEBUG_MSG("restackwindow start ");
60405b261ecSmrg    if (winRec)
60505b261ecSmrg        RL_DEBUG_MSG("restack top level \n");
60605b261ecSmrg
60705b261ecSmrg    HUGE_ROOT(pWin);
60805b261ecSmrg    SCREEN_UNWRAP(pScreen, RestackWindow);
60905b261ecSmrg
61005b261ecSmrg    if (pScreen->RestackWindow)
61105b261ecSmrg        pScreen->RestackWindow(pWin, pOldNextSib);
61205b261ecSmrg
61305b261ecSmrg    SCREEN_WRAP(pScreen, RestackWindow);
61405b261ecSmrg    NORMAL_ROOT(pWin);
61505b261ecSmrg
61605b261ecSmrg    if (winRec && pWin->viewable) {
61705b261ecSmrg        RootlessReorderWindow(pWin);
61805b261ecSmrg    }
61905b261ecSmrg
62005b261ecSmrg    RL_DEBUG_MSG("restackwindow end\n");
62105b261ecSmrg}
62205b261ecSmrg
62305b261ecSmrg/*
62405b261ecSmrg * Specialized window copy procedures
62505b261ecSmrg */
62605b261ecSmrg
62705b261ecSmrg// Globals needed during window resize and move.
62835c4bbdfSmrgstatic void *gResizeDeathBits = NULL;
62905b261ecSmrgstatic int gResizeDeathCount = 0;
63035c4bbdfSmrgstatic PixmapPtr gResizeDeathPix[2] = { NULL, NULL };
63135c4bbdfSmrg
63205b261ecSmrgstatic BoxRec gResizeDeathBounds[2];
63305b261ecSmrgstatic CopyWindowProcPtr gResizeOldCopyWindowProc = NULL;
63405b261ecSmrg
63505b261ecSmrg/*
63605b261ecSmrg * RootlessNoCopyWindow
63705b261ecSmrg *  CopyWindow() that doesn't do anything. For MoveWindow() of
63805b261ecSmrg *  top-level windows.
63905b261ecSmrg */
64005b261ecSmrgstatic void
64135c4bbdfSmrgRootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
64205b261ecSmrg{
64305b261ecSmrg    // some code expects the region to be translated
64405b261ecSmrg    int dx = ptOldOrg.x - pWin->drawable.x;
64505b261ecSmrg    int dy = ptOldOrg.y - pWin->drawable.y;
64605b261ecSmrg
64705b261ecSmrg    RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW ");
64805b261ecSmrg
6496747b715Smrg    RegionTranslate(prgnSrc, -dx, -dy);
65005b261ecSmrg}
65105b261ecSmrg
65205b261ecSmrg/*
65305b261ecSmrg * RootlessResizeCopyWindow
65405b261ecSmrg *  CopyWindow used during ResizeWindow for gravity moves. Based on
65505b261ecSmrg *  fbCopyWindow. The original always draws on the root pixmap, which
65605b261ecSmrg *  we don't have. Instead, draw on the parent window's pixmap.
65705b261ecSmrg *  Resize version: the old location's pixels are in gResizeCopyWindowSource.
65805b261ecSmrg */
65905b261ecSmrgstatic void
66005b261ecSmrgRootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
66105b261ecSmrg                         RegionPtr prgnSrc)
66205b261ecSmrg{
66305b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
66435c4bbdfSmrg    RegionRec rgnDst;
66535c4bbdfSmrg    int dx, dy;
66605b261ecSmrg
66705b261ecSmrg    RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin);
66805b261ecSmrg
66905b261ecSmrg    /* Don't unwrap pScreen->CopyWindow.
67005b261ecSmrg       The bogus rewrap with RootlessCopyWindow causes a crash if
67105b261ecSmrg       CopyWindow is called again during the same resize. */
67205b261ecSmrg
67305b261ecSmrg    if (gResizeDeathCount == 0)
67405b261ecSmrg        return;
67505b261ecSmrg
67605b261ecSmrg    RootlessStartDrawing(pWin);
67705b261ecSmrg
67805b261ecSmrg    dx = ptOldOrg.x - pWin->drawable.x;
67905b261ecSmrg    dy = ptOldOrg.y - pWin->drawable.y;
6806747b715Smrg    RegionTranslate(prgnSrc, -dx, -dy);
6816747b715Smrg    RegionNull(&rgnDst);
6826747b715Smrg    RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
68305b261ecSmrg
68405b261ecSmrg    if (gResizeDeathCount == 1) {
68505b261ecSmrg        /* Simple case, we only have a single source pixmap. */
68605b261ecSmrg
68735c4bbdfSmrg        miCopyRegion(&gResizeDeathPix[0]->drawable,
68805b261ecSmrg                     &pScreen->GetWindowPixmap(pWin)->drawable, 0,
68905b261ecSmrg                     &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
69005b261ecSmrg    }
69105b261ecSmrg    else {
69205b261ecSmrg        int i;
69305b261ecSmrg        RegionRec clip, clipped;
69405b261ecSmrg
69505b261ecSmrg        /* More complex case, N source pixmaps (usually two). So we
69605b261ecSmrg           intersect the destination with each source and copy those bits. */
69705b261ecSmrg
69805b261ecSmrg        for (i = 0; i < gResizeDeathCount; i++) {
6996747b715Smrg            RegionInit(&clip, gResizeDeathBounds + 0, 1);
7006747b715Smrg            RegionNull(&clipped);
7016747b715Smrg            RegionIntersect(&rgnDst, &clip, &clipped);
70205b261ecSmrg
70335c4bbdfSmrg            miCopyRegion(&gResizeDeathPix[i]->drawable,
70405b261ecSmrg                         &pScreen->GetWindowPixmap(pWin)->drawable, 0,
70505b261ecSmrg                         &clipped, dx, dy, fbCopyWindowProc, 0, 0);
70605b261ecSmrg
7076747b715Smrg            RegionUninit(&clipped);
7086747b715Smrg            RegionUninit(&clip);
70905b261ecSmrg        }
71005b261ecSmrg    }
71105b261ecSmrg
71205b261ecSmrg    /* Don't update - resize will update everything */
7136747b715Smrg    RegionUninit(&rgnDst);
71405b261ecSmrg
71505b261ecSmrg    fbValidateDrawable(&pWin->drawable);
71605b261ecSmrg
71705b261ecSmrg    RL_DEBUG_MSG("resizecopywindowFB end\n");
71805b261ecSmrg}
71905b261ecSmrg
72005b261ecSmrg/*
72105b261ecSmrg * RootlessCopyWindow
72205b261ecSmrg *  Update *new* location of window. Old location is redrawn with
72335c4bbdfSmrg *  PaintWindow. Cloned from fbCopyWindow.
72405b261ecSmrg *  The original always draws on the root pixmap, which we don't have.
72505b261ecSmrg *  Instead, draw on the parent window's pixmap.
72605b261ecSmrg */
72705b261ecSmrgvoid
72805b261ecSmrgRootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
72905b261ecSmrg{
73005b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
73135c4bbdfSmrg    RegionRec rgnDst;
73235c4bbdfSmrg    int dx, dy;
73305b261ecSmrg    BoxPtr extents;
73405b261ecSmrg    int area;
73505b261ecSmrg
73605b261ecSmrg    RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin);
73705b261ecSmrg
73805b261ecSmrg    SCREEN_UNWRAP(pScreen, CopyWindow);
73905b261ecSmrg
74005b261ecSmrg    dx = ptOldOrg.x - pWin->drawable.x;
74105b261ecSmrg    dy = ptOldOrg.y - pWin->drawable.y;
7426747b715Smrg    RegionTranslate(prgnSrc, -dx, -dy);
74305b261ecSmrg
7446747b715Smrg    RegionNull(&rgnDst);
7456747b715Smrg    RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
74605b261ecSmrg
7476747b715Smrg    extents = RegionExtents(&rgnDst);
74805b261ecSmrg    area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1);
74905b261ecSmrg
75005b261ecSmrg    /* If the area exceeds threshold, use the implementation's
75105b261ecSmrg       accelerated version. */
75205b261ecSmrg    if (area > rootless_CopyWindow_threshold &&
75335c4bbdfSmrg        SCREENREC(pScreen)->imp->CopyWindow) {
75405b261ecSmrg        RootlessWindowRec *winRec;
75505b261ecSmrg        WindowPtr top;
75605b261ecSmrg
75705b261ecSmrg        top = TopLevelParent(pWin);
75805b261ecSmrg        if (top == NULL) {
75905b261ecSmrg            RL_DEBUG_MSG("no parent\n");
7604642e01fSmrg            goto out;
76105b261ecSmrg        }
76205b261ecSmrg
76305b261ecSmrg        winRec = WINREC(top);
76405b261ecSmrg        if (winRec == NULL) {
76505b261ecSmrg            RL_DEBUG_MSG("not framed\n");
7664642e01fSmrg            goto out;
76705b261ecSmrg        }
76805b261ecSmrg
76905b261ecSmrg        /* Move region to window local coords */
7706747b715Smrg        RegionTranslate(&rgnDst, -winRec->x, -winRec->y);
77105b261ecSmrg
77205b261ecSmrg        RootlessStopDrawing(pWin, FALSE);
77305b261ecSmrg
77405b261ecSmrg        SCREENREC(pScreen)->imp->CopyWindow(winRec->wid,
7756747b715Smrg                                            RegionNumRects(&rgnDst),
77635c4bbdfSmrg                                            RegionRects(&rgnDst), dx, dy);
77705b261ecSmrg    }
77805b261ecSmrg    else {
77905b261ecSmrg        RootlessStartDrawing(pWin);
78005b261ecSmrg
78135c4bbdfSmrg        miCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin,
78205b261ecSmrg                     0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
78305b261ecSmrg
78405b261ecSmrg        /* prgnSrc has been translated to dst position */
78505b261ecSmrg        RootlessDamageRegion(pWin, prgnSrc);
78605b261ecSmrg    }
78705b261ecSmrg
78835c4bbdfSmrg out:
7896747b715Smrg    RegionUninit(&rgnDst);
79005b261ecSmrg    fbValidateDrawable(&pWin->drawable);
79105b261ecSmrg
79205b261ecSmrg    SCREEN_WRAP(pScreen, CopyWindow);
79305b261ecSmrg
79405b261ecSmrg    RL_DEBUG_MSG("copywindowFB end\n");
79505b261ecSmrg}
79605b261ecSmrg
79735c4bbdfSmrgvoid
79835c4bbdfSmrgRootlessPaintWindow(WindowPtr pWin, RegionPtr prgn, int what)
79935c4bbdfSmrg{
80035c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
80135c4bbdfSmrg
80235c4bbdfSmrg    if (IsFramedWindow(pWin)) {
80335c4bbdfSmrg        RootlessStartDrawing(pWin);
80435c4bbdfSmrg        RootlessDamageRegion(pWin, prgn);
80535c4bbdfSmrg
80635c4bbdfSmrg        if (pWin->backgroundState == ParentRelative) {
80735c4bbdfSmrg            if ((what == PW_BACKGROUND) ||
80835c4bbdfSmrg                (what == PW_BORDER && !pWin->borderIsPixel))
80935c4bbdfSmrg                RootlessSetPixmapOfAncestors(pWin);
81035c4bbdfSmrg        }
81135c4bbdfSmrg    }
81235c4bbdfSmrg
81335c4bbdfSmrg    SCREEN_UNWRAP(pScreen, PaintWindow);
81435c4bbdfSmrg    pScreen->PaintWindow(pWin, prgn, what);
81535c4bbdfSmrg    SCREEN_WRAP(pScreen, PaintWindow);
81635c4bbdfSmrg}
81705b261ecSmrg
81805b261ecSmrg/*
81905b261ecSmrg * Window resize procedures
82005b261ecSmrg */
82105b261ecSmrg
82205b261ecSmrgenum {
82305b261ecSmrg    WIDTH_SMALLER = 1,
82405b261ecSmrg    HEIGHT_SMALLER = 2,
82505b261ecSmrg};
82605b261ecSmrg
82705b261ecSmrg/*
82805b261ecSmrg * ResizeWeighting
82905b261ecSmrg *  Choose gravity to avoid local copies. Do that by looking for
83005b261ecSmrg *  a corner that doesn't move _relative to the screen_.
83105b261ecSmrg */
83205b261ecSmrgstatic inline unsigned int
83305b261ecSmrgResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
83405b261ecSmrg                int newX1, int newY1, int newX2, int newY2, int newBW)
83505b261ecSmrg{
83605b261ecSmrg#ifdef ROOTLESS_RESIZE_GRAVITY
83705b261ecSmrg    if (newBW != oldBW)
83805b261ecSmrg        return RL_GRAVITY_NONE;
83905b261ecSmrg
84005b261ecSmrg    if (newX1 == oldX1 && newY1 == oldY1)
84105b261ecSmrg        return RL_GRAVITY_NORTH_WEST;
84205b261ecSmrg    else if (newX1 == oldX1 && newY2 == oldY2)
84305b261ecSmrg        return RL_GRAVITY_SOUTH_WEST;
84405b261ecSmrg    else if (newX2 == oldX2 && newY2 == oldY2)
84505b261ecSmrg        return RL_GRAVITY_SOUTH_EAST;
84605b261ecSmrg    else if (newX2 == oldX2 && newY1 == oldY1)
84705b261ecSmrg        return RL_GRAVITY_NORTH_EAST;
84805b261ecSmrg    else
84905b261ecSmrg        return RL_GRAVITY_NONE;
85005b261ecSmrg#else
85105b261ecSmrg    return RL_GRAVITY_NONE;
85205b261ecSmrg#endif
85305b261ecSmrg}
85405b261ecSmrg
85505b261ecSmrg/*
85605b261ecSmrg * StartFrameResize
85705b261ecSmrg *  Prepare to resize a top-level window. The old window's pixels are
85805b261ecSmrg *  saved and the implementation is told to change the window size.
85905b261ecSmrg *  (x,y,w,h) is outer frame of window (outside border)
86005b261ecSmrg */
86105b261ecSmrgstatic Bool
86205b261ecSmrgStartFrameResize(WindowPtr pWin, Bool gravity,
86305b261ecSmrg                 int oldX, int oldY, int oldW, int oldH, int oldBW,
86405b261ecSmrg                 int newX, int newY, int newW, int newH, int newBW)
86505b261ecSmrg{
86605b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
86705b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
86805b261ecSmrg    Bool need_window_source = FALSE, resize_after = FALSE;
86905b261ecSmrg
87005b261ecSmrg    BoxRec rect;
87105b261ecSmrg    int oldX2, newX2;
87205b261ecSmrg    int oldY2, newY2;
87305b261ecSmrg    unsigned int weight;
87405b261ecSmrg
87505b261ecSmrg    oldX2 = oldX + oldW, newX2 = newX + newW;
87605b261ecSmrg    oldY2 = oldY + oldH, newY2 = newY + newH;
87705b261ecSmrg
87805b261ecSmrg    /* Decide which resize weighting to use */
87905b261ecSmrg    weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
88005b261ecSmrg                             newX, newY, newW, newH, newBW);
88105b261ecSmrg
88205b261ecSmrg    /* Compute intersection between old and new rects */
88305b261ecSmrg    rect.x1 = max(oldX, newX);
88405b261ecSmrg    rect.y1 = max(oldY, newY);
88505b261ecSmrg    rect.x2 = min(oldX2, newX2);
88605b261ecSmrg    rect.y2 = min(oldY2, newY2);
88705b261ecSmrg
88805b261ecSmrg    RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
88905b261ecSmrg    RL_DEBUG_MSG("%d %d %d %d %d   %d %d %d %d %d\n",
89035c4bbdfSmrg                 oldX, oldY, oldW, oldH, oldBW, newX, newY, newW, newH, newBW);
89105b261ecSmrg
89205b261ecSmrg    RootlessRedisplay(pWin);
89305b261ecSmrg
89405b261ecSmrg    /* If gravity is true, then we need to have a way of recovering all
89505b261ecSmrg       the original bits in the window for when X rearranges the contents
89605b261ecSmrg       based on the various gravity settings. The obvious way is to just
89705b261ecSmrg       snapshot the entire backing store before resizing it, but that
89805b261ecSmrg       it slow on large windows.
89905b261ecSmrg
90005b261ecSmrg       So the optimization here is to use the implementation's resize
90105b261ecSmrg       weighting options (if available) to allow us to reason about what
90205b261ecSmrg       is left in the backing store after the resize. We can then only
90305b261ecSmrg       copy what won't be there after the resize, and do a two-stage copy
90405b261ecSmrg       operation.
90505b261ecSmrg
90605b261ecSmrg       Most of these optimizations are only applied when the top-left
90705b261ecSmrg       corner of the window is fixed, since that's the common case. They
90805b261ecSmrg       could probably be extended with some thought. */
90905b261ecSmrg
91005b261ecSmrg    gResizeDeathCount = 0;
91105b261ecSmrg
91205b261ecSmrg    if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
91305b261ecSmrg        unsigned int code = 0;
91405b261ecSmrg
91505b261ecSmrg        /* Top left corner is anchored. We never need to copy the
91605b261ecSmrg           entire window. */
91705b261ecSmrg
91805b261ecSmrg        need_window_source = TRUE;
91905b261ecSmrg
92005b261ecSmrg        /* These comparisons were chosen to avoid setting bits when the sizes
92135c4bbdfSmrg           are the same. (So the fastest case automatically gets taken when
92235c4bbdfSmrg           dimensions are unchanging.) */
92305b261ecSmrg
92405b261ecSmrg        if (newW < oldW)
92505b261ecSmrg            code |= WIDTH_SMALLER;
92605b261ecSmrg        if (newH < oldH)
92705b261ecSmrg            code |= HEIGHT_SMALLER;
92805b261ecSmrg
92905b261ecSmrg        if (((code ^ (code >> 1)) & 1) == 0) {
93005b261ecSmrg            /* Both dimensions are either getting larger, or both
93105b261ecSmrg               are getting smaller. No need to copy anything. */
93205b261ecSmrg
93305b261ecSmrg            if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) {
93405b261ecSmrg                /* Since the window is getting smaller, we can do gravity
935ed6184dfSmrg                   repair on it with its current size, then resize it
93605b261ecSmrg                   afterwards. */
93705b261ecSmrg
93805b261ecSmrg                resize_after = TRUE;
93905b261ecSmrg            }
94005b261ecSmrg
94105b261ecSmrg            gResizeDeathCount = 1;
94205b261ecSmrg        }
94305b261ecSmrg        else {
94405b261ecSmrg            unsigned int copy_rowbytes, Bpp;
94505b261ecSmrg            unsigned int copy_rect_width, copy_rect_height;
94605b261ecSmrg            BoxRec copy_rect;
94705b261ecSmrg
94805b261ecSmrg            /* We can get away with a partial copy. 'rect' is the
94905b261ecSmrg               intersection between old and new bounds, so copy
95005b261ecSmrg               everything to the right of or below the intersection. */
95105b261ecSmrg
95205b261ecSmrg            RootlessStartDrawing(pWin);
95305b261ecSmrg
95405b261ecSmrg            if (code == WIDTH_SMALLER) {
95505b261ecSmrg                copy_rect.x1 = rect.x2;
95605b261ecSmrg                copy_rect.y1 = rect.y1;
95705b261ecSmrg                copy_rect.x2 = oldX2;
95805b261ecSmrg                copy_rect.y2 = oldY2;
95905b261ecSmrg            }
96005b261ecSmrg            else if (code == HEIGHT_SMALLER) {
96105b261ecSmrg                copy_rect.x1 = rect.x1;
96205b261ecSmrg                copy_rect.y1 = rect.y2;
96305b261ecSmrg                copy_rect.x2 = oldX2;
96405b261ecSmrg                copy_rect.y2 = oldY2;
96505b261ecSmrg            }
96605b261ecSmrg            else
9676747b715Smrg                OsAbort();
96805b261ecSmrg
96905b261ecSmrg            Bpp = winRec->win->drawable.bitsPerPixel / 8;
97005b261ecSmrg            copy_rect_width = copy_rect.x2 - copy_rect.x1;
97105b261ecSmrg            copy_rect_height = copy_rect.y2 - copy_rect.y1;
97205b261ecSmrg            copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31;
97335c4bbdfSmrg            gResizeDeathBits = xallocarray(copy_rowbytes, copy_rect_height);
97405b261ecSmrg
97505b261ecSmrg            if (copy_rect_width * copy_rect_height >
97635c4bbdfSmrg                rootless_CopyBytes_threshold &&
97735c4bbdfSmrg                SCREENREC(pScreen)->imp->CopyBytes) {
97835c4bbdfSmrg                SCREENREC(pScreen)->imp->CopyBytes(copy_rect_width * Bpp,
97935c4bbdfSmrg                                                   copy_rect_height,
98035c4bbdfSmrg                                                   ((char *) winRec->pixelData)
98135c4bbdfSmrg                                                   +
98235c4bbdfSmrg                                                   ((copy_rect.y1 -
98335c4bbdfSmrg                                                     oldY) *
98435c4bbdfSmrg                                                    winRec->bytesPerRow)
98535c4bbdfSmrg                                                   + (copy_rect.x1 -
98635c4bbdfSmrg                                                      oldX) * Bpp,
98735c4bbdfSmrg                                                   winRec->bytesPerRow,
98835c4bbdfSmrg                                                   gResizeDeathBits,
98935c4bbdfSmrg                                                   copy_rowbytes);
99035c4bbdfSmrg            }
99135c4bbdfSmrg            else {
99205b261ecSmrg                fbBlt((FbBits *) (winRec->pixelData
99335c4bbdfSmrg                                  +
99435c4bbdfSmrg                                  ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
99535c4bbdfSmrg                                  + (copy_rect.x1 - oldX) * Bpp),
99605b261ecSmrg                      winRec->bytesPerRow / sizeof(FbBits), 0,
99705b261ecSmrg                      (FbBits *) gResizeDeathBits,
99835c4bbdfSmrg                      copy_rowbytes / sizeof(FbBits), 0, copy_rect_width * Bpp,
99935c4bbdfSmrg                      copy_rect_height, GXcopy, FB_ALLONES, Bpp, 0, 0);
100005b261ecSmrg            }
100105b261ecSmrg
100205b261ecSmrg            gResizeDeathBounds[1] = copy_rect;
100305b261ecSmrg            gResizeDeathPix[1]
100405b261ecSmrg                = GetScratchPixmapHeader(pScreen, copy_rect_width,
100505b261ecSmrg                                         copy_rect_height,
100605b261ecSmrg                                         winRec->win->drawable.depth,
100705b261ecSmrg                                         winRec->win->drawable.bitsPerPixel,
100805b261ecSmrg                                         winRec->bytesPerRow,
100905b261ecSmrg                                         (void *) gResizeDeathBits);
101005b261ecSmrg
101105b261ecSmrg            SetPixmapBaseToScreen(gResizeDeathPix[1],
101205b261ecSmrg                                  copy_rect.x1, copy_rect.y1);
101305b261ecSmrg
101405b261ecSmrg            gResizeDeathCount = 2;
101505b261ecSmrg        }
101605b261ecSmrg    }
101705b261ecSmrg    else if (gravity) {
101805b261ecSmrg        /* The general case. Just copy everything. */
101905b261ecSmrg
102005b261ecSmrg        RootlessStartDrawing(pWin);
102105b261ecSmrg
102235c4bbdfSmrg        gResizeDeathBits = xallocarray(winRec->bytesPerRow, winRec->height);
102305b261ecSmrg
102405b261ecSmrg        memcpy(gResizeDeathBits, winRec->pixelData,
102505b261ecSmrg               winRec->bytesPerRow * winRec->height);
102605b261ecSmrg
102735c4bbdfSmrg        gResizeDeathBounds[0] = (BoxRec) {
102835c4bbdfSmrg        oldX, oldY, oldX2, oldY2};
102905b261ecSmrg        gResizeDeathPix[0]
103005b261ecSmrg            = GetScratchPixmapHeader(pScreen, winRec->width,
103105b261ecSmrg                                     winRec->height,
103205b261ecSmrg                                     winRec->win->drawable.depth,
103305b261ecSmrg                                     winRec->win->drawable.bitsPerPixel,
103405b261ecSmrg                                     winRec->bytesPerRow,
103505b261ecSmrg                                     (void *) gResizeDeathBits);
103605b261ecSmrg
103705b261ecSmrg        SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
103805b261ecSmrg        gResizeDeathCount = 1;
103905b261ecSmrg    }
104005b261ecSmrg
104105b261ecSmrg    RootlessStopDrawing(pWin, FALSE);
104205b261ecSmrg
104305b261ecSmrg    winRec->x = newX;
104405b261ecSmrg    winRec->y = newY;
104505b261ecSmrg    winRec->width = newW;
104605b261ecSmrg    winRec->height = newH;
104705b261ecSmrg    winRec->borderWidth = newBW;
104805b261ecSmrg
104905b261ecSmrg    /* Unless both dimensions are getting smaller, Resize the frame
105005b261ecSmrg       before doing gravity repair */
105105b261ecSmrg
105205b261ecSmrg    if (!resize_after) {
105305b261ecSmrg        SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
105405b261ecSmrg                                             newX + SCREEN_TO_GLOBAL_X,
105505b261ecSmrg                                             newY + SCREEN_TO_GLOBAL_Y,
105605b261ecSmrg                                             newW, newH, weight);
105705b261ecSmrg    }
105805b261ecSmrg
105905b261ecSmrg    RootlessStartDrawing(pWin);
106005b261ecSmrg
106105b261ecSmrg    /* If necessary, create a source pixmap pointing at the current
106205b261ecSmrg       window bits. */
106305b261ecSmrg
106405b261ecSmrg    if (need_window_source) {
106535c4bbdfSmrg        gResizeDeathBounds[0] = (BoxRec) {
106635c4bbdfSmrg        oldX, oldY, oldX2, oldY2};
106705b261ecSmrg        gResizeDeathPix[0]
106805b261ecSmrg            = GetScratchPixmapHeader(pScreen, oldW, oldH,
106905b261ecSmrg                                     winRec->win->drawable.depth,
107005b261ecSmrg                                     winRec->win->drawable.bitsPerPixel,
107105b261ecSmrg                                     winRec->bytesPerRow, winRec->pixelData);
107205b261ecSmrg
107305b261ecSmrg        SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
107405b261ecSmrg    }
107505b261ecSmrg
107605b261ecSmrg    /* Use custom CopyWindow when moving gravity bits around
107705b261ecSmrg       ResizeWindow assumes the old window contents are in the same
107805b261ecSmrg       pixmap, but here they're in deathPix instead. */
107905b261ecSmrg
108005b261ecSmrg    if (gravity) {
108105b261ecSmrg        gResizeOldCopyWindowProc = pScreen->CopyWindow;
108205b261ecSmrg        pScreen->CopyWindow = RootlessResizeCopyWindow;
108305b261ecSmrg    }
108405b261ecSmrg
108505b261ecSmrg    /* If we can't rely on the window server preserving the bits we
108605b261ecSmrg       need in the position we need, copy the pixels in the
108705b261ecSmrg       intersection from src to dst. ResizeWindow assumes these pixels
108805b261ecSmrg       are already present when making gravity adjustments. pWin
108905b261ecSmrg       currently has new-sized pixmap but is in old position.
109005b261ecSmrg
109105b261ecSmrg       FIXME: border width change! (?) */
109205b261ecSmrg
109305b261ecSmrg    if (gravity && weight == RL_GRAVITY_NONE) {
109405b261ecSmrg        PixmapPtr src, dst;
109505b261ecSmrg
109605b261ecSmrg        assert(gResizeDeathCount == 1);
109705b261ecSmrg
109805b261ecSmrg        src = gResizeDeathPix[0];
109905b261ecSmrg        dst = pScreen->GetWindowPixmap(pWin);
110005b261ecSmrg
110105b261ecSmrg        RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
110205b261ecSmrg                     rect.x1, rect.y1, rect.x2, rect.y2);
110305b261ecSmrg
110405b261ecSmrg        /* rect is the intersection of the old location and new location */
110505b261ecSmrg        if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) {
110605b261ecSmrg            /* The window drawable still has the old frame position, which
110705b261ecSmrg               means that DST doesn't actually point at the origin of our
110805b261ecSmrg               physical backing store when adjusted by the drawable.x,y
110905b261ecSmrg               position. So sneakily adjust it temporarily while copying.. */
111005b261ecSmrg
111105b261ecSmrg            ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
111205b261ecSmrg            SetPixmapBaseToScreen(dst, newX, newY);
111305b261ecSmrg
111405b261ecSmrg            fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
111505b261ecSmrg                             &rect, 1, 0, 0, FALSE, FALSE, 0, 0);
111605b261ecSmrg
111705b261ecSmrg            ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
111805b261ecSmrg            SetPixmapBaseToScreen(dst, oldX, oldY);
111905b261ecSmrg        }
112005b261ecSmrg    }
112105b261ecSmrg
112205b261ecSmrg    return resize_after;
112305b261ecSmrg}
112405b261ecSmrg
112505b261ecSmrgstatic void
112605b261ecSmrgFinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY,
112705b261ecSmrg                  unsigned int oldW, unsigned int oldH, unsigned int oldBW,
112805b261ecSmrg                  int newX, int newY, unsigned int newW, unsigned int newH,
112905b261ecSmrg                  unsigned int newBW, Bool resize_now)
113005b261ecSmrg{
113105b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
113205b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
113305b261ecSmrg    int i;
113405b261ecSmrg
113505b261ecSmrg    RootlessStopDrawing(pWin, FALSE);
113605b261ecSmrg
113705b261ecSmrg    if (resize_now) {
113805b261ecSmrg        unsigned int weight;
113905b261ecSmrg
114005b261ecSmrg        /* We didn't resize anything earlier, so do it now, now that
114105b261ecSmrg           we've finished gravitating the bits. */
114205b261ecSmrg
114305b261ecSmrg        weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
114405b261ecSmrg                                 newX, newY, newW, newH, newBW);
114505b261ecSmrg
114605b261ecSmrg        SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
114705b261ecSmrg                                             newX + SCREEN_TO_GLOBAL_X,
114805b261ecSmrg                                             newY + SCREEN_TO_GLOBAL_Y,
114905b261ecSmrg                                             newW, newH, weight);
115005b261ecSmrg    }
115105b261ecSmrg
115205b261ecSmrg    /* Redraw everything. FIXME: there must be times when we don't need
115305b261ecSmrg       to do this. Perhaps when top-left weighting and no gravity? */
115405b261ecSmrg
115505b261ecSmrg    RootlessDamageRect(pWin, -newBW, -newBW, newW, newH);
115605b261ecSmrg
115705b261ecSmrg    for (i = 0; i < 2; i++) {
115805b261ecSmrg        if (gResizeDeathPix[i] != NULL) {
115905b261ecSmrg            FreeScratchPixmapHeader(gResizeDeathPix[i]);
116005b261ecSmrg            gResizeDeathPix[i] = NULL;
116105b261ecSmrg        }
116205b261ecSmrg    }
116305b261ecSmrg
11649ace9065Smrg    free(gResizeDeathBits);
11659ace9065Smrg    gResizeDeathBits = NULL;
116605b261ecSmrg
116705b261ecSmrg    if (gravity) {
116805b261ecSmrg        pScreen->CopyWindow = gResizeOldCopyWindowProc;
116905b261ecSmrg    }
117005b261ecSmrg}
117105b261ecSmrg
117205b261ecSmrg/*
117305b261ecSmrg * RootlessMoveWindow
117405b261ecSmrg *  If kind==VTOther, window border is resizing (and borderWidth is
117505b261ecSmrg *  already changed!!@#$)  This case works like window resize, not move.
117605b261ecSmrg */
117705b261ecSmrgvoid
117805b261ecSmrgRootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
117905b261ecSmrg{
118005b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
118105b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
118205b261ecSmrg    CopyWindowProcPtr oldCopyWindowProc = NULL;
118305b261ecSmrg    int oldX = 0, oldY = 0, newX = 0, newY = 0;
118405b261ecSmrg    unsigned int oldW = 0, oldH = 0, oldBW = 0;
118505b261ecSmrg    unsigned int newW = 0, newH = 0, newBW = 0;
118605b261ecSmrg    Bool resize_after = FALSE;
118705b261ecSmrg    RegionRec saveRoot;
118805b261ecSmrg
118905b261ecSmrg    RL_DEBUG_MSG("movewindow start \n");
119005b261ecSmrg
119105b261ecSmrg    if (winRec) {
119205b261ecSmrg        if (kind == VTMove) {
119305b261ecSmrg            oldX = winRec->x;
119405b261ecSmrg            oldY = winRec->y;
119505b261ecSmrg            RootlessRedisplay(pWin);
119605b261ecSmrg            RootlessStartDrawing(pWin);
119735c4bbdfSmrg        }
119835c4bbdfSmrg        else {
119905b261ecSmrg            RL_DEBUG_MSG("movewindow border resizing ");
120005b261ecSmrg
120105b261ecSmrg            oldBW = winRec->borderWidth;
120205b261ecSmrg            oldX = winRec->x;
120305b261ecSmrg            oldY = winRec->y;
120405b261ecSmrg            oldW = winRec->width;
120505b261ecSmrg            oldH = winRec->height;
120605b261ecSmrg
120705b261ecSmrg            newBW = wBorderWidth(pWin);
120805b261ecSmrg            newX = x;
120905b261ecSmrg            newY = y;
121035c4bbdfSmrg            newW = pWin->drawable.width + 2 * newBW;
121135c4bbdfSmrg            newH = pWin->drawable.height + 2 * newBW;
121205b261ecSmrg
121305b261ecSmrg            resize_after = StartFrameResize(pWin, FALSE,
121405b261ecSmrg                                            oldX, oldY, oldW, oldH, oldBW,
121505b261ecSmrg                                            newX, newY, newW, newH, newBW);
121605b261ecSmrg        }
121705b261ecSmrg    }
121805b261ecSmrg
121905b261ecSmrg    HUGE_ROOT(pWin);
122005b261ecSmrg    SCREEN_UNWRAP(pScreen, MoveWindow);
122105b261ecSmrg
122205b261ecSmrg    if (winRec) {
122305b261ecSmrg        oldCopyWindowProc = pScreen->CopyWindow;
122405b261ecSmrg        pScreen->CopyWindow = RootlessNoCopyWindow;
122505b261ecSmrg    }
122605b261ecSmrg    pScreen->MoveWindow(pWin, x, y, pSib, kind);
122705b261ecSmrg    if (winRec) {
122805b261ecSmrg        pScreen->CopyWindow = oldCopyWindowProc;
122905b261ecSmrg    }
123005b261ecSmrg
123105b261ecSmrg    NORMAL_ROOT(pWin);
123205b261ecSmrg    SCREEN_WRAP(pScreen, MoveWindow);
123305b261ecSmrg
123405b261ecSmrg    if (winRec) {
123505b261ecSmrg        if (kind == VTMove) {
123605b261ecSmrg            winRec->x = x;
123705b261ecSmrg            winRec->y = y;
123805b261ecSmrg            RootlessStopDrawing(pWin, FALSE);
123905b261ecSmrg            SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
124005b261ecSmrg                                               x + SCREEN_TO_GLOBAL_X,
124105b261ecSmrg                                               y + SCREEN_TO_GLOBAL_Y);
124235c4bbdfSmrg        }
124335c4bbdfSmrg        else {
124405b261ecSmrg            FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
124505b261ecSmrg                              newX, newY, newW, newH, newBW, resize_after);
124605b261ecSmrg        }
124705b261ecSmrg    }
124805b261ecSmrg
124905b261ecSmrg    RL_DEBUG_MSG("movewindow end\n");
125005b261ecSmrg}
125105b261ecSmrg
125205b261ecSmrg/*
125305b261ecSmrg * RootlessResizeWindow
125405b261ecSmrg *  Note: (x, y, w, h) as passed to this procedure don't match the frame
125505b261ecSmrg *  definition. (x,y) is corner of very outer edge, *outside* border.
125605b261ecSmrg *  w,h is width and height *inside* border, *ignoring* border width.
125705b261ecSmrg *  The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw)
125805b261ecSmrg *  is total rect and (x+bw, y+bw, w, h) is inner rect.
125905b261ecSmrg */
126005b261ecSmrgvoid
126105b261ecSmrgRootlessResizeWindow(WindowPtr pWin, int x, int y,
126205b261ecSmrg                     unsigned int w, unsigned int h, WindowPtr pSib)
126305b261ecSmrg{
126405b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
126505b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
126605b261ecSmrg    int oldX = 0, oldY = 0, newX = 0, newY = 0;
126705b261ecSmrg    unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0;
126805b261ecSmrg    Bool resize_after = FALSE;
126905b261ecSmrg    RegionRec saveRoot;
127005b261ecSmrg
127105b261ecSmrg    RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin);
127235c4bbdfSmrg
127335c4bbdfSmrg    if (pWin->parent) {
12744642e01fSmrg        if (winRec) {
12754642e01fSmrg            oldBW = winRec->borderWidth;
12764642e01fSmrg            oldX = winRec->x;
12774642e01fSmrg            oldY = winRec->y;
12784642e01fSmrg            oldW = winRec->width;
12794642e01fSmrg            oldH = winRec->height;
128005b261ecSmrg
12814642e01fSmrg            newBW = oldBW;
12824642e01fSmrg            newX = x;
12834642e01fSmrg            newY = y;
128435c4bbdfSmrg            newW = w + 2 * newBW;
128535c4bbdfSmrg            newH = h + 2 * newBW;
128605b261ecSmrg
12874642e01fSmrg            resize_after = StartFrameResize(pWin, TRUE,
12884642e01fSmrg                                            oldX, oldY, oldW, oldH, oldBW,
12894642e01fSmrg                                            newX, newY, newW, newH, newBW);
12904642e01fSmrg        }
129105b261ecSmrg
12924642e01fSmrg        HUGE_ROOT(pWin);
12934642e01fSmrg        SCREEN_UNWRAP(pScreen, ResizeWindow);
12944642e01fSmrg        pScreen->ResizeWindow(pWin, x, y, w, h, pSib);
12954642e01fSmrg        SCREEN_WRAP(pScreen, ResizeWindow);
12964642e01fSmrg        NORMAL_ROOT(pWin);
12974642e01fSmrg
12984642e01fSmrg        if (winRec) {
12994642e01fSmrg            FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
13004642e01fSmrg                              newX, newY, newW, newH, newBW, resize_after);
13014642e01fSmrg        }
130235c4bbdfSmrg    }
130335c4bbdfSmrg    else {
13044642e01fSmrg        /* Special case for resizing the root window */
13054642e01fSmrg        BoxRec box;
13064642e01fSmrg
13074642e01fSmrg        pWin->drawable.x = x;
13084642e01fSmrg        pWin->drawable.y = y;
13094642e01fSmrg        pWin->drawable.width = w;
13104642e01fSmrg        pWin->drawable.height = h;
13114642e01fSmrg
131235c4bbdfSmrg        box.x1 = x;
131335c4bbdfSmrg        box.y1 = y;
131435c4bbdfSmrg        box.x2 = x + w;
131535c4bbdfSmrg        box.y2 = y + h;
13166747b715Smrg        RegionUninit(&pWin->winSize);
13176747b715Smrg        RegionInit(&pWin->winSize, &box, 1);
13186747b715Smrg        RegionCopy(&pWin->borderSize, &pWin->winSize);
13196747b715Smrg        RegionCopy(&pWin->clipList, &pWin->winSize);
13206747b715Smrg        RegionCopy(&pWin->borderClip, &pWin->winSize);
13216747b715Smrg
13226747b715Smrg        if (winRec) {
13236747b715Smrg            SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
13246747b715Smrg                                                 x + SCREEN_TO_GLOBAL_X,
13256747b715Smrg                                                 y + SCREEN_TO_GLOBAL_Y,
13266747b715Smrg                                                 w, h, RL_GRAVITY_NONE);
13276747b715Smrg        }
13284642e01fSmrg
13294642e01fSmrg        miSendExposures(pWin, &pWin->borderClip,
133035c4bbdfSmrg                        pWin->drawable.x, pWin->drawable.y);
133105b261ecSmrg    }
133205b261ecSmrg
133305b261ecSmrg    RL_DEBUG_MSG("resizewindow end\n");
133405b261ecSmrg}
133505b261ecSmrg
133605b261ecSmrg/*
133705b261ecSmrg * RootlessRepositionWindow
133805b261ecSmrg *  Called by the implementation when a window needs to be repositioned to
133905b261ecSmrg *  its correct location on the screen. This routine is typically needed
134005b261ecSmrg *  due to changes in the underlying window system, such as a screen layout
134105b261ecSmrg *  change.
134205b261ecSmrg */
134305b261ecSmrgvoid
134405b261ecSmrgRootlessRepositionWindow(WindowPtr pWin)
134505b261ecSmrg{
134605b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
134705b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
134805b261ecSmrg
134905b261ecSmrg    if (winRec == NULL)
135005b261ecSmrg        return;
135105b261ecSmrg
135205b261ecSmrg    RootlessStopDrawing(pWin, FALSE);
135305b261ecSmrg    SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
135405b261ecSmrg                                       winRec->x + SCREEN_TO_GLOBAL_X,
135505b261ecSmrg                                       winRec->y + SCREEN_TO_GLOBAL_Y);
135605b261ecSmrg
135705b261ecSmrg    RootlessReorderWindow(pWin);
135805b261ecSmrg}
135905b261ecSmrg
136005b261ecSmrg/*
136105b261ecSmrg * RootlessReparentWindow
136205b261ecSmrg *  Called after a window has been reparented. Generally windows are not
136305b261ecSmrg *  framed until they are mapped. However, a window may be framed early by the
136405b261ecSmrg *  implementation calling RootlessFrameForWindow. (e.g. this could be needed
136505b261ecSmrg *  to attach a VRAM surface to it.) If the window is subsequently reparented
136605b261ecSmrg *  by the window manager before being mapped, we need to give the frame to
136705b261ecSmrg *  the new top-level window.
136805b261ecSmrg */
136905b261ecSmrgvoid
137005b261ecSmrgRootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
137105b261ecSmrg{
137205b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
137305b261ecSmrg    RootlessWindowRec *winRec = WINREC(pWin);
137405b261ecSmrg    WindowPtr pTopWin;
137505b261ecSmrg
137605b261ecSmrg    /* Check that window is not top-level now, but used to be. */
137705b261ecSmrg    if (IsRoot(pWin) || IsRoot(pWin->parent)
137835c4bbdfSmrg        || IsTopLevel(pWin) || winRec == NULL) {
137905b261ecSmrg        goto out;
138005b261ecSmrg    }
138105b261ecSmrg
138205b261ecSmrg    /* If the formerly top-level window has a frame, we want to give the
138305b261ecSmrg       frame to its new top-level parent. If we can't do that, we'll just
138405b261ecSmrg       have to jettison it... */
138505b261ecSmrg
138605b261ecSmrg    pTopWin = TopLevelParent(pWin);
138705b261ecSmrg    assert(pTopWin != pWin);
138835c4bbdfSmrg
138935c4bbdfSmrg    pWin->unhittable = FALSE;
139035c4bbdfSmrg
139135c4bbdfSmrg    DeleteProperty(serverClient, pWin, xa_native_window_id());
139205b261ecSmrg
139305b261ecSmrg    if (WINREC(pTopWin) != NULL) {
139405b261ecSmrg        /* We're screwed. */
139505b261ecSmrg        RootlessDestroyFrame(pWin, winRec);
139635c4bbdfSmrg    }
139735c4bbdfSmrg    else {
139805b261ecSmrg        if (!pTopWin->realized && pWin->realized) {
139905b261ecSmrg            SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
140005b261ecSmrg        }
140105b261ecSmrg
140205b261ecSmrg        /* Switch the frame record from one to the other. */
140305b261ecSmrg
14044642e01fSmrg        SETWINREC(pWin, NULL);
14054642e01fSmrg        SETWINREC(pTopWin, winRec);
140605b261ecSmrg
140705b261ecSmrg        RootlessInitializeFrame(pTopWin, winRec);
140805b261ecSmrg        RootlessReshapeFrame(pTopWin);
140905b261ecSmrg
141005b261ecSmrg        SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
141105b261ecSmrg                                             winRec->x + SCREEN_TO_GLOBAL_X,
141205b261ecSmrg                                             winRec->y + SCREEN_TO_GLOBAL_Y,
141305b261ecSmrg                                             winRec->width, winRec->height,
141405b261ecSmrg                                             RL_GRAVITY_NONE);
141505b261ecSmrg
141605b261ecSmrg        if (SCREENREC(pScreen)->imp->SwitchWindow) {
141705b261ecSmrg            SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
141805b261ecSmrg        }
141905b261ecSmrg
142005b261ecSmrg        if (pTopWin->realized && !pWin->realized)
142105b261ecSmrg            winRec->is_reorder_pending = TRUE;
142205b261ecSmrg    }
142305b261ecSmrg
142435c4bbdfSmrg out:
142505b261ecSmrg    if (SCREENREC(pScreen)->ReparentWindow) {
142605b261ecSmrg        SCREEN_UNWRAP(pScreen, ReparentWindow);
142705b261ecSmrg        pScreen->ReparentWindow(pWin, pPriorParent);
142805b261ecSmrg        SCREEN_WRAP(pScreen, ReparentWindow);
142905b261ecSmrg    }
143005b261ecSmrg}
143105b261ecSmrg
143205b261ecSmrgvoid
143335c4bbdfSmrgRootlessFlushWindowColormap(WindowPtr pWin)
143405b261ecSmrg{
143535c4bbdfSmrg    RootlessWindowRec *winRec = WINREC(pWin);
143635c4bbdfSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
143705b261ecSmrg
143835c4bbdfSmrg    if (winRec == NULL)
143935c4bbdfSmrg        return;
144005b261ecSmrg
144135c4bbdfSmrg    RootlessStopDrawing(pWin, FALSE);
144205b261ecSmrg
144335c4bbdfSmrg    if (SCREENREC(pScreen)->imp->UpdateColormap)
144435c4bbdfSmrg        SCREENREC(pScreen)->imp->UpdateColormap(winRec->wid, pScreen);
144505b261ecSmrg}
144605b261ecSmrg
144705b261ecSmrg/*
144805b261ecSmrg * RootlessChangeBorderWidth
144905b261ecSmrg *  FIXME: untested!
145005b261ecSmrg *  pWin inside corner stays the same; pWin->drawable.[xy] stays the same
145105b261ecSmrg *  Frame moves and resizes.
145205b261ecSmrg */
145305b261ecSmrgvoid
145405b261ecSmrgRootlessChangeBorderWidth(WindowPtr pWin, unsigned int width)
145505b261ecSmrg{
145605b261ecSmrg    RegionRec saveRoot;
145705b261ecSmrg    Bool resize_after = FALSE;
145805b261ecSmrg
145905b261ecSmrg    RL_DEBUG_MSG("change border width ");
146005b261ecSmrg
146105b261ecSmrg    if (width != wBorderWidth(pWin)) {
146205b261ecSmrg        RootlessWindowRec *winRec = WINREC(pWin);
146305b261ecSmrg        int oldX = 0, oldY = 0, newX = 0, newY = 0;
146405b261ecSmrg        unsigned int oldW = 0, oldH = 0, oldBW = 0;
146505b261ecSmrg        unsigned int newW = 0, newH = 0, newBW = 0;
146605b261ecSmrg
146705b261ecSmrg        if (winRec) {
146805b261ecSmrg            oldBW = winRec->borderWidth;
146905b261ecSmrg            oldX = winRec->x;
147005b261ecSmrg            oldY = winRec->y;
147105b261ecSmrg            oldW = winRec->width;
147205b261ecSmrg            oldH = winRec->height;
147305b261ecSmrg
147405b261ecSmrg            newBW = width;
147505b261ecSmrg            newX = pWin->drawable.x - newBW;
147605b261ecSmrg            newY = pWin->drawable.y - newBW;
147735c4bbdfSmrg            newW = pWin->drawable.width + 2 * newBW;
147835c4bbdfSmrg            newH = pWin->drawable.height + 2 * newBW;
147905b261ecSmrg
148005b261ecSmrg            resize_after = StartFrameResize(pWin, FALSE,
148105b261ecSmrg                                            oldX, oldY, oldW, oldH, oldBW,
148205b261ecSmrg                                            newX, newY, newW, newH, newBW);
148305b261ecSmrg        }
148405b261ecSmrg
148505b261ecSmrg        HUGE_ROOT(pWin);
148605b261ecSmrg        SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth);
148705b261ecSmrg        pWin->drawable.pScreen->ChangeBorderWidth(pWin, width);
148805b261ecSmrg        SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth);
148905b261ecSmrg        NORMAL_ROOT(pWin);
149005b261ecSmrg
149105b261ecSmrg        if (winRec) {
149205b261ecSmrg            FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
149305b261ecSmrg                              newX, newY, newW, newH, newBW, resize_after);
149405b261ecSmrg        }
149505b261ecSmrg    }
149605b261ecSmrg
149705b261ecSmrg    RL_DEBUG_MSG("change border width end\n");
149805b261ecSmrg}
14994642e01fSmrg
15004642e01fSmrg/*
15014642e01fSmrg * RootlessOrderAllWindows
15024642e01fSmrg * Brings all X11 windows to the top of the window stack
15034642e01fSmrg * (i.e in front of Aqua windows) -- called when X11.app is given focus
15044642e01fSmrg */
15054642e01fSmrgvoid
150635c4bbdfSmrgRootlessOrderAllWindows(Bool include_unhitable)
15074642e01fSmrg{
15084642e01fSmrg    int i;
15094642e01fSmrg    WindowPtr pWin;
15104642e01fSmrg
15114642e01fSmrg    if (windows_hidden)
151235c4bbdfSmrg        return;
15134642e01fSmrg
15144642e01fSmrg    RL_DEBUG_MSG("RootlessOrderAllWindows() ");
15154642e01fSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
151635c4bbdfSmrg        if (screenInfo.screens[i] == NULL)
151735c4bbdfSmrg            continue;
151835c4bbdfSmrg        pWin = screenInfo.screens[i]->root;
151935c4bbdfSmrg        if (pWin == NULL)
152035c4bbdfSmrg            continue;
152135c4bbdfSmrg
152235c4bbdfSmrg        for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
152335c4bbdfSmrg            if (!pWin->realized)
152435c4bbdfSmrg                continue;
152535c4bbdfSmrg            if (RootlessEnsureFrame(pWin) == NULL)
152635c4bbdfSmrg                continue;
152735c4bbdfSmrg            if (!include_unhitable && pWin->unhittable)
152835c4bbdfSmrg                continue;
152935c4bbdfSmrg            RootlessReorderWindow(pWin);
153035c4bbdfSmrg        }
15314642e01fSmrg    }
15324642e01fSmrg    RL_DEBUG_MSG("RootlessOrderAllWindows() done");
15334642e01fSmrg}
15344642e01fSmrg
15354642e01fSmrgvoid
153635c4bbdfSmrgRootlessEnableRoot(ScreenPtr pScreen)
15374642e01fSmrg{
15384642e01fSmrg    WindowPtr pRoot;
153935c4bbdfSmrg
15406747b715Smrg    pRoot = pScreen->root;
154135c4bbdfSmrg
154235c4bbdfSmrg    RootlessEnsureFrame(pRoot);
15434642e01fSmrg    (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE);
154435c4bbdfSmrg    RootlessReorderWindow(pRoot);
15454642e01fSmrg}
15464642e01fSmrg
15474642e01fSmrgvoid
154835c4bbdfSmrgRootlessDisableRoot(ScreenPtr pScreen)
15494642e01fSmrg{
15504642e01fSmrg    WindowPtr pRoot;
15514642e01fSmrg    RootlessWindowRec *winRec;
15524642e01fSmrg
15536747b715Smrg    pRoot = pScreen->root;
155435c4bbdfSmrg    winRec = WINREC(pRoot);
15554642e01fSmrg
15564642e01fSmrg    if (NULL == winRec)
155735c4bbdfSmrg        return;
155835c4bbdfSmrg
155935c4bbdfSmrg    RootlessDestroyFrame(pRoot, winRec);
156035c4bbdfSmrg    DeleteProperty(serverClient, pRoot, xa_native_window_id());
15614642e01fSmrg}
15624642e01fSmrg
15634642e01fSmrgvoid
156435c4bbdfSmrgRootlessHideAllWindows(void)
15654642e01fSmrg{
15664642e01fSmrg    int i;
15674642e01fSmrg    ScreenPtr pScreen;
15684642e01fSmrg    WindowPtr pWin;
15694642e01fSmrg    RootlessWindowRec *winRec;
157035c4bbdfSmrg
15714642e01fSmrg    if (windows_hidden)
15724642e01fSmrg        return;
157335c4bbdfSmrg
15744642e01fSmrg    windows_hidden = TRUE;
157535c4bbdfSmrg
157635c4bbdfSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
15774642e01fSmrg        pScreen = screenInfo.screens[i];
157835c4bbdfSmrg        if (pScreen == NULL)
157935c4bbdfSmrg            continue;
158035c4bbdfSmrg        pWin = pScreen->root;
158135c4bbdfSmrg        if (pWin == NULL)
15824642e01fSmrg            continue;
158335c4bbdfSmrg
158435c4bbdfSmrg        for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
15854642e01fSmrg            if (!pWin->realized)
15864642e01fSmrg                continue;
158735c4bbdfSmrg
158835c4bbdfSmrg            RootlessStopDrawing(pWin, FALSE);
158935c4bbdfSmrg
159035c4bbdfSmrg            winRec = WINREC(pWin);
159135c4bbdfSmrg            if (winRec != NULL) {
159235c4bbdfSmrg                if (SCREENREC(pScreen)->imp->HideWindow)
159335c4bbdfSmrg                    SCREENREC(pScreen)->imp->HideWindow(winRec->wid);
15944642e01fSmrg            }
15954642e01fSmrg        }
15964642e01fSmrg    }
15974642e01fSmrg}
15984642e01fSmrg
15994642e01fSmrgvoid
160035c4bbdfSmrgRootlessShowAllWindows(void)
16014642e01fSmrg{
16024642e01fSmrg    int i;
16034642e01fSmrg    ScreenPtr pScreen;
16044642e01fSmrg    WindowPtr pWin;
16054642e01fSmrg    RootlessWindowRec *winRec;
160635c4bbdfSmrg
16074642e01fSmrg    if (!windows_hidden)
16084642e01fSmrg        return;
160935c4bbdfSmrg
16104642e01fSmrg    windows_hidden = FALSE;
161135c4bbdfSmrg
161235c4bbdfSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
16134642e01fSmrg        pScreen = screenInfo.screens[i];
161435c4bbdfSmrg        if (pScreen == NULL)
161535c4bbdfSmrg            continue;
161635c4bbdfSmrg        pWin = pScreen->root;
161735c4bbdfSmrg        if (pWin == NULL)
16184642e01fSmrg            continue;
161935c4bbdfSmrg
162035c4bbdfSmrg        for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
16214642e01fSmrg            if (!pWin->realized)
16224642e01fSmrg                continue;
162335c4bbdfSmrg
162435c4bbdfSmrg            winRec = RootlessEnsureFrame(pWin);
16254642e01fSmrg            if (winRec == NULL)
16264642e01fSmrg                continue;
162735c4bbdfSmrg
162835c4bbdfSmrg            RootlessReorderWindow(pWin);
16294642e01fSmrg        }
163035c4bbdfSmrg
163135c4bbdfSmrg        RootlessScreenExpose(pScreen);
16324642e01fSmrg    }
16334642e01fSmrg}
16346747b715Smrg
16356747b715Smrg/*
16366747b715Smrg * SetPixmapOfAncestors
16376747b715Smrg *  Set the Pixmaps on all ParentRelative windows up the ancestor chain.
16386747b715Smrg */
16396747b715Smrgvoid
16406747b715SmrgRootlessSetPixmapOfAncestors(WindowPtr pWin)
16416747b715Smrg{
16426747b715Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
16436747b715Smrg    WindowPtr topWin = TopLevelParent(pWin);
16446747b715Smrg    RootlessWindowRec *topWinRec = WINREC(topWin);
164535c4bbdfSmrg
16466747b715Smrg    while (pWin->backgroundState == ParentRelative) {
16476747b715Smrg        if (pWin == topWin) {
16486747b715Smrg            // disallow ParentRelative background state on top level
16496747b715Smrg            XID pixel = 0;
165035c4bbdfSmrg
16516747b715Smrg            ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
16526747b715Smrg            RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
16536747b715Smrg            break;
16546747b715Smrg        }
165535c4bbdfSmrg
16566747b715Smrg        pWin = pWin->parent;
16576747b715Smrg        pScreen->SetWindowPixmap(pWin, topWinRec->pixmap);
16586747b715Smrg    }
16596747b715Smrg}
1660