105b261ecSmrg/*
205b261ecSmrg * Screen routines for generic rootless X server
305b261ecSmrg */
405b261ecSmrg/*
505b261ecSmrg * Copyright (c) 2001 Greg Parker. All Rights Reserved.
605b261ecSmrg * Copyright (c) 2002-2003 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 "mi.h"
3705b261ecSmrg#include "scrnintstr.h"
3805b261ecSmrg#include "gcstruct.h"
3905b261ecSmrg#include "pixmapstr.h"
4005b261ecSmrg#include "windowstr.h"
4105b261ecSmrg#include "propertyst.h"
4205b261ecSmrg#include "mivalidate.h"
4305b261ecSmrg#include "picturestr.h"
444642e01fSmrg#include "colormapst.h"
4505b261ecSmrg
4605b261ecSmrg#include <sys/types.h>
4705b261ecSmrg#include <sys/stat.h>
4805b261ecSmrg#include <fcntl.h>
4905b261ecSmrg#include <string.h>
5005b261ecSmrg
5105b261ecSmrg#include "rootlessCommon.h"
5205b261ecSmrg#include "rootlessWindow.h"
5305b261ecSmrg
5405b261ecSmrgextern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild,
5505b261ecSmrg                                  VTKind kind);
5605b261ecSmrgextern Bool RootlessCreateGC(GCPtr pGC);
5705b261ecSmrg
5805b261ecSmrg// Initialize globals
596747b715SmrgDevPrivateKeyRec rootlessGCPrivateKeyRec;
606747b715SmrgDevPrivateKeyRec rootlessScreenPrivateKeyRec;
616747b715SmrgDevPrivateKeyRec rootlessWindowPrivateKeyRec;
626747b715SmrgDevPrivateKeyRec rootlessWindowOldPixmapPrivateKeyRec;
6305b261ecSmrg
6405b261ecSmrg/*
6505b261ecSmrg * RootlessUpdateScreenPixmap
6605b261ecSmrg *  miCreateScreenResources does not like a null framebuffer pointer,
6705b261ecSmrg *  it leaves the screen pixmap with an uninitialized data pointer.
6805b261ecSmrg *  Thus, rootless implementations typically set the framebuffer width
6905b261ecSmrg *  to zero so that miCreateScreenResources does not allocate a screen
7005b261ecSmrg *  pixmap for us. We allocate our own screen pixmap here since we need
7105b261ecSmrg *  the screen pixmap to be valid (e.g. CopyArea from the root window).
7205b261ecSmrg */
7305b261ecSmrgvoid
7405b261ecSmrgRootlessUpdateScreenPixmap(ScreenPtr pScreen)
7505b261ecSmrg{
7605b261ecSmrg    RootlessScreenRec *s = SCREENREC(pScreen);
7705b261ecSmrg    PixmapPtr pPix;
7805b261ecSmrg    unsigned int rowbytes;
7905b261ecSmrg
8035c4bbdfSmrg    pPix = (*pScreen->GetScreenPixmap) (pScreen);
8105b261ecSmrg    if (pPix == NULL) {
8235c4bbdfSmrg        pPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
8335c4bbdfSmrg        (*pScreen->SetScreenPixmap) (pPix);
8405b261ecSmrg    }
8505b261ecSmrg
8605b261ecSmrg    rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth);
8705b261ecSmrg
8805b261ecSmrg    if (s->pixmap_data_size < rowbytes) {
899ace9065Smrg        free(s->pixmap_data);
9005b261ecSmrg
9105b261ecSmrg        s->pixmap_data_size = rowbytes;
926747b715Smrg        s->pixmap_data = malloc(s->pixmap_data_size);
9305b261ecSmrg        if (s->pixmap_data == NULL)
9405b261ecSmrg            return;
9505b261ecSmrg
9605b261ecSmrg        memset(s->pixmap_data, 0xFF, s->pixmap_data_size);
9705b261ecSmrg
9805b261ecSmrg        pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height,
9905b261ecSmrg                                    pScreen->rootDepth,
10005b261ecSmrg                                    BitsPerPixel(pScreen->rootDepth),
10105b261ecSmrg                                    0, s->pixmap_data);
10205b261ecSmrg        /* ModifyPixmapHeader ignores zero arguments, so install rowbytes
10305b261ecSmrg           by hand. */
10405b261ecSmrg        pPix->devKind = 0;
10505b261ecSmrg    }
10605b261ecSmrg}
10705b261ecSmrg
10805b261ecSmrg/*
10905b261ecSmrg * RootlessCreateScreenResources
11005b261ecSmrg *  Rootless implementations typically set a null framebuffer pointer, which
11105b261ecSmrg *  causes problems with miCreateScreenResources. We fix things up here.
11205b261ecSmrg */
11305b261ecSmrgstatic Bool
11405b261ecSmrgRootlessCreateScreenResources(ScreenPtr pScreen)
11505b261ecSmrg{
11605b261ecSmrg    Bool ret = TRUE;
11705b261ecSmrg
11805b261ecSmrg    SCREEN_UNWRAP(pScreen, CreateScreenResources);
11905b261ecSmrg
12005b261ecSmrg    if (pScreen->CreateScreenResources != NULL)
12135c4bbdfSmrg        ret = (*pScreen->CreateScreenResources) (pScreen);
12205b261ecSmrg
12305b261ecSmrg    SCREEN_WRAP(pScreen, CreateScreenResources);
12405b261ecSmrg
12505b261ecSmrg    if (!ret)
12605b261ecSmrg        return ret;
12705b261ecSmrg
12805b261ecSmrg    /* Make sure we have a valid screen pixmap. */
12905b261ecSmrg
13005b261ecSmrg    RootlessUpdateScreenPixmap(pScreen);
13105b261ecSmrg
13205b261ecSmrg    return ret;
13305b261ecSmrg}
13405b261ecSmrg
13505b261ecSmrgstatic Bool
13635c4bbdfSmrgRootlessCloseScreen(ScreenPtr pScreen)
13705b261ecSmrg{
13805b261ecSmrg    RootlessScreenRec *s;
13905b261ecSmrg
14005b261ecSmrg    s = SCREENREC(pScreen);
14105b261ecSmrg
14205b261ecSmrg    // fixme unwrap everything that was wrapped?
14305b261ecSmrg    pScreen->CloseScreen = s->CloseScreen;
14405b261ecSmrg
14505b261ecSmrg    if (s->pixmap_data != NULL) {
1466747b715Smrg        free(s->pixmap_data);
14705b261ecSmrg        s->pixmap_data = NULL;
14805b261ecSmrg        s->pixmap_data_size = 0;
14905b261ecSmrg    }
15005b261ecSmrg
1516747b715Smrg    free(s);
15235c4bbdfSmrg    return pScreen->CloseScreen(pScreen);
15305b261ecSmrg}
15405b261ecSmrg
15505b261ecSmrgstatic void
15605b261ecSmrgRootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
15705b261ecSmrg                 unsigned int format, unsigned long planeMask, char *pdstLine)
15805b261ecSmrg{
15905b261ecSmrg    ScreenPtr pScreen = pDrawable->pScreen;
16035c4bbdfSmrg
16105b261ecSmrg    SCREEN_UNWRAP(pScreen, GetImage);
16205b261ecSmrg
16305b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
16405b261ecSmrg        int x0, y0, x1, y1;
16505b261ecSmrg        RootlessWindowRec *winRec;
16605b261ecSmrg
16705b261ecSmrg        // Many apps use GetImage to sync with the visible frame buffer
16805b261ecSmrg        // FIXME: entire screen or just window or all screens?
16905b261ecSmrg        RootlessRedisplayScreen(pScreen);
17005b261ecSmrg
17105b261ecSmrg        // RedisplayScreen stops drawing, so we need to start it again
17235c4bbdfSmrg        RootlessStartDrawing((WindowPtr) pDrawable);
17305b261ecSmrg
17405b261ecSmrg        /* Check that we have some place to read from. */
17505b261ecSmrg        winRec = WINREC(TopLevelParent((WindowPtr) pDrawable));
17605b261ecSmrg        if (winRec == NULL)
17705b261ecSmrg            goto out;
17805b261ecSmrg
17905b261ecSmrg        /* Clip to top-level window bounds. */
18005b261ecSmrg        /* FIXME: fbGetImage uses the width parameter to calculate the
18105b261ecSmrg           stride of the destination pixmap. If w is clipped, the data
18205b261ecSmrg           returned will be garbage, although we will not crash. */
18305b261ecSmrg
18405b261ecSmrg        x0 = pDrawable->x + sx;
18505b261ecSmrg        y0 = pDrawable->y + sy;
18605b261ecSmrg        x1 = x0 + w;
18705b261ecSmrg        y1 = y0 + h;
18805b261ecSmrg
18935c4bbdfSmrg        x0 = max(x0, winRec->x);
19035c4bbdfSmrg        y0 = max(y0, winRec->y);
19135c4bbdfSmrg        x1 = min(x1, winRec->x + winRec->width);
19235c4bbdfSmrg        y1 = min(y1, winRec->y + winRec->height);
19305b261ecSmrg
19405b261ecSmrg        sx = x0 - pDrawable->x;
19505b261ecSmrg        sy = y0 - pDrawable->y;
19605b261ecSmrg        w = x1 - x0;
19705b261ecSmrg        h = y1 - y0;
19805b261ecSmrg
19905b261ecSmrg        if (w <= 0 || h <= 0)
20005b261ecSmrg            goto out;
20105b261ecSmrg    }
20205b261ecSmrg
20305b261ecSmrg    pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
20405b261ecSmrg
20535c4bbdfSmrg out:
20605b261ecSmrg    SCREEN_WRAP(pScreen, GetImage);
20705b261ecSmrg}
20805b261ecSmrg
20905b261ecSmrg/*
21005b261ecSmrg * RootlessSourceValidate
21105b261ecSmrg *  CopyArea and CopyPlane use a GC tied to the destination drawable.
21205b261ecSmrg *  StartDrawing/StopDrawing wrappers won't be called if source is
21305b261ecSmrg *  a visible window but the destination isn't. So, we call StartDrawing
21405b261ecSmrg *  here and leave StopDrawing for the block handler.
21505b261ecSmrg */
21605b261ecSmrgstatic void
2179ace9065SmrgRootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h,
2189ace9065Smrg                       unsigned int subWindowMode)
21905b261ecSmrg{
22005b261ecSmrg    SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate);
22105b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
22235c4bbdfSmrg        WindowPtr pWin = (WindowPtr) pDrawable;
22335c4bbdfSmrg
22405b261ecSmrg        RootlessStartDrawing(pWin);
22505b261ecSmrg    }
226ed6184dfSmrg    pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h,
227ed6184dfSmrg                                       subWindowMode);
22805b261ecSmrg    SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
22905b261ecSmrg}
23005b261ecSmrg
23105b261ecSmrgstatic void
23205b261ecSmrgRootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
23335c4bbdfSmrg                  INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask,
23405b261ecSmrg                  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
23505b261ecSmrg{
23605b261ecSmrg    ScreenPtr pScreen = pDst->pDrawable->pScreen;
23705b261ecSmrg    PictureScreenPtr ps = GetPictureScreen(pScreen);
23805b261ecSmrg    WindowPtr srcWin, dstWin, maskWin = NULL;
23905b261ecSmrg
24035c4bbdfSmrg    if (pMask) {                // pMask can be NULL
24135c4bbdfSmrg        maskWin = (pMask->pDrawable &&
24235c4bbdfSmrg                   pMask->pDrawable->type ==
24335c4bbdfSmrg                   DRAWABLE_WINDOW) ? (WindowPtr) pMask->pDrawable : NULL;
24405b261ecSmrg    }
24535c4bbdfSmrg    srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
24635c4bbdfSmrg        (WindowPtr) pSrc->pDrawable : NULL;
24735c4bbdfSmrg    dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
24835c4bbdfSmrg        (WindowPtr) pDst->pDrawable : NULL;
24905b261ecSmrg
25005b261ecSmrg    // SCREEN_UNWRAP(ps, Composite);
25105b261ecSmrg    ps->Composite = SCREENREC(pScreen)->Composite;
25205b261ecSmrg
25335c4bbdfSmrg    if (srcWin && IsFramedWindow(srcWin))
25405b261ecSmrg        RootlessStartDrawing(srcWin);
25505b261ecSmrg    if (maskWin && IsFramedWindow(maskWin))
25605b261ecSmrg        RootlessStartDrawing(maskWin);
25735c4bbdfSmrg    if (dstWin && IsFramedWindow(dstWin))
25805b261ecSmrg        RootlessStartDrawing(dstWin);
25905b261ecSmrg
26005b261ecSmrg    ps->Composite(op, pSrc, pMask, pDst,
26135c4bbdfSmrg                  xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
26205b261ecSmrg
26335c4bbdfSmrg    if (dstWin && IsFramedWindow(dstWin)) {
26405b261ecSmrg        RootlessDamageRect(dstWin, xDst, yDst, width, height);
26505b261ecSmrg    }
26605b261ecSmrg
26705b261ecSmrg    ps->Composite = RootlessComposite;
26805b261ecSmrg    // SCREEN_WRAP(ps, Composite);
26905b261ecSmrg}
27005b261ecSmrg
27105b261ecSmrgstatic void
27205b261ecSmrgRootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
27305b261ecSmrg               PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
27435c4bbdfSmrg               int nlist, GlyphListPtr list, GlyphPtr * glyphs)
27505b261ecSmrg{
27605b261ecSmrg    ScreenPtr pScreen = pDst->pDrawable->pScreen;
27705b261ecSmrg    PictureScreenPtr ps = GetPictureScreen(pScreen);
27805b261ecSmrg    int x, y;
27905b261ecSmrg    int n;
28005b261ecSmrg    GlyphPtr glyph;
28105b261ecSmrg    WindowPtr srcWin, dstWin;
28205b261ecSmrg
2836747b715Smrg    srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
28435c4bbdfSmrg        (WindowPtr) pSrc->pDrawable : NULL;
28505b261ecSmrg    dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
28635c4bbdfSmrg        (WindowPtr) pDst->pDrawable : NULL;
28705b261ecSmrg
28835c4bbdfSmrg    if (srcWin && IsFramedWindow(srcWin))
28935c4bbdfSmrg        RootlessStartDrawing(srcWin);
29035c4bbdfSmrg    if (dstWin && IsFramedWindow(dstWin))
29135c4bbdfSmrg        RootlessStartDrawing(dstWin);
29205b261ecSmrg
29305b261ecSmrg    //SCREEN_UNWRAP(ps, Glyphs);
29405b261ecSmrg    ps->Glyphs = SCREENREC(pScreen)->Glyphs;
29505b261ecSmrg    ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
29605b261ecSmrg    ps->Glyphs = RootlessGlyphs;
29705b261ecSmrg    //SCREEN_WRAP(ps, Glyphs);
29805b261ecSmrg
29905b261ecSmrg    if (dstWin && IsFramedWindow(dstWin)) {
30005b261ecSmrg        x = xSrc;
30105b261ecSmrg        y = ySrc;
30205b261ecSmrg
30305b261ecSmrg        while (nlist--) {
30405b261ecSmrg            x += list->xOff;
30505b261ecSmrg            y += list->yOff;
30605b261ecSmrg            n = list->len;
30705b261ecSmrg
30805b261ecSmrg            /* Calling DamageRect for the bounding box of each glyph is
30905b261ecSmrg               inefficient. So compute the union of all glyphs in a list
31005b261ecSmrg               and damage that. */
31105b261ecSmrg
31205b261ecSmrg            if (n > 0) {
31305b261ecSmrg                BoxRec box;
31405b261ecSmrg
31505b261ecSmrg                glyph = *glyphs++;
31605b261ecSmrg
31705b261ecSmrg                box.x1 = x - glyph->info.x;
31805b261ecSmrg                box.y1 = y - glyph->info.y;
31905b261ecSmrg                box.x2 = box.x1 + glyph->info.width;
3209ace9065Smrg                box.y2 = box.y1 + glyph->info.height;
32105b261ecSmrg
32205b261ecSmrg                x += glyph->info.xOff;
32305b261ecSmrg                y += glyph->info.yOff;
32405b261ecSmrg
32505b261ecSmrg                while (--n > 0) {
32605b261ecSmrg                    short x1, y1, x2, y2;
32705b261ecSmrg
32805b261ecSmrg                    glyph = *glyphs++;
32905b261ecSmrg
33005b261ecSmrg                    x1 = x - glyph->info.x;
33105b261ecSmrg                    y1 = y - glyph->info.y;
33205b261ecSmrg                    x2 = x1 + glyph->info.width;
33305b261ecSmrg                    y2 = y1 + glyph->info.height;
33405b261ecSmrg
33535c4bbdfSmrg                    box.x1 = max(box.x1, x1);
33635c4bbdfSmrg                    box.y1 = max(box.y1, y1);
33735c4bbdfSmrg                    box.x2 = max(box.x2, x2);
33835c4bbdfSmrg                    box.y2 = max(box.y2, y2);
33905b261ecSmrg
34005b261ecSmrg                    x += glyph->info.xOff;
34105b261ecSmrg                    y += glyph->info.yOff;
34205b261ecSmrg                }
34305b261ecSmrg
34405b261ecSmrg                RootlessDamageBox(dstWin, &box);
34505b261ecSmrg            }
34605b261ecSmrg            list++;
34705b261ecSmrg        }
34805b261ecSmrg    }
34905b261ecSmrg}
35005b261ecSmrg
35105b261ecSmrg/*
35205b261ecSmrg * RootlessValidateTree
35305b261ecSmrg *  ValidateTree is modified in two ways:
35405b261ecSmrg *   - top-level windows don't clip each other
35505b261ecSmrg *   - windows aren't clipped against root.
35605b261ecSmrg *  These only matter when validating from the root.
35705b261ecSmrg */
35805b261ecSmrgstatic int
35905b261ecSmrgRootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
36005b261ecSmrg{
36105b261ecSmrg    int result;
36205b261ecSmrg    RegionRec saveRoot;
36305b261ecSmrg    ScreenPtr pScreen = pParent->drawable.pScreen;
36405b261ecSmrg
36505b261ecSmrg    SCREEN_UNWRAP(pScreen, ValidateTree);
36605b261ecSmrg    RL_DEBUG_MSG("VALIDATETREE start ");
36705b261ecSmrg
36805b261ecSmrg    // Use our custom version to validate from root
36905b261ecSmrg    if (IsRoot(pParent)) {
37005b261ecSmrg        RL_DEBUG_MSG("custom ");
37105b261ecSmrg        result = RootlessMiValidateTree(pParent, pChild, kind);
37235c4bbdfSmrg    }
37335c4bbdfSmrg    else {
37405b261ecSmrg        HUGE_ROOT(pParent);
37505b261ecSmrg        result = pScreen->ValidateTree(pParent, pChild, kind);
37605b261ecSmrg        NORMAL_ROOT(pParent);
37705b261ecSmrg    }
37805b261ecSmrg
37905b261ecSmrg    SCREEN_WRAP(pScreen, ValidateTree);
38005b261ecSmrg    RL_DEBUG_MSG("VALIDATETREE end\n");
38105b261ecSmrg
38205b261ecSmrg    return result;
38305b261ecSmrg}
38405b261ecSmrg
38505b261ecSmrg/*
38605b261ecSmrg * RootlessMarkOverlappedWindows
38705b261ecSmrg *  MarkOverlappedWindows is modified to ignore overlapping
38805b261ecSmrg *  top-level windows.
38905b261ecSmrg */
39005b261ecSmrgstatic Bool
39105b261ecSmrgRootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
39205b261ecSmrg                              WindowPtr *ppLayerWin)
39305b261ecSmrg{
39405b261ecSmrg    RegionRec saveRoot;
39505b261ecSmrg    Bool result;
39605b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
39735c4bbdfSmrg
39805b261ecSmrg    SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
39905b261ecSmrg    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
40005b261ecSmrg
40105b261ecSmrg    HUGE_ROOT(pWin);
40205b261ecSmrg    if (IsRoot(pWin)) {
40305b261ecSmrg        // root - mark nothing
40405b261ecSmrg        RL_DEBUG_MSG("is root not marking ");
40505b261ecSmrg        result = FALSE;
40605b261ecSmrg    }
40735c4bbdfSmrg    else if (!IsTopLevel(pWin)) {
40805b261ecSmrg        // not top-level window - mark normally
40905b261ecSmrg        result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
41005b261ecSmrg    }
41105b261ecSmrg    else {
41205b261ecSmrg        //top-level window - mark children ONLY - NO overlaps with sibs (?)
41305b261ecSmrg        // This code copied from miMarkOverlappedWindows()
41405b261ecSmrg
41505b261ecSmrg        register WindowPtr pChild;
41605b261ecSmrg        Bool anyMarked = FALSE;
4176747b715Smrg        MarkWindowProcPtr MarkWindow = pScreen->MarkWindow;
41805b261ecSmrg
41905b261ecSmrg        RL_DEBUG_MSG("is top level! ");
42005b261ecSmrg        /* single layered systems are easy */
42135c4bbdfSmrg        if (ppLayerWin)
42235c4bbdfSmrg            *ppLayerWin = pWin;
42305b261ecSmrg
42405b261ecSmrg        if (pWin == pFirst) {
42505b261ecSmrg            /* Blindly mark pWin and all of its inferiors.   This is a slight
42605b261ecSmrg             * overkill if there are mapped windows that outside pWin's border,
42705b261ecSmrg             * but it's better than wasting time on RectIn checks.
42805b261ecSmrg             */
42905b261ecSmrg            pChild = pWin;
43005b261ecSmrg            while (1) {
43105b261ecSmrg                if (pChild->viewable) {
4326747b715Smrg                    if (RegionBroken(&pChild->winSize))
43335c4bbdfSmrg                        SetWinSize(pChild);
4346747b715Smrg                    if (RegionBroken(&pChild->borderSize))
43535c4bbdfSmrg                        SetBorderSize(pChild);
43635c4bbdfSmrg                    (*MarkWindow) (pChild);
43705b261ecSmrg                    if (pChild->firstChild) {
43805b261ecSmrg                        pChild = pChild->firstChild;
43905b261ecSmrg                        continue;
44005b261ecSmrg                    }
44105b261ecSmrg                }
44205b261ecSmrg                while (!pChild->nextSib && (pChild != pWin))
44305b261ecSmrg                    pChild = pChild->parent;
44405b261ecSmrg                if (pChild == pWin)
44505b261ecSmrg                    break;
44605b261ecSmrg                pChild = pChild->nextSib;
44705b261ecSmrg            }
44805b261ecSmrg            anyMarked = TRUE;
44905b261ecSmrg        }
45005b261ecSmrg        if (anyMarked)
45135c4bbdfSmrg            (*MarkWindow) (pWin->parent);
45205b261ecSmrg        result = anyMarked;
45305b261ecSmrg    }
45405b261ecSmrg    NORMAL_ROOT(pWin);
45505b261ecSmrg    SCREEN_WRAP(pScreen, MarkOverlappedWindows);
45605b261ecSmrg    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
45705b261ecSmrg
45805b261ecSmrg    return result;
45905b261ecSmrg}
46005b261ecSmrg
46135c4bbdfSmrgstatic void
46235c4bbdfSmrgexpose_1(WindowPtr pWin)
46335c4bbdfSmrg{
4644642e01fSmrg    WindowPtr pChild;
46535c4bbdfSmrg
4664642e01fSmrg    if (!pWin->realized)
4674642e01fSmrg        return;
46835c4bbdfSmrg
46935c4bbdfSmrg    pWin->drawable.pScreen->PaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND);
47035c4bbdfSmrg
4714642e01fSmrg    /* FIXME: comments in windowstr.h indicate that borderClip doesn't
47235c4bbdfSmrg       include subwindow visibility. But I'm not so sure.. so we may
47335c4bbdfSmrg       be exposing too much.. */
47435c4bbdfSmrg
47535c4bbdfSmrg    miSendExposures(pWin, &pWin->borderClip,
47635c4bbdfSmrg                    pWin->drawable.x, pWin->drawable.y);
47735c4bbdfSmrg
4784642e01fSmrg    for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib)
47935c4bbdfSmrg        expose_1(pChild);
4804642e01fSmrg}
4814642e01fSmrg
4824642e01fSmrgvoid
48335c4bbdfSmrgRootlessScreenExpose(ScreenPtr pScreen)
4844642e01fSmrg{
48535c4bbdfSmrg    expose_1(pScreen->root);
4864642e01fSmrg}
4874642e01fSmrg
4884642e01fSmrgColormapPtr
48935c4bbdfSmrgRootlessGetColormap(ScreenPtr pScreen)
4904642e01fSmrg{
49135c4bbdfSmrg    RootlessScreenRec *s = SCREENREC(pScreen);
4924642e01fSmrg
49335c4bbdfSmrg    return s->colormap;
4944642e01fSmrg}
4954642e01fSmrg
4964642e01fSmrgstatic void
49735c4bbdfSmrgRootlessInstallColormap(ColormapPtr pMap)
4984642e01fSmrg{
49935c4bbdfSmrg    ScreenPtr pScreen = pMap->pScreen;
50035c4bbdfSmrg    RootlessScreenRec *s = SCREENREC(pScreen);
5014642e01fSmrg
50235c4bbdfSmrg    SCREEN_UNWRAP(pScreen, InstallColormap);
5034642e01fSmrg
50435c4bbdfSmrg    if (s->colormap != pMap) {
50535c4bbdfSmrg        s->colormap = pMap;
50635c4bbdfSmrg        s->colormap_changed = TRUE;
50735c4bbdfSmrg        RootlessQueueRedisplay(pScreen);
50835c4bbdfSmrg    }
5094642e01fSmrg
51035c4bbdfSmrg    pScreen->InstallColormap(pMap);
5114642e01fSmrg
51235c4bbdfSmrg    SCREEN_WRAP(pScreen, InstallColormap);
5134642e01fSmrg}
5144642e01fSmrg
5154642e01fSmrgstatic void
51635c4bbdfSmrgRootlessUninstallColormap(ColormapPtr pMap)
5174642e01fSmrg{
51835c4bbdfSmrg    ScreenPtr pScreen = pMap->pScreen;
51935c4bbdfSmrg    RootlessScreenRec *s = SCREENREC(pScreen);
5204642e01fSmrg
52135c4bbdfSmrg    SCREEN_UNWRAP(pScreen, UninstallColormap);
5224642e01fSmrg
52335c4bbdfSmrg    if (s->colormap == pMap)
52435c4bbdfSmrg        s->colormap = NULL;
5254642e01fSmrg
52635c4bbdfSmrg    pScreen->UninstallColormap(pMap);
5274642e01fSmrg
52835c4bbdfSmrg    SCREEN_WRAP(pScreen, UninstallColormap);
5294642e01fSmrg}
5304642e01fSmrg
5314642e01fSmrgstatic void
53235c4bbdfSmrgRootlessStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef)
5334642e01fSmrg{
53435c4bbdfSmrg    ScreenPtr pScreen = pMap->pScreen;
53535c4bbdfSmrg    RootlessScreenRec *s = SCREENREC(pScreen);
5364642e01fSmrg
53735c4bbdfSmrg    SCREEN_UNWRAP(pScreen, StoreColors);
5384642e01fSmrg
53935c4bbdfSmrg    if (s->colormap == pMap && ndef > 0) {
54035c4bbdfSmrg        s->colormap_changed = TRUE;
54135c4bbdfSmrg        RootlessQueueRedisplay(pScreen);
54235c4bbdfSmrg    }
5434642e01fSmrg
54435c4bbdfSmrg    pScreen->StoreColors(pMap, ndef, pdef);
5454642e01fSmrg
54635c4bbdfSmrg    SCREEN_WRAP(pScreen, StoreColors);
5474642e01fSmrg}
5484642e01fSmrg
54905b261ecSmrgstatic CARD32
55005b261ecSmrgRootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg)
55105b261ecSmrg{
55205b261ecSmrg    RootlessScreenRec *screenRec = arg;
55305b261ecSmrg
55405b261ecSmrg    if (!screenRec->redisplay_queued) {
55505b261ecSmrg        /* No update needed. Stop the timer. */
55605b261ecSmrg
55705b261ecSmrg        screenRec->redisplay_timer_set = FALSE;
55805b261ecSmrg        return 0;
55905b261ecSmrg    }
56005b261ecSmrg
56105b261ecSmrg    screenRec->redisplay_queued = FALSE;
56205b261ecSmrg
56305b261ecSmrg    /* Mark that we should redisplay before waiting for I/O next time */
56405b261ecSmrg    screenRec->redisplay_expired = TRUE;
56505b261ecSmrg
56605b261ecSmrg    /* Reinstall the timer immediately, so we get as close to our
56705b261ecSmrg       redisplay interval as possible. */
56805b261ecSmrg
56905b261ecSmrg    return ROOTLESS_REDISPLAY_DELAY;
57005b261ecSmrg}
57105b261ecSmrg
57205b261ecSmrg/*
57305b261ecSmrg * RootlessQueueRedisplay
57405b261ecSmrg *  Queue a redisplay after a timer delay to ensure we do not redisplay
57505b261ecSmrg *  too frequently.
57605b261ecSmrg */
57705b261ecSmrgvoid
57805b261ecSmrgRootlessQueueRedisplay(ScreenPtr pScreen)
57905b261ecSmrg{
58005b261ecSmrg    RootlessScreenRec *screenRec = SCREENREC(pScreen);
58105b261ecSmrg
58205b261ecSmrg    screenRec->redisplay_queued = TRUE;
58305b261ecSmrg
58405b261ecSmrg    if (screenRec->redisplay_timer_set)
58505b261ecSmrg        return;
58605b261ecSmrg
58705b261ecSmrg    screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer,
58805b261ecSmrg                                          0, ROOTLESS_REDISPLAY_DELAY,
58935c4bbdfSmrg                                          RootlessRedisplayCallback, screenRec);
59005b261ecSmrg    screenRec->redisplay_timer_set = TRUE;
59105b261ecSmrg}
59205b261ecSmrg
59305b261ecSmrg/*
59405b261ecSmrg * RootlessBlockHandler
59505b261ecSmrg *  If the redisplay timer has expired, flush drawing before blocking
59605b261ecSmrg *  on select().
59705b261ecSmrg */
59805b261ecSmrgstatic void
5991b5d61b8SmrgRootlessBlockHandler(void *pbdata, void *ptimeout)
60005b261ecSmrg{
60105b261ecSmrg    ScreenPtr pScreen = pbdata;
60205b261ecSmrg    RootlessScreenRec *screenRec = SCREENREC(pScreen);
60305b261ecSmrg
60405b261ecSmrg    if (screenRec->redisplay_expired) {
60505b261ecSmrg        screenRec->redisplay_expired = FALSE;
60605b261ecSmrg
60705b261ecSmrg        RootlessRedisplayScreen(pScreen);
60805b261ecSmrg    }
60905b261ecSmrg}
61005b261ecSmrg
61105b261ecSmrgstatic void
6121b5d61b8SmrgRootlessWakeupHandler(void *data, int result)
61305b261ecSmrg{
61405b261ecSmrg    // nothing here
61505b261ecSmrg}
61605b261ecSmrg
61705b261ecSmrgstatic Bool
61805b261ecSmrgRootlessAllocatePrivates(ScreenPtr pScreen)
61905b261ecSmrg{
62005b261ecSmrg    RootlessScreenRec *s;
62105b261ecSmrg
62235c4bbdfSmrg    if (!dixRegisterPrivateKey
62335c4bbdfSmrg        (&rootlessGCPrivateKeyRec, PRIVATE_GC, sizeof(RootlessGCRec)))
6246747b715Smrg        return FALSE;
6256747b715Smrg    if (!dixRegisterPrivateKey(&rootlessScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
6266747b715Smrg        return FALSE;
6276747b715Smrg    if (!dixRegisterPrivateKey(&rootlessWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
6286747b715Smrg        return FALSE;
62935c4bbdfSmrg    if (!dixRegisterPrivateKey
63035c4bbdfSmrg        (&rootlessWindowOldPixmapPrivateKeyRec, PRIVATE_WINDOW, 0))
63105b261ecSmrg        return FALSE;
63205b261ecSmrg
6336747b715Smrg    s = malloc(sizeof(RootlessScreenRec));
63435c4bbdfSmrg    if (!s)
63535c4bbdfSmrg        return FALSE;
6364642e01fSmrg    SETSCREENREC(pScreen, s);
63705b261ecSmrg
63805b261ecSmrg    s->pixmap_data = NULL;
63905b261ecSmrg    s->pixmap_data_size = 0;
64005b261ecSmrg
64105b261ecSmrg    s->redisplay_timer = NULL;
64205b261ecSmrg    s->redisplay_timer_set = FALSE;
64305b261ecSmrg
64405b261ecSmrg    return TRUE;
64505b261ecSmrg}
64605b261ecSmrg
64705b261ecSmrgstatic void
64805b261ecSmrgRootlessWrap(ScreenPtr pScreen)
64905b261ecSmrg{
6504642e01fSmrg    RootlessScreenRec *s = SCREENREC(pScreen);
65105b261ecSmrg
65205b261ecSmrg#define WRAP(a) \
65305b261ecSmrg    if (pScreen->a) { \
65405b261ecSmrg        s->a = pScreen->a; \
65505b261ecSmrg    } else { \
65605b261ecSmrg        RL_DEBUG_MSG("null screen fn " #a "\n"); \
65705b261ecSmrg        s->a = NULL; \
65805b261ecSmrg    } \
65905b261ecSmrg    pScreen->a = Rootless##a
66005b261ecSmrg
66105b261ecSmrg    WRAP(CreateScreenResources);
66205b261ecSmrg    WRAP(CloseScreen);
66305b261ecSmrg    WRAP(CreateGC);
66405b261ecSmrg    WRAP(CopyWindow);
66535c4bbdfSmrg    WRAP(PaintWindow);
66605b261ecSmrg    WRAP(GetImage);
66705b261ecSmrg    WRAP(SourceValidate);
66805b261ecSmrg    WRAP(CreateWindow);
66905b261ecSmrg    WRAP(DestroyWindow);
67005b261ecSmrg    WRAP(RealizeWindow);
67105b261ecSmrg    WRAP(UnrealizeWindow);
67205b261ecSmrg    WRAP(MoveWindow);
67305b261ecSmrg    WRAP(PositionWindow);
67405b261ecSmrg    WRAP(ResizeWindow);
67505b261ecSmrg    WRAP(RestackWindow);
67605b261ecSmrg    WRAP(ReparentWindow);
67705b261ecSmrg    WRAP(ChangeBorderWidth);
67805b261ecSmrg    WRAP(MarkOverlappedWindows);
67905b261ecSmrg    WRAP(ValidateTree);
68005b261ecSmrg    WRAP(ChangeWindowAttributes);
6814642e01fSmrg    WRAP(InstallColormap);
6824642e01fSmrg    WRAP(UninstallColormap);
6834642e01fSmrg    WRAP(StoreColors);
68405b261ecSmrg
68505b261ecSmrg    WRAP(SetShape);
68605b261ecSmrg
68705b261ecSmrg    {
68805b261ecSmrg        // Composite and Glyphs don't use normal screen wrapping
68905b261ecSmrg        PictureScreenPtr ps = GetPictureScreen(pScreen);
69035c4bbdfSmrg
69105b261ecSmrg        s->Composite = ps->Composite;
69205b261ecSmrg        ps->Composite = RootlessComposite;
69305b261ecSmrg        s->Glyphs = ps->Glyphs;
69405b261ecSmrg        ps->Glyphs = RootlessGlyphs;
69505b261ecSmrg    }
69605b261ecSmrg
69705b261ecSmrg    // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
69805b261ecSmrg
69905b261ecSmrg#undef WRAP
70005b261ecSmrg}
70105b261ecSmrg
70205b261ecSmrg/*
70305b261ecSmrg * RootlessInit
70405b261ecSmrg *  Called by the rootless implementation to initialize the rootless layer.
70505b261ecSmrg *  Rootless wraps lots of stuff and needs a bunch of devPrivates.
70605b261ecSmrg */
70735c4bbdfSmrgBool
70835c4bbdfSmrgRootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
70905b261ecSmrg{
71005b261ecSmrg    RootlessScreenRec *s;
71105b261ecSmrg
71205b261ecSmrg    if (!RootlessAllocatePrivates(pScreen))
71305b261ecSmrg        return FALSE;
71405b261ecSmrg
7154642e01fSmrg    s = SCREENREC(pScreen);
71605b261ecSmrg
71705b261ecSmrg    s->imp = procs;
7184642e01fSmrg    s->colormap = NULL;
7194642e01fSmrg    s->redisplay_expired = FALSE;
72005b261ecSmrg
72105b261ecSmrg    RootlessWrap(pScreen);
72205b261ecSmrg
72305b261ecSmrg    if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler,
72405b261ecSmrg                                        RootlessWakeupHandler,
72535c4bbdfSmrg                                        (void *) pScreen)) {
72605b261ecSmrg        return FALSE;
72705b261ecSmrg    }
72805b261ecSmrg
72905b261ecSmrg    return TRUE;
73005b261ecSmrg}
7314642e01fSmrg
73235c4bbdfSmrgvoid
73335c4bbdfSmrgRootlessUpdateRooted(Bool state)
73435c4bbdfSmrg{
7354642e01fSmrg    int i;
73635c4bbdfSmrg
73735c4bbdfSmrg    if (!state) {
7384642e01fSmrg        for (i = 0; i < screenInfo.numScreens; i++)
73935c4bbdfSmrg            RootlessDisableRoot(screenInfo.screens[i]);
7404642e01fSmrg    }
74135c4bbdfSmrg    else {
7424642e01fSmrg        for (i = 0; i < screenInfo.numScreens; i++)
74335c4bbdfSmrg            RootlessEnableRoot(screenInfo.screens[i]);
7444642e01fSmrg    }
7454642e01fSmrg}
746