rootlessScreen.c revision 05b261ec
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
3305b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3405b261ecSmrg#include <dix-config.h>
3505b261ecSmrg#endif
3605b261ecSmrg
3705b261ecSmrg#include "mi.h"
3805b261ecSmrg#include "scrnintstr.h"
3905b261ecSmrg#include "gcstruct.h"
4005b261ecSmrg#include "pixmapstr.h"
4105b261ecSmrg#include "windowstr.h"
4205b261ecSmrg#include "propertyst.h"
4305b261ecSmrg#include "mivalidate.h"
4405b261ecSmrg#include "picturestr.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
5405b261ecSmrg/* In milliseconds */
5505b261ecSmrg#ifndef ROOTLESS_REDISPLAY_DELAY
5605b261ecSmrg#define ROOTLESS_REDISPLAY_DELAY 10
5705b261ecSmrg#endif
5805b261ecSmrg
5905b261ecSmrgextern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild,
6005b261ecSmrg                                  VTKind kind);
6105b261ecSmrgextern Bool RootlessCreateGC(GCPtr pGC);
6205b261ecSmrg
6305b261ecSmrg// Initialize globals
6405b261ecSmrgint rootlessGCPrivateIndex = -1;
6505b261ecSmrgint rootlessScreenPrivateIndex = -1;
6605b261ecSmrgint rootlessWindowPrivateIndex = -1;
6705b261ecSmrg
6805b261ecSmrg
6905b261ecSmrg/*
7005b261ecSmrg * RootlessUpdateScreenPixmap
7105b261ecSmrg *  miCreateScreenResources does not like a null framebuffer pointer,
7205b261ecSmrg *  it leaves the screen pixmap with an uninitialized data pointer.
7305b261ecSmrg *  Thus, rootless implementations typically set the framebuffer width
7405b261ecSmrg *  to zero so that miCreateScreenResources does not allocate a screen
7505b261ecSmrg *  pixmap for us. We allocate our own screen pixmap here since we need
7605b261ecSmrg *  the screen pixmap to be valid (e.g. CopyArea from the root window).
7705b261ecSmrg */
7805b261ecSmrgvoid
7905b261ecSmrgRootlessUpdateScreenPixmap(ScreenPtr pScreen)
8005b261ecSmrg{
8105b261ecSmrg    RootlessScreenRec *s = SCREENREC(pScreen);
8205b261ecSmrg    PixmapPtr pPix;
8305b261ecSmrg    unsigned int rowbytes;
8405b261ecSmrg
8505b261ecSmrg    pPix = (*pScreen->GetScreenPixmap)(pScreen);
8605b261ecSmrg    if (pPix == NULL) {
8705b261ecSmrg        pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth);
8805b261ecSmrg        (*pScreen->SetScreenPixmap)(pPix);
8905b261ecSmrg    }
9005b261ecSmrg
9105b261ecSmrg    rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth);
9205b261ecSmrg
9305b261ecSmrg    if (s->pixmap_data_size < rowbytes) {
9405b261ecSmrg        if (s->pixmap_data != NULL)
9505b261ecSmrg            xfree(s->pixmap_data);
9605b261ecSmrg
9705b261ecSmrg        s->pixmap_data_size = rowbytes;
9805b261ecSmrg        s->pixmap_data = xalloc(s->pixmap_data_size);
9905b261ecSmrg        if (s->pixmap_data == NULL)
10005b261ecSmrg            return;
10105b261ecSmrg
10205b261ecSmrg        memset(s->pixmap_data, 0xFF, s->pixmap_data_size);
10305b261ecSmrg
10405b261ecSmrg        pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height,
10505b261ecSmrg                                    pScreen->rootDepth,
10605b261ecSmrg                                    BitsPerPixel(pScreen->rootDepth),
10705b261ecSmrg                                    0, s->pixmap_data);
10805b261ecSmrg        /* ModifyPixmapHeader ignores zero arguments, so install rowbytes
10905b261ecSmrg           by hand. */
11005b261ecSmrg        pPix->devKind = 0;
11105b261ecSmrg    }
11205b261ecSmrg}
11305b261ecSmrg
11405b261ecSmrg
11505b261ecSmrg/*
11605b261ecSmrg * RootlessCreateScreenResources
11705b261ecSmrg *  Rootless implementations typically set a null framebuffer pointer, which
11805b261ecSmrg *  causes problems with miCreateScreenResources. We fix things up here.
11905b261ecSmrg */
12005b261ecSmrgstatic Bool
12105b261ecSmrgRootlessCreateScreenResources(ScreenPtr pScreen)
12205b261ecSmrg{
12305b261ecSmrg    Bool ret = TRUE;
12405b261ecSmrg
12505b261ecSmrg    SCREEN_UNWRAP(pScreen, CreateScreenResources);
12605b261ecSmrg
12705b261ecSmrg    if (pScreen->CreateScreenResources != NULL)
12805b261ecSmrg        ret = (*pScreen->CreateScreenResources)(pScreen);
12905b261ecSmrg
13005b261ecSmrg    SCREEN_WRAP(pScreen, CreateScreenResources);
13105b261ecSmrg
13205b261ecSmrg    if (!ret)
13305b261ecSmrg        return ret;
13405b261ecSmrg
13505b261ecSmrg    /* Make sure we have a valid screen pixmap. */
13605b261ecSmrg
13705b261ecSmrg    RootlessUpdateScreenPixmap(pScreen);
13805b261ecSmrg
13905b261ecSmrg    return ret;
14005b261ecSmrg}
14105b261ecSmrg
14205b261ecSmrg
14305b261ecSmrgstatic Bool
14405b261ecSmrgRootlessCloseScreen(int i, ScreenPtr pScreen)
14505b261ecSmrg{
14605b261ecSmrg    RootlessScreenRec *s;
14705b261ecSmrg
14805b261ecSmrg    s = SCREENREC(pScreen);
14905b261ecSmrg
15005b261ecSmrg    // fixme unwrap everything that was wrapped?
15105b261ecSmrg    pScreen->CloseScreen = s->CloseScreen;
15205b261ecSmrg
15305b261ecSmrg    if (s->pixmap_data != NULL) {
15405b261ecSmrg        xfree (s->pixmap_data);
15505b261ecSmrg        s->pixmap_data = NULL;
15605b261ecSmrg        s->pixmap_data_size = 0;
15705b261ecSmrg    }
15805b261ecSmrg
15905b261ecSmrg    xfree(s);
16005b261ecSmrg    return pScreen->CloseScreen(i, pScreen);
16105b261ecSmrg}
16205b261ecSmrg
16305b261ecSmrg
16405b261ecSmrgstatic void
16505b261ecSmrgRootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
16605b261ecSmrg                 unsigned int format, unsigned long planeMask, char *pdstLine)
16705b261ecSmrg{
16805b261ecSmrg    ScreenPtr pScreen = pDrawable->pScreen;
16905b261ecSmrg    SCREEN_UNWRAP(pScreen, GetImage);
17005b261ecSmrg
17105b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
17205b261ecSmrg        int x0, y0, x1, y1;
17305b261ecSmrg        RootlessWindowRec *winRec;
17405b261ecSmrg
17505b261ecSmrg        // Many apps use GetImage to sync with the visible frame buffer
17605b261ecSmrg        // FIXME: entire screen or just window or all screens?
17705b261ecSmrg        RootlessRedisplayScreen(pScreen);
17805b261ecSmrg
17905b261ecSmrg        // RedisplayScreen stops drawing, so we need to start it again
18005b261ecSmrg        RootlessStartDrawing((WindowPtr)pDrawable);
18105b261ecSmrg
18205b261ecSmrg        /* Check that we have some place to read from. */
18305b261ecSmrg        winRec = WINREC(TopLevelParent((WindowPtr) pDrawable));
18405b261ecSmrg        if (winRec == NULL)
18505b261ecSmrg            goto out;
18605b261ecSmrg
18705b261ecSmrg        /* Clip to top-level window bounds. */
18805b261ecSmrg        /* FIXME: fbGetImage uses the width parameter to calculate the
18905b261ecSmrg           stride of the destination pixmap. If w is clipped, the data
19005b261ecSmrg           returned will be garbage, although we will not crash. */
19105b261ecSmrg
19205b261ecSmrg        x0 = pDrawable->x + sx;
19305b261ecSmrg        y0 = pDrawable->y + sy;
19405b261ecSmrg        x1 = x0 + w;
19505b261ecSmrg        y1 = y0 + h;
19605b261ecSmrg
19705b261ecSmrg        x0 = MAX (x0, winRec->x);
19805b261ecSmrg        y0 = MAX (y0, winRec->y);
19905b261ecSmrg        x1 = MIN (x1, winRec->x + winRec->width);
20005b261ecSmrg        y1 = MIN (y1, winRec->y + winRec->height);
20105b261ecSmrg
20205b261ecSmrg        sx = x0 - pDrawable->x;
20305b261ecSmrg        sy = y0 - pDrawable->y;
20405b261ecSmrg        w = x1 - x0;
20505b261ecSmrg        h = y1 - y0;
20605b261ecSmrg
20705b261ecSmrg        if (w <= 0 || h <= 0)
20805b261ecSmrg            goto out;
20905b261ecSmrg    }
21005b261ecSmrg
21105b261ecSmrg    pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
21205b261ecSmrg
21305b261ecSmrgout:
21405b261ecSmrg    SCREEN_WRAP(pScreen, GetImage);
21505b261ecSmrg}
21605b261ecSmrg
21705b261ecSmrg
21805b261ecSmrg/*
21905b261ecSmrg * RootlessSourceValidate
22005b261ecSmrg *  CopyArea and CopyPlane use a GC tied to the destination drawable.
22105b261ecSmrg *  StartDrawing/StopDrawing wrappers won't be called if source is
22205b261ecSmrg *  a visible window but the destination isn't. So, we call StartDrawing
22305b261ecSmrg *  here and leave StopDrawing for the block handler.
22405b261ecSmrg */
22505b261ecSmrgstatic void
22605b261ecSmrgRootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h)
22705b261ecSmrg{
22805b261ecSmrg    SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate);
22905b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
23005b261ecSmrg        WindowPtr pWin = (WindowPtr)pDrawable;
23105b261ecSmrg        RootlessStartDrawing(pWin);
23205b261ecSmrg    }
23305b261ecSmrg    if (pDrawable->pScreen->SourceValidate) {
23405b261ecSmrg        pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h);
23505b261ecSmrg    }
23605b261ecSmrg    SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
23705b261ecSmrg}
23805b261ecSmrg
23905b261ecSmrg#ifdef RENDER
24005b261ecSmrg
24105b261ecSmrgstatic void
24205b261ecSmrgRootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
24305b261ecSmrg                  INT16 xSrc, INT16 ySrc, INT16  xMask, INT16  yMask,
24405b261ecSmrg                  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
24505b261ecSmrg{
24605b261ecSmrg    ScreenPtr pScreen = pDst->pDrawable->pScreen;
24705b261ecSmrg    PictureScreenPtr ps = GetPictureScreen(pScreen);
24805b261ecSmrg    WindowPtr srcWin, dstWin, maskWin = NULL;
24905b261ecSmrg
25005b261ecSmrg    if (pMask) {                        // pMask can be NULL
25105b261ecSmrg        maskWin = (pMask->pDrawable->type == DRAWABLE_WINDOW) ?
25205b261ecSmrg                  (WindowPtr)pMask->pDrawable :  NULL;
25305b261ecSmrg    }
25405b261ecSmrg    srcWin  = (pSrc->pDrawable->type  == DRAWABLE_WINDOW) ?
25505b261ecSmrg              (WindowPtr)pSrc->pDrawable  :  NULL;
25605b261ecSmrg    dstWin  = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
25705b261ecSmrg              (WindowPtr)pDst->pDrawable  :  NULL;
25805b261ecSmrg
25905b261ecSmrg    // SCREEN_UNWRAP(ps, Composite);
26005b261ecSmrg    ps->Composite = SCREENREC(pScreen)->Composite;
26105b261ecSmrg
26205b261ecSmrg    if (srcWin  && IsFramedWindow(srcWin))
26305b261ecSmrg        RootlessStartDrawing(srcWin);
26405b261ecSmrg    if (maskWin && IsFramedWindow(maskWin))
26505b261ecSmrg        RootlessStartDrawing(maskWin);
26605b261ecSmrg    if (dstWin  && IsFramedWindow(dstWin))
26705b261ecSmrg        RootlessStartDrawing(dstWin);
26805b261ecSmrg
26905b261ecSmrg    ps->Composite(op, pSrc, pMask, pDst,
27005b261ecSmrg                  xSrc, ySrc, xMask, yMask,
27105b261ecSmrg                  xDst, yDst, width, height);
27205b261ecSmrg
27305b261ecSmrg    if (dstWin  && IsFramedWindow(dstWin)) {
27405b261ecSmrg        RootlessDamageRect(dstWin, xDst, yDst, width, height);
27505b261ecSmrg    }
27605b261ecSmrg
27705b261ecSmrg    ps->Composite = RootlessComposite;
27805b261ecSmrg    // SCREEN_WRAP(ps, Composite);
27905b261ecSmrg}
28005b261ecSmrg
28105b261ecSmrg
28205b261ecSmrgstatic void
28305b261ecSmrgRootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
28405b261ecSmrg               PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
28505b261ecSmrg               int nlist, GlyphListPtr list, GlyphPtr *glyphs)
28605b261ecSmrg{
28705b261ecSmrg    ScreenPtr pScreen = pDst->pDrawable->pScreen;
28805b261ecSmrg    PictureScreenPtr ps = GetPictureScreen(pScreen);
28905b261ecSmrg    int x, y;
29005b261ecSmrg    int n;
29105b261ecSmrg    GlyphPtr glyph;
29205b261ecSmrg    WindowPtr srcWin, dstWin;
29305b261ecSmrg
29405b261ecSmrg    srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
29505b261ecSmrg             (WindowPtr)pSrc->pDrawable  :  NULL;
29605b261ecSmrg    dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
29705b261ecSmrg             (WindowPtr)pDst->pDrawable  :  NULL;
29805b261ecSmrg
29905b261ecSmrg    if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin);
30005b261ecSmrg    if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin);
30105b261ecSmrg
30205b261ecSmrg    //SCREEN_UNWRAP(ps, Glyphs);
30305b261ecSmrg    ps->Glyphs = SCREENREC(pScreen)->Glyphs;
30405b261ecSmrg    ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
30505b261ecSmrg    ps->Glyphs = RootlessGlyphs;
30605b261ecSmrg    //SCREEN_WRAP(ps, Glyphs);
30705b261ecSmrg
30805b261ecSmrg    if (dstWin && IsFramedWindow(dstWin)) {
30905b261ecSmrg        x = xSrc;
31005b261ecSmrg        y = ySrc;
31105b261ecSmrg
31205b261ecSmrg        while (nlist--) {
31305b261ecSmrg            x += list->xOff;
31405b261ecSmrg            y += list->yOff;
31505b261ecSmrg            n = list->len;
31605b261ecSmrg
31705b261ecSmrg            /* Calling DamageRect for the bounding box of each glyph is
31805b261ecSmrg               inefficient. So compute the union of all glyphs in a list
31905b261ecSmrg               and damage that. */
32005b261ecSmrg
32105b261ecSmrg            if (n > 0) {
32205b261ecSmrg                BoxRec box;
32305b261ecSmrg
32405b261ecSmrg                glyph = *glyphs++;
32505b261ecSmrg
32605b261ecSmrg                box.x1 = x - glyph->info.x;
32705b261ecSmrg                box.y1 = y - glyph->info.y;
32805b261ecSmrg                box.x2 = box.x1 + glyph->info.width;
32905b261ecSmrg                box.y2 = box.y2 + glyph->info.height;
33005b261ecSmrg
33105b261ecSmrg                x += glyph->info.xOff;
33205b261ecSmrg                y += glyph->info.yOff;
33305b261ecSmrg
33405b261ecSmrg                while (--n > 0) {
33505b261ecSmrg                    short x1, y1, x2, y2;
33605b261ecSmrg
33705b261ecSmrg                    glyph = *glyphs++;
33805b261ecSmrg
33905b261ecSmrg                    x1 = x - glyph->info.x;
34005b261ecSmrg                    y1 = y - glyph->info.y;
34105b261ecSmrg                    x2 = x1 + glyph->info.width;
34205b261ecSmrg                    y2 = y1 + glyph->info.height;
34305b261ecSmrg
34405b261ecSmrg                    box.x1 = MAX (box.x1, x1);
34505b261ecSmrg                    box.y1 = MAX (box.y1, y1);
34605b261ecSmrg                    box.x2 = MAX (box.x2, x2);
34705b261ecSmrg                    box.y2 = MAX (box.y2, y2);
34805b261ecSmrg
34905b261ecSmrg                    x += glyph->info.xOff;
35005b261ecSmrg                    y += glyph->info.yOff;
35105b261ecSmrg                }
35205b261ecSmrg
35305b261ecSmrg                RootlessDamageBox(dstWin, &box);
35405b261ecSmrg            }
35505b261ecSmrg            list++;
35605b261ecSmrg        }
35705b261ecSmrg    }
35805b261ecSmrg}
35905b261ecSmrg
36005b261ecSmrg#endif // RENDER
36105b261ecSmrg
36205b261ecSmrg
36305b261ecSmrg/*
36405b261ecSmrg * RootlessValidateTree
36505b261ecSmrg *  ValidateTree is modified in two ways:
36605b261ecSmrg *   - top-level windows don't clip each other
36705b261ecSmrg *   - windows aren't clipped against root.
36805b261ecSmrg *  These only matter when validating from the root.
36905b261ecSmrg */
37005b261ecSmrgstatic int
37105b261ecSmrgRootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
37205b261ecSmrg{
37305b261ecSmrg    int result;
37405b261ecSmrg    RegionRec saveRoot;
37505b261ecSmrg    ScreenPtr pScreen = pParent->drawable.pScreen;
37605b261ecSmrg
37705b261ecSmrg    SCREEN_UNWRAP(pScreen, ValidateTree);
37805b261ecSmrg    RL_DEBUG_MSG("VALIDATETREE start ");
37905b261ecSmrg
38005b261ecSmrg    // Use our custom version to validate from root
38105b261ecSmrg    if (IsRoot(pParent)) {
38205b261ecSmrg        RL_DEBUG_MSG("custom ");
38305b261ecSmrg        result = RootlessMiValidateTree(pParent, pChild, kind);
38405b261ecSmrg    } else {
38505b261ecSmrg        HUGE_ROOT(pParent);
38605b261ecSmrg        result = pScreen->ValidateTree(pParent, pChild, kind);
38705b261ecSmrg        NORMAL_ROOT(pParent);
38805b261ecSmrg    }
38905b261ecSmrg
39005b261ecSmrg    SCREEN_WRAP(pScreen, ValidateTree);
39105b261ecSmrg    RL_DEBUG_MSG("VALIDATETREE end\n");
39205b261ecSmrg
39305b261ecSmrg    return result;
39405b261ecSmrg}
39505b261ecSmrg
39605b261ecSmrg
39705b261ecSmrg/*
39805b261ecSmrg * RootlessMarkOverlappedWindows
39905b261ecSmrg *  MarkOverlappedWindows is modified to ignore overlapping
40005b261ecSmrg *  top-level windows.
40105b261ecSmrg */
40205b261ecSmrgstatic Bool
40305b261ecSmrgRootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
40405b261ecSmrg                              WindowPtr *ppLayerWin)
40505b261ecSmrg{
40605b261ecSmrg    RegionRec saveRoot;
40705b261ecSmrg    Bool result;
40805b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
40905b261ecSmrg    SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
41005b261ecSmrg    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
41105b261ecSmrg
41205b261ecSmrg    HUGE_ROOT(pWin);
41305b261ecSmrg    if (IsRoot(pWin)) {
41405b261ecSmrg        // root - mark nothing
41505b261ecSmrg        RL_DEBUG_MSG("is root not marking ");
41605b261ecSmrg        result = FALSE;
41705b261ecSmrg    }
41805b261ecSmrg    else if (! IsTopLevel(pWin)) {
41905b261ecSmrg        // not top-level window - mark normally
42005b261ecSmrg        result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
42105b261ecSmrg    }
42205b261ecSmrg    else {
42305b261ecSmrg        //top-level window - mark children ONLY - NO overlaps with sibs (?)
42405b261ecSmrg        // This code copied from miMarkOverlappedWindows()
42505b261ecSmrg
42605b261ecSmrg        register WindowPtr pChild;
42705b261ecSmrg        Bool anyMarked = FALSE;
42805b261ecSmrg        void (* MarkWindow)() = pScreen->MarkWindow;
42905b261ecSmrg
43005b261ecSmrg        RL_DEBUG_MSG("is top level! ");
43105b261ecSmrg        /* single layered systems are easy */
43205b261ecSmrg        if (ppLayerWin) *ppLayerWin = pWin;
43305b261ecSmrg
43405b261ecSmrg        if (pWin == pFirst) {
43505b261ecSmrg            /* Blindly mark pWin and all of its inferiors.   This is a slight
43605b261ecSmrg             * overkill if there are mapped windows that outside pWin's border,
43705b261ecSmrg             * but it's better than wasting time on RectIn checks.
43805b261ecSmrg             */
43905b261ecSmrg            pChild = pWin;
44005b261ecSmrg            while (1) {
44105b261ecSmrg                if (pChild->viewable) {
44205b261ecSmrg                    if (REGION_BROKEN (pScreen, &pChild->winSize))
44305b261ecSmrg                        SetWinSize (pChild);
44405b261ecSmrg                    if (REGION_BROKEN (pScreen, &pChild->borderSize))
44505b261ecSmrg                        SetBorderSize (pChild);
44605b261ecSmrg                    (* MarkWindow)(pChild);
44705b261ecSmrg                    if (pChild->firstChild) {
44805b261ecSmrg                        pChild = pChild->firstChild;
44905b261ecSmrg                        continue;
45005b261ecSmrg                    }
45105b261ecSmrg                }
45205b261ecSmrg                while (!pChild->nextSib && (pChild != pWin))
45305b261ecSmrg                    pChild = pChild->parent;
45405b261ecSmrg                if (pChild == pWin)
45505b261ecSmrg                    break;
45605b261ecSmrg                pChild = pChild->nextSib;
45705b261ecSmrg            }
45805b261ecSmrg            anyMarked = TRUE;
45905b261ecSmrg            pFirst = pFirst->nextSib;
46005b261ecSmrg        }
46105b261ecSmrg        if (anyMarked)
46205b261ecSmrg            (* MarkWindow)(pWin->parent);
46305b261ecSmrg        result = anyMarked;
46405b261ecSmrg    }
46505b261ecSmrg    NORMAL_ROOT(pWin);
46605b261ecSmrg    SCREEN_WRAP(pScreen, MarkOverlappedWindows);
46705b261ecSmrg    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
46805b261ecSmrg
46905b261ecSmrg    return result;
47005b261ecSmrg}
47105b261ecSmrg
47205b261ecSmrg
47305b261ecSmrgstatic CARD32
47405b261ecSmrgRootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg)
47505b261ecSmrg{
47605b261ecSmrg    RootlessScreenRec *screenRec = arg;
47705b261ecSmrg
47805b261ecSmrg    if (!screenRec->redisplay_queued) {
47905b261ecSmrg        /* No update needed. Stop the timer. */
48005b261ecSmrg
48105b261ecSmrg        screenRec->redisplay_timer_set = FALSE;
48205b261ecSmrg        return 0;
48305b261ecSmrg    }
48405b261ecSmrg
48505b261ecSmrg    screenRec->redisplay_queued = FALSE;
48605b261ecSmrg
48705b261ecSmrg    /* Mark that we should redisplay before waiting for I/O next time */
48805b261ecSmrg    screenRec->redisplay_expired = TRUE;
48905b261ecSmrg
49005b261ecSmrg    /* Reinstall the timer immediately, so we get as close to our
49105b261ecSmrg       redisplay interval as possible. */
49205b261ecSmrg
49305b261ecSmrg    return ROOTLESS_REDISPLAY_DELAY;
49405b261ecSmrg}
49505b261ecSmrg
49605b261ecSmrg
49705b261ecSmrg/*
49805b261ecSmrg * RootlessQueueRedisplay
49905b261ecSmrg *  Queue a redisplay after a timer delay to ensure we do not redisplay
50005b261ecSmrg *  too frequently.
50105b261ecSmrg */
50205b261ecSmrgvoid
50305b261ecSmrgRootlessQueueRedisplay(ScreenPtr pScreen)
50405b261ecSmrg{
50505b261ecSmrg    RootlessScreenRec *screenRec = SCREENREC(pScreen);
50605b261ecSmrg
50705b261ecSmrg    screenRec->redisplay_queued = TRUE;
50805b261ecSmrg
50905b261ecSmrg    if (screenRec->redisplay_timer_set)
51005b261ecSmrg        return;
51105b261ecSmrg
51205b261ecSmrg    screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer,
51305b261ecSmrg                                          0, ROOTLESS_REDISPLAY_DELAY,
51405b261ecSmrg                                          RootlessRedisplayCallback,
51505b261ecSmrg                                          screenRec);
51605b261ecSmrg    screenRec->redisplay_timer_set = TRUE;
51705b261ecSmrg}
51805b261ecSmrg
51905b261ecSmrg
52005b261ecSmrg/*
52105b261ecSmrg * RootlessBlockHandler
52205b261ecSmrg *  If the redisplay timer has expired, flush drawing before blocking
52305b261ecSmrg *  on select().
52405b261ecSmrg */
52505b261ecSmrgstatic void
52605b261ecSmrgRootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask)
52705b261ecSmrg{
52805b261ecSmrg    ScreenPtr pScreen = pbdata;
52905b261ecSmrg    RootlessScreenRec *screenRec = SCREENREC(pScreen);
53005b261ecSmrg
53105b261ecSmrg    if (screenRec->redisplay_expired) {
53205b261ecSmrg        screenRec->redisplay_expired = FALSE;
53305b261ecSmrg
53405b261ecSmrg        RootlessRedisplayScreen(pScreen);
53505b261ecSmrg    }
53605b261ecSmrg}
53705b261ecSmrg
53805b261ecSmrg
53905b261ecSmrgstatic void
54005b261ecSmrgRootlessWakeupHandler(pointer data, int i, pointer LastSelectMask)
54105b261ecSmrg{
54205b261ecSmrg    // nothing here
54305b261ecSmrg}
54405b261ecSmrg
54505b261ecSmrg
54605b261ecSmrgstatic Bool
54705b261ecSmrgRootlessAllocatePrivates(ScreenPtr pScreen)
54805b261ecSmrg{
54905b261ecSmrg    RootlessScreenRec *s;
55005b261ecSmrg    static unsigned long rootlessGeneration = 0;
55105b261ecSmrg
55205b261ecSmrg    if (rootlessGeneration != serverGeneration) {
55305b261ecSmrg        rootlessScreenPrivateIndex = AllocateScreenPrivateIndex();
55405b261ecSmrg        if (rootlessScreenPrivateIndex == -1) return FALSE;
55505b261ecSmrg        rootlessGCPrivateIndex = AllocateGCPrivateIndex();
55605b261ecSmrg        if (rootlessGCPrivateIndex == -1) return FALSE;
55705b261ecSmrg        rootlessWindowPrivateIndex = AllocateWindowPrivateIndex();
55805b261ecSmrg        if (rootlessWindowPrivateIndex == -1) return FALSE;
55905b261ecSmrg        rootlessGeneration = serverGeneration;
56005b261ecSmrg    }
56105b261ecSmrg
56205b261ecSmrg    // no allocation needed for screen privates
56305b261ecSmrg    if (!AllocateGCPrivate(pScreen, rootlessGCPrivateIndex,
56405b261ecSmrg                           sizeof(RootlessGCRec)))
56505b261ecSmrg        return FALSE;
56605b261ecSmrg    if (!AllocateWindowPrivate(pScreen, rootlessWindowPrivateIndex, 0))
56705b261ecSmrg        return FALSE;
56805b261ecSmrg
56905b261ecSmrg    s = xalloc(sizeof(RootlessScreenRec));
57005b261ecSmrg    if (! s) return FALSE;
57105b261ecSmrg    SCREENREC(pScreen) = s;
57205b261ecSmrg
57305b261ecSmrg    s->pixmap_data = NULL;
57405b261ecSmrg    s->pixmap_data_size = 0;
57505b261ecSmrg
57605b261ecSmrg    s->redisplay_timer = NULL;
57705b261ecSmrg    s->redisplay_timer_set = FALSE;
57805b261ecSmrg
57905b261ecSmrg    return TRUE;
58005b261ecSmrg}
58105b261ecSmrg
58205b261ecSmrg
58305b261ecSmrgstatic void
58405b261ecSmrgRootlessWrap(ScreenPtr pScreen)
58505b261ecSmrg{
58605b261ecSmrg    RootlessScreenRec *s = (RootlessScreenRec*)
58705b261ecSmrg            pScreen->devPrivates[rootlessScreenPrivateIndex].ptr;
58805b261ecSmrg
58905b261ecSmrg#define WRAP(a) \
59005b261ecSmrg    if (pScreen->a) { \
59105b261ecSmrg        s->a = pScreen->a; \
59205b261ecSmrg    } else { \
59305b261ecSmrg        RL_DEBUG_MSG("null screen fn " #a "\n"); \
59405b261ecSmrg        s->a = NULL; \
59505b261ecSmrg    } \
59605b261ecSmrg    pScreen->a = Rootless##a
59705b261ecSmrg
59805b261ecSmrg    WRAP(CreateScreenResources);
59905b261ecSmrg    WRAP(CloseScreen);
60005b261ecSmrg    WRAP(CreateGC);
60105b261ecSmrg    WRAP(PaintWindowBackground);
60205b261ecSmrg    WRAP(PaintWindowBorder);
60305b261ecSmrg    WRAP(CopyWindow);
60405b261ecSmrg    WRAP(GetImage);
60505b261ecSmrg    WRAP(SourceValidate);
60605b261ecSmrg    WRAP(CreateWindow);
60705b261ecSmrg    WRAP(DestroyWindow);
60805b261ecSmrg    WRAP(RealizeWindow);
60905b261ecSmrg    WRAP(UnrealizeWindow);
61005b261ecSmrg    WRAP(MoveWindow);
61105b261ecSmrg    WRAP(PositionWindow);
61205b261ecSmrg    WRAP(ResizeWindow);
61305b261ecSmrg    WRAP(RestackWindow);
61405b261ecSmrg    WRAP(ReparentWindow);
61505b261ecSmrg    WRAP(ChangeBorderWidth);
61605b261ecSmrg    WRAP(MarkOverlappedWindows);
61705b261ecSmrg    WRAP(ValidateTree);
61805b261ecSmrg    WRAP(ChangeWindowAttributes);
61905b261ecSmrg
62005b261ecSmrg#ifdef SHAPE
62105b261ecSmrg    WRAP(SetShape);
62205b261ecSmrg#endif
62305b261ecSmrg
62405b261ecSmrg#ifdef RENDER
62505b261ecSmrg    {
62605b261ecSmrg        // Composite and Glyphs don't use normal screen wrapping
62705b261ecSmrg        PictureScreenPtr ps = GetPictureScreen(pScreen);
62805b261ecSmrg        s->Composite = ps->Composite;
62905b261ecSmrg        ps->Composite = RootlessComposite;
63005b261ecSmrg        s->Glyphs = ps->Glyphs;
63105b261ecSmrg        ps->Glyphs = RootlessGlyphs;
63205b261ecSmrg    }
63305b261ecSmrg#endif
63405b261ecSmrg
63505b261ecSmrg    // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
63605b261ecSmrg    // WRAP(RestoreAreas); fixme put this back?
63705b261ecSmrg
63805b261ecSmrg#undef WRAP
63905b261ecSmrg}
64005b261ecSmrg
64105b261ecSmrg
64205b261ecSmrg/*
64305b261ecSmrg * RootlessInit
64405b261ecSmrg *  Called by the rootless implementation to initialize the rootless layer.
64505b261ecSmrg *  Rootless wraps lots of stuff and needs a bunch of devPrivates.
64605b261ecSmrg */
64705b261ecSmrgBool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
64805b261ecSmrg{
64905b261ecSmrg    RootlessScreenRec *s;
65005b261ecSmrg
65105b261ecSmrg    if (!RootlessAllocatePrivates(pScreen))
65205b261ecSmrg        return FALSE;
65305b261ecSmrg
65405b261ecSmrg    s = (RootlessScreenRec*)
65505b261ecSmrg        pScreen->devPrivates[rootlessScreenPrivateIndex].ptr;
65605b261ecSmrg
65705b261ecSmrg    s->imp = procs;
65805b261ecSmrg
65905b261ecSmrg    RootlessWrap(pScreen);
66005b261ecSmrg
66105b261ecSmrg    if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler,
66205b261ecSmrg                                        RootlessWakeupHandler,
66305b261ecSmrg                                        (pointer) pScreen))
66405b261ecSmrg    {
66505b261ecSmrg        return FALSE;
66605b261ecSmrg    }
66705b261ecSmrg
66805b261ecSmrg    return TRUE;
66905b261ecSmrg}
670