rootlessScreen.c revision 9ace9065
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"
454642e01fSmrg#include "colormapst.h"
4605b261ecSmrg
4705b261ecSmrg#include <sys/types.h>
4805b261ecSmrg#include <sys/stat.h>
4905b261ecSmrg#include <fcntl.h>
5005b261ecSmrg#include <string.h>
5105b261ecSmrg
5205b261ecSmrg#include "rootlessCommon.h"
5305b261ecSmrg#include "rootlessWindow.h"
5405b261ecSmrg
5505b261ecSmrg/* In milliseconds */
5605b261ecSmrg#ifndef ROOTLESS_REDISPLAY_DELAY
5705b261ecSmrg#define ROOTLESS_REDISPLAY_DELAY 10
5805b261ecSmrg#endif
5905b261ecSmrg
6005b261ecSmrgextern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild,
6105b261ecSmrg                                  VTKind kind);
6205b261ecSmrgextern Bool RootlessCreateGC(GCPtr pGC);
6305b261ecSmrg
6405b261ecSmrg// Initialize globals
656747b715SmrgDevPrivateKeyRec rootlessGCPrivateKeyRec;
666747b715SmrgDevPrivateKeyRec rootlessScreenPrivateKeyRec;
676747b715SmrgDevPrivateKeyRec rootlessWindowPrivateKeyRec;
686747b715SmrgDevPrivateKeyRec rootlessWindowOldPixmapPrivateKeyRec;
6905b261ecSmrg
7005b261ecSmrg/*
7105b261ecSmrg * RootlessUpdateScreenPixmap
7205b261ecSmrg *  miCreateScreenResources does not like a null framebuffer pointer,
7305b261ecSmrg *  it leaves the screen pixmap with an uninitialized data pointer.
7405b261ecSmrg *  Thus, rootless implementations typically set the framebuffer width
7505b261ecSmrg *  to zero so that miCreateScreenResources does not allocate a screen
7605b261ecSmrg *  pixmap for us. We allocate our own screen pixmap here since we need
7705b261ecSmrg *  the screen pixmap to be valid (e.g. CopyArea from the root window).
7805b261ecSmrg */
7905b261ecSmrgvoid
8005b261ecSmrgRootlessUpdateScreenPixmap(ScreenPtr pScreen)
8105b261ecSmrg{
8205b261ecSmrg    RootlessScreenRec *s = SCREENREC(pScreen);
8305b261ecSmrg    PixmapPtr pPix;
8405b261ecSmrg    unsigned int rowbytes;
8505b261ecSmrg
8605b261ecSmrg    pPix = (*pScreen->GetScreenPixmap)(pScreen);
8705b261ecSmrg    if (pPix == NULL) {
884642e01fSmrg        pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0);
8905b261ecSmrg        (*pScreen->SetScreenPixmap)(pPix);
9005b261ecSmrg    }
9105b261ecSmrg
9205b261ecSmrg    rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth);
9305b261ecSmrg
9405b261ecSmrg    if (s->pixmap_data_size < rowbytes) {
959ace9065Smrg        free(s->pixmap_data);
9605b261ecSmrg
9705b261ecSmrg        s->pixmap_data_size = rowbytes;
986747b715Smrg        s->pixmap_data = malloc(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) {
1546747b715Smrg        free(s->pixmap_data);
15505b261ecSmrg        s->pixmap_data = NULL;
15605b261ecSmrg        s->pixmap_data_size = 0;
15705b261ecSmrg    }
15805b261ecSmrg
1596747b715Smrg    free(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
1976747b715Smrg        x0 = max (x0, winRec->x);
1986747b715Smrg        y0 = max (y0, winRec->y);
1996747b715Smrg        x1 = min (x1, winRec->x + winRec->width);
2006747b715Smrg        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
2269ace9065SmrgRootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h,
2279ace9065Smrg                       unsigned int subWindowMode)
22805b261ecSmrg{
22905b261ecSmrg    SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate);
23005b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
23105b261ecSmrg        WindowPtr pWin = (WindowPtr)pDrawable;
23205b261ecSmrg        RootlessStartDrawing(pWin);
23305b261ecSmrg    }
23405b261ecSmrg    if (pDrawable->pScreen->SourceValidate) {
2359ace9065Smrg        pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h, subWindowMode);
23605b261ecSmrg    }
23705b261ecSmrg    SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
23805b261ecSmrg}
23905b261ecSmrg
24005b261ecSmrgstatic void
24105b261ecSmrgRootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
24205b261ecSmrg                  INT16 xSrc, INT16 ySrc, INT16  xMask, INT16  yMask,
24305b261ecSmrg                  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
24405b261ecSmrg{
24505b261ecSmrg    ScreenPtr pScreen = pDst->pDrawable->pScreen;
24605b261ecSmrg    PictureScreenPtr ps = GetPictureScreen(pScreen);
24705b261ecSmrg    WindowPtr srcWin, dstWin, maskWin = NULL;
24805b261ecSmrg
24905b261ecSmrg    if (pMask) {                        // pMask can be NULL
25005b261ecSmrg        maskWin = (pMask->pDrawable->type == DRAWABLE_WINDOW) ?
25105b261ecSmrg                  (WindowPtr)pMask->pDrawable :  NULL;
25205b261ecSmrg    }
2536747b715Smrg    srcWin  = (pSrc->pDrawable && pSrc->pDrawable->type  == DRAWABLE_WINDOW) ?
25405b261ecSmrg              (WindowPtr)pSrc->pDrawable  :  NULL;
25505b261ecSmrg    dstWin  = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
25605b261ecSmrg              (WindowPtr)pDst->pDrawable  :  NULL;
25705b261ecSmrg
25805b261ecSmrg    // SCREEN_UNWRAP(ps, Composite);
25905b261ecSmrg    ps->Composite = SCREENREC(pScreen)->Composite;
26005b261ecSmrg
26105b261ecSmrg    if (srcWin  && IsFramedWindow(srcWin))
26205b261ecSmrg        RootlessStartDrawing(srcWin);
26305b261ecSmrg    if (maskWin && IsFramedWindow(maskWin))
26405b261ecSmrg        RootlessStartDrawing(maskWin);
26505b261ecSmrg    if (dstWin  && IsFramedWindow(dstWin))
26605b261ecSmrg        RootlessStartDrawing(dstWin);
26705b261ecSmrg
26805b261ecSmrg    ps->Composite(op, pSrc, pMask, pDst,
26905b261ecSmrg                  xSrc, ySrc, xMask, yMask,
27005b261ecSmrg                  xDst, yDst, width, height);
27105b261ecSmrg
27205b261ecSmrg    if (dstWin  && IsFramedWindow(dstWin)) {
27305b261ecSmrg        RootlessDamageRect(dstWin, xDst, yDst, width, height);
27405b261ecSmrg    }
27505b261ecSmrg
27605b261ecSmrg    ps->Composite = RootlessComposite;
27705b261ecSmrg    // SCREEN_WRAP(ps, Composite);
27805b261ecSmrg}
27905b261ecSmrg
28005b261ecSmrg
28105b261ecSmrgstatic void
28205b261ecSmrgRootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
28305b261ecSmrg               PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
28405b261ecSmrg               int nlist, GlyphListPtr list, GlyphPtr *glyphs)
28505b261ecSmrg{
28605b261ecSmrg    ScreenPtr pScreen = pDst->pDrawable->pScreen;
28705b261ecSmrg    PictureScreenPtr ps = GetPictureScreen(pScreen);
28805b261ecSmrg    int x, y;
28905b261ecSmrg    int n;
29005b261ecSmrg    GlyphPtr glyph;
29105b261ecSmrg    WindowPtr srcWin, dstWin;
29205b261ecSmrg
2936747b715Smrg    srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
29405b261ecSmrg             (WindowPtr)pSrc->pDrawable  :  NULL;
29505b261ecSmrg    dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
29605b261ecSmrg             (WindowPtr)pDst->pDrawable  :  NULL;
29705b261ecSmrg
29805b261ecSmrg    if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin);
29905b261ecSmrg    if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin);
30005b261ecSmrg
30105b261ecSmrg    //SCREEN_UNWRAP(ps, Glyphs);
30205b261ecSmrg    ps->Glyphs = SCREENREC(pScreen)->Glyphs;
30305b261ecSmrg    ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
30405b261ecSmrg    ps->Glyphs = RootlessGlyphs;
30505b261ecSmrg    //SCREEN_WRAP(ps, Glyphs);
30605b261ecSmrg
30705b261ecSmrg    if (dstWin && IsFramedWindow(dstWin)) {
30805b261ecSmrg        x = xSrc;
30905b261ecSmrg        y = ySrc;
31005b261ecSmrg
31105b261ecSmrg        while (nlist--) {
31205b261ecSmrg            x += list->xOff;
31305b261ecSmrg            y += list->yOff;
31405b261ecSmrg            n = list->len;
31505b261ecSmrg
31605b261ecSmrg            /* Calling DamageRect for the bounding box of each glyph is
31705b261ecSmrg               inefficient. So compute the union of all glyphs in a list
31805b261ecSmrg               and damage that. */
31905b261ecSmrg
32005b261ecSmrg            if (n > 0) {
32105b261ecSmrg                BoxRec box;
32205b261ecSmrg
32305b261ecSmrg                glyph = *glyphs++;
32405b261ecSmrg
32505b261ecSmrg                box.x1 = x - glyph->info.x;
32605b261ecSmrg                box.y1 = y - glyph->info.y;
32705b261ecSmrg                box.x2 = box.x1 + glyph->info.width;
3289ace9065Smrg                box.y2 = box.y1 + glyph->info.height;
32905b261ecSmrg
33005b261ecSmrg                x += glyph->info.xOff;
33105b261ecSmrg                y += glyph->info.yOff;
33205b261ecSmrg
33305b261ecSmrg                while (--n > 0) {
33405b261ecSmrg                    short x1, y1, x2, y2;
33505b261ecSmrg
33605b261ecSmrg                    glyph = *glyphs++;
33705b261ecSmrg
33805b261ecSmrg                    x1 = x - glyph->info.x;
33905b261ecSmrg                    y1 = y - glyph->info.y;
34005b261ecSmrg                    x2 = x1 + glyph->info.width;
34105b261ecSmrg                    y2 = y1 + glyph->info.height;
34205b261ecSmrg
3436747b715Smrg                    box.x1 = max (box.x1, x1);
3446747b715Smrg                    box.y1 = max (box.y1, y1);
3456747b715Smrg                    box.x2 = max (box.x2, x2);
3466747b715Smrg                    box.y2 = max (box.y2, y2);
34705b261ecSmrg
34805b261ecSmrg                    x += glyph->info.xOff;
34905b261ecSmrg                    y += glyph->info.yOff;
35005b261ecSmrg                }
35105b261ecSmrg
35205b261ecSmrg                RootlessDamageBox(dstWin, &box);
35305b261ecSmrg            }
35405b261ecSmrg            list++;
35505b261ecSmrg        }
35605b261ecSmrg    }
35705b261ecSmrg}
35805b261ecSmrg
35905b261ecSmrg
36005b261ecSmrg/*
36105b261ecSmrg * RootlessValidateTree
36205b261ecSmrg *  ValidateTree is modified in two ways:
36305b261ecSmrg *   - top-level windows don't clip each other
36405b261ecSmrg *   - windows aren't clipped against root.
36505b261ecSmrg *  These only matter when validating from the root.
36605b261ecSmrg */
36705b261ecSmrgstatic int
36805b261ecSmrgRootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
36905b261ecSmrg{
37005b261ecSmrg    int result;
37105b261ecSmrg    RegionRec saveRoot;
37205b261ecSmrg    ScreenPtr pScreen = pParent->drawable.pScreen;
37305b261ecSmrg
37405b261ecSmrg    SCREEN_UNWRAP(pScreen, ValidateTree);
37505b261ecSmrg    RL_DEBUG_MSG("VALIDATETREE start ");
37605b261ecSmrg
37705b261ecSmrg    // Use our custom version to validate from root
37805b261ecSmrg    if (IsRoot(pParent)) {
37905b261ecSmrg        RL_DEBUG_MSG("custom ");
38005b261ecSmrg        result = RootlessMiValidateTree(pParent, pChild, kind);
38105b261ecSmrg    } else {
38205b261ecSmrg        HUGE_ROOT(pParent);
38305b261ecSmrg        result = pScreen->ValidateTree(pParent, pChild, kind);
38405b261ecSmrg        NORMAL_ROOT(pParent);
38505b261ecSmrg    }
38605b261ecSmrg
38705b261ecSmrg    SCREEN_WRAP(pScreen, ValidateTree);
38805b261ecSmrg    RL_DEBUG_MSG("VALIDATETREE end\n");
38905b261ecSmrg
39005b261ecSmrg    return result;
39105b261ecSmrg}
39205b261ecSmrg
39305b261ecSmrg
39405b261ecSmrg/*
39505b261ecSmrg * RootlessMarkOverlappedWindows
39605b261ecSmrg *  MarkOverlappedWindows is modified to ignore overlapping
39705b261ecSmrg *  top-level windows.
39805b261ecSmrg */
39905b261ecSmrgstatic Bool
40005b261ecSmrgRootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
40105b261ecSmrg                              WindowPtr *ppLayerWin)
40205b261ecSmrg{
40305b261ecSmrg    RegionRec saveRoot;
40405b261ecSmrg    Bool result;
40505b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
40605b261ecSmrg    SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
40705b261ecSmrg    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
40805b261ecSmrg
40905b261ecSmrg    HUGE_ROOT(pWin);
41005b261ecSmrg    if (IsRoot(pWin)) {
41105b261ecSmrg        // root - mark nothing
41205b261ecSmrg        RL_DEBUG_MSG("is root not marking ");
41305b261ecSmrg        result = FALSE;
41405b261ecSmrg    }
41505b261ecSmrg    else if (! IsTopLevel(pWin)) {
41605b261ecSmrg        // not top-level window - mark normally
41705b261ecSmrg        result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
41805b261ecSmrg    }
41905b261ecSmrg    else {
42005b261ecSmrg        //top-level window - mark children ONLY - NO overlaps with sibs (?)
42105b261ecSmrg        // This code copied from miMarkOverlappedWindows()
42205b261ecSmrg
42305b261ecSmrg        register WindowPtr pChild;
42405b261ecSmrg        Bool anyMarked = FALSE;
4256747b715Smrg        MarkWindowProcPtr MarkWindow = pScreen->MarkWindow;
42605b261ecSmrg
42705b261ecSmrg        RL_DEBUG_MSG("is top level! ");
42805b261ecSmrg        /* single layered systems are easy */
42905b261ecSmrg        if (ppLayerWin) *ppLayerWin = pWin;
43005b261ecSmrg
43105b261ecSmrg        if (pWin == pFirst) {
43205b261ecSmrg            /* Blindly mark pWin and all of its inferiors.   This is a slight
43305b261ecSmrg             * overkill if there are mapped windows that outside pWin's border,
43405b261ecSmrg             * but it's better than wasting time on RectIn checks.
43505b261ecSmrg             */
43605b261ecSmrg            pChild = pWin;
43705b261ecSmrg            while (1) {
43805b261ecSmrg                if (pChild->viewable) {
4396747b715Smrg                    if (RegionBroken(&pChild->winSize))
44005b261ecSmrg                        SetWinSize (pChild);
4416747b715Smrg                    if (RegionBroken(&pChild->borderSize))
44205b261ecSmrg                        SetBorderSize (pChild);
44305b261ecSmrg                    (* MarkWindow)(pChild);
44405b261ecSmrg                    if (pChild->firstChild) {
44505b261ecSmrg                        pChild = pChild->firstChild;
44605b261ecSmrg                        continue;
44705b261ecSmrg                    }
44805b261ecSmrg                }
44905b261ecSmrg                while (!pChild->nextSib && (pChild != pWin))
45005b261ecSmrg                    pChild = pChild->parent;
45105b261ecSmrg                if (pChild == pWin)
45205b261ecSmrg                    break;
45305b261ecSmrg                pChild = pChild->nextSib;
45405b261ecSmrg            }
45505b261ecSmrg            anyMarked = TRUE;
45605b261ecSmrg            pFirst = pFirst->nextSib;
45705b261ecSmrg        }
45805b261ecSmrg        if (anyMarked)
45905b261ecSmrg            (* MarkWindow)(pWin->parent);
46005b261ecSmrg        result = anyMarked;
46105b261ecSmrg    }
46205b261ecSmrg    NORMAL_ROOT(pWin);
46305b261ecSmrg    SCREEN_WRAP(pScreen, MarkOverlappedWindows);
46405b261ecSmrg    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
46505b261ecSmrg
46605b261ecSmrg    return result;
46705b261ecSmrg}
46805b261ecSmrg
4696747b715Smrgstatic void expose_1 (WindowPtr pWin) {
4704642e01fSmrg    WindowPtr pChild;
4714642e01fSmrg
4724642e01fSmrg    if (!pWin->realized)
4734642e01fSmrg        return;
4744642e01fSmrg
4756747b715Smrg    miPaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND);
4764642e01fSmrg
4774642e01fSmrg    /* FIXME: comments in windowstr.h indicate that borderClip doesn't
4784642e01fSmrg     include subwindow visibility. But I'm not so sure.. so we may
4794642e01fSmrg     be exposing too much.. */
4804642e01fSmrg
4814642e01fSmrg    miSendExposures (pWin, &pWin->borderClip,
4824642e01fSmrg                     pWin->drawable.x, pWin->drawable.y);
4834642e01fSmrg
4844642e01fSmrg    for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib)
4854642e01fSmrg        expose_1 (pChild);
4864642e01fSmrg}
4874642e01fSmrg
4884642e01fSmrgvoid
4894642e01fSmrgRootlessScreenExpose (ScreenPtr pScreen)
4904642e01fSmrg{
4916747b715Smrg    expose_1 (pScreen->root);
4924642e01fSmrg}
4934642e01fSmrg
4944642e01fSmrg
4954642e01fSmrgColormapPtr
4964642e01fSmrgRootlessGetColormap (ScreenPtr pScreen)
4974642e01fSmrg{
4984642e01fSmrg  RootlessScreenRec *s = SCREENREC (pScreen);
4994642e01fSmrg
5004642e01fSmrg  return s->colormap;
5014642e01fSmrg}
5024642e01fSmrg
5034642e01fSmrgstatic void
5044642e01fSmrgRootlessInstallColormap (ColormapPtr pMap)
5054642e01fSmrg{
5064642e01fSmrg  ScreenPtr pScreen = pMap->pScreen;
5074642e01fSmrg  RootlessScreenRec *s = SCREENREC (pScreen);
5084642e01fSmrg
5094642e01fSmrg  SCREEN_UNWRAP(pScreen, InstallColormap);
5104642e01fSmrg
5114642e01fSmrg  if (s->colormap != pMap) {
5124642e01fSmrg    s->colormap = pMap;
5134642e01fSmrg    s->colormap_changed = TRUE;
5144642e01fSmrg    RootlessQueueRedisplay (pScreen);
5154642e01fSmrg  }
5164642e01fSmrg
5174642e01fSmrg  pScreen->InstallColormap (pMap);
5184642e01fSmrg
5194642e01fSmrg  SCREEN_WRAP (pScreen, InstallColormap);
5204642e01fSmrg}
5214642e01fSmrg
5224642e01fSmrgstatic void
5234642e01fSmrgRootlessUninstallColormap (ColormapPtr pMap)
5244642e01fSmrg{
5254642e01fSmrg  ScreenPtr pScreen = pMap->pScreen;
5264642e01fSmrg  RootlessScreenRec *s = SCREENREC (pScreen);
5274642e01fSmrg
5284642e01fSmrg  SCREEN_UNWRAP(pScreen, UninstallColormap);
5294642e01fSmrg
5304642e01fSmrg  if (s->colormap == pMap)
5314642e01fSmrg    s->colormap = NULL;
5324642e01fSmrg
5334642e01fSmrg  pScreen->UninstallColormap (pMap);
5344642e01fSmrg
5354642e01fSmrg  SCREEN_WRAP(pScreen, UninstallColormap);
5364642e01fSmrg}
5374642e01fSmrg
5384642e01fSmrgstatic void
5394642e01fSmrgRootlessStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef)
5404642e01fSmrg{
5414642e01fSmrg  ScreenPtr pScreen = pMap->pScreen;
5424642e01fSmrg  RootlessScreenRec *s = SCREENREC (pScreen);
5434642e01fSmrg
5444642e01fSmrg  SCREEN_UNWRAP(pScreen, StoreColors);
5454642e01fSmrg
5464642e01fSmrg  if (s->colormap == pMap && ndef > 0) {
5474642e01fSmrg    s->colormap_changed = TRUE;
5484642e01fSmrg    RootlessQueueRedisplay (pScreen);
5494642e01fSmrg  }
5504642e01fSmrg
5514642e01fSmrg  pScreen->StoreColors (pMap, ndef, pdef);
5524642e01fSmrg
5534642e01fSmrg  SCREEN_WRAP(pScreen, StoreColors);
5544642e01fSmrg}
5554642e01fSmrg
55605b261ecSmrg
55705b261ecSmrgstatic CARD32
55805b261ecSmrgRootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg)
55905b261ecSmrg{
56005b261ecSmrg    RootlessScreenRec *screenRec = arg;
56105b261ecSmrg
56205b261ecSmrg    if (!screenRec->redisplay_queued) {
56305b261ecSmrg        /* No update needed. Stop the timer. */
56405b261ecSmrg
56505b261ecSmrg        screenRec->redisplay_timer_set = FALSE;
56605b261ecSmrg        return 0;
56705b261ecSmrg    }
56805b261ecSmrg
56905b261ecSmrg    screenRec->redisplay_queued = FALSE;
57005b261ecSmrg
57105b261ecSmrg    /* Mark that we should redisplay before waiting for I/O next time */
57205b261ecSmrg    screenRec->redisplay_expired = TRUE;
57305b261ecSmrg
57405b261ecSmrg    /* Reinstall the timer immediately, so we get as close to our
57505b261ecSmrg       redisplay interval as possible. */
57605b261ecSmrg
57705b261ecSmrg    return ROOTLESS_REDISPLAY_DELAY;
57805b261ecSmrg}
57905b261ecSmrg
58005b261ecSmrg
58105b261ecSmrg/*
58205b261ecSmrg * RootlessQueueRedisplay
58305b261ecSmrg *  Queue a redisplay after a timer delay to ensure we do not redisplay
58405b261ecSmrg *  too frequently.
58505b261ecSmrg */
58605b261ecSmrgvoid
58705b261ecSmrgRootlessQueueRedisplay(ScreenPtr pScreen)
58805b261ecSmrg{
58905b261ecSmrg    RootlessScreenRec *screenRec = SCREENREC(pScreen);
59005b261ecSmrg
59105b261ecSmrg    screenRec->redisplay_queued = TRUE;
59205b261ecSmrg
59305b261ecSmrg    if (screenRec->redisplay_timer_set)
59405b261ecSmrg        return;
59505b261ecSmrg
59605b261ecSmrg    screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer,
59705b261ecSmrg                                          0, ROOTLESS_REDISPLAY_DELAY,
59805b261ecSmrg                                          RootlessRedisplayCallback,
59905b261ecSmrg                                          screenRec);
60005b261ecSmrg    screenRec->redisplay_timer_set = TRUE;
60105b261ecSmrg}
60205b261ecSmrg
60305b261ecSmrg
60405b261ecSmrg/*
60505b261ecSmrg * RootlessBlockHandler
60605b261ecSmrg *  If the redisplay timer has expired, flush drawing before blocking
60705b261ecSmrg *  on select().
60805b261ecSmrg */
60905b261ecSmrgstatic void
61005b261ecSmrgRootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask)
61105b261ecSmrg{
61205b261ecSmrg    ScreenPtr pScreen = pbdata;
61305b261ecSmrg    RootlessScreenRec *screenRec = SCREENREC(pScreen);
61405b261ecSmrg
61505b261ecSmrg    if (screenRec->redisplay_expired) {
61605b261ecSmrg        screenRec->redisplay_expired = FALSE;
61705b261ecSmrg
61805b261ecSmrg        RootlessRedisplayScreen(pScreen);
61905b261ecSmrg    }
62005b261ecSmrg}
62105b261ecSmrg
62205b261ecSmrg
62305b261ecSmrgstatic void
62405b261ecSmrgRootlessWakeupHandler(pointer data, int i, pointer LastSelectMask)
62505b261ecSmrg{
62605b261ecSmrg    // nothing here
62705b261ecSmrg}
62805b261ecSmrg
62905b261ecSmrg
63005b261ecSmrgstatic Bool
63105b261ecSmrgRootlessAllocatePrivates(ScreenPtr pScreen)
63205b261ecSmrg{
63305b261ecSmrg    RootlessScreenRec *s;
63405b261ecSmrg
6356747b715Smrg    if (!dixRegisterPrivateKey(&rootlessGCPrivateKeyRec, PRIVATE_GC, sizeof(RootlessGCRec)))
6366747b715Smrg        return FALSE;
6376747b715Smrg    if (!dixRegisterPrivateKey(&rootlessScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
6386747b715Smrg        return FALSE;
6396747b715Smrg    if (!dixRegisterPrivateKey(&rootlessWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
6406747b715Smrg        return FALSE;
6416747b715Smrg    if (!dixRegisterPrivateKey(&rootlessWindowOldPixmapPrivateKeyRec, PRIVATE_WINDOW, 0))
64205b261ecSmrg        return FALSE;
64305b261ecSmrg
6446747b715Smrg    s = malloc(sizeof(RootlessScreenRec));
64505b261ecSmrg    if (! s) return FALSE;
6464642e01fSmrg    SETSCREENREC(pScreen, s);
64705b261ecSmrg
64805b261ecSmrg    s->pixmap_data = NULL;
64905b261ecSmrg    s->pixmap_data_size = 0;
65005b261ecSmrg
65105b261ecSmrg    s->redisplay_timer = NULL;
65205b261ecSmrg    s->redisplay_timer_set = FALSE;
65305b261ecSmrg
65405b261ecSmrg    return TRUE;
65505b261ecSmrg}
65605b261ecSmrg
65705b261ecSmrg
65805b261ecSmrgstatic void
65905b261ecSmrgRootlessWrap(ScreenPtr pScreen)
66005b261ecSmrg{
6614642e01fSmrg    RootlessScreenRec *s = SCREENREC(pScreen);
66205b261ecSmrg
66305b261ecSmrg#define WRAP(a) \
66405b261ecSmrg    if (pScreen->a) { \
66505b261ecSmrg        s->a = pScreen->a; \
66605b261ecSmrg    } else { \
66705b261ecSmrg        RL_DEBUG_MSG("null screen fn " #a "\n"); \
66805b261ecSmrg        s->a = NULL; \
66905b261ecSmrg    } \
67005b261ecSmrg    pScreen->a = Rootless##a
67105b261ecSmrg
67205b261ecSmrg    WRAP(CreateScreenResources);
67305b261ecSmrg    WRAP(CloseScreen);
67405b261ecSmrg    WRAP(CreateGC);
67505b261ecSmrg    WRAP(CopyWindow);
67605b261ecSmrg    WRAP(GetImage);
67705b261ecSmrg    WRAP(SourceValidate);
67805b261ecSmrg    WRAP(CreateWindow);
67905b261ecSmrg    WRAP(DestroyWindow);
68005b261ecSmrg    WRAP(RealizeWindow);
68105b261ecSmrg    WRAP(UnrealizeWindow);
68205b261ecSmrg    WRAP(MoveWindow);
68305b261ecSmrg    WRAP(PositionWindow);
68405b261ecSmrg    WRAP(ResizeWindow);
68505b261ecSmrg    WRAP(RestackWindow);
68605b261ecSmrg    WRAP(ReparentWindow);
68705b261ecSmrg    WRAP(ChangeBorderWidth);
68805b261ecSmrg    WRAP(MarkOverlappedWindows);
68905b261ecSmrg    WRAP(ValidateTree);
69005b261ecSmrg    WRAP(ChangeWindowAttributes);
6914642e01fSmrg    WRAP(InstallColormap);
6924642e01fSmrg    WRAP(UninstallColormap);
6934642e01fSmrg    WRAP(StoreColors);
69405b261ecSmrg
69505b261ecSmrg    WRAP(SetShape);
69605b261ecSmrg
69705b261ecSmrg    {
69805b261ecSmrg        // Composite and Glyphs don't use normal screen wrapping
69905b261ecSmrg        PictureScreenPtr ps = GetPictureScreen(pScreen);
70005b261ecSmrg        s->Composite = ps->Composite;
70105b261ecSmrg        ps->Composite = RootlessComposite;
70205b261ecSmrg        s->Glyphs = ps->Glyphs;
70305b261ecSmrg        ps->Glyphs = RootlessGlyphs;
70405b261ecSmrg    }
70505b261ecSmrg
70605b261ecSmrg    // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
70705b261ecSmrg
70805b261ecSmrg#undef WRAP
70905b261ecSmrg}
71005b261ecSmrg
71105b261ecSmrg
71205b261ecSmrg/*
71305b261ecSmrg * RootlessInit
71405b261ecSmrg *  Called by the rootless implementation to initialize the rootless layer.
71505b261ecSmrg *  Rootless wraps lots of stuff and needs a bunch of devPrivates.
71605b261ecSmrg */
71705b261ecSmrgBool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
71805b261ecSmrg{
71905b261ecSmrg    RootlessScreenRec *s;
72005b261ecSmrg
72105b261ecSmrg    if (!RootlessAllocatePrivates(pScreen))
72205b261ecSmrg        return FALSE;
72305b261ecSmrg
7244642e01fSmrg    s = SCREENREC(pScreen);
72505b261ecSmrg
72605b261ecSmrg    s->imp = procs;
7274642e01fSmrg    s->colormap = NULL;
7284642e01fSmrg    s->redisplay_expired = FALSE;
72905b261ecSmrg
73005b261ecSmrg    RootlessWrap(pScreen);
73105b261ecSmrg
73205b261ecSmrg    if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler,
73305b261ecSmrg                                        RootlessWakeupHandler,
73405b261ecSmrg                                        (pointer) pScreen))
73505b261ecSmrg    {
73605b261ecSmrg        return FALSE;
73705b261ecSmrg    }
73805b261ecSmrg
73905b261ecSmrg    return TRUE;
74005b261ecSmrg}
7414642e01fSmrg
7424642e01fSmrgvoid RootlessUpdateRooted (Bool state) {
7434642e01fSmrg    int i;
7444642e01fSmrg
7454642e01fSmrg    if (!state)
7464642e01fSmrg    {
7474642e01fSmrg        for (i = 0; i < screenInfo.numScreens; i++)
7484642e01fSmrg            RootlessDisableRoot (screenInfo.screens[i]);
7494642e01fSmrg    }
7504642e01fSmrg    else
7514642e01fSmrg    {
7524642e01fSmrg        for (i = 0; i < screenInfo.numScreens; i++)
7534642e01fSmrg            RootlessEnableRoot (screenInfo.screens[i]);
7544642e01fSmrg    }
7554642e01fSmrg}
756