1706f2543Smrg/*
2706f2543Smrg * Screen routines for generic rootless X server
3706f2543Smrg */
4706f2543Smrg/*
5706f2543Smrg * Copyright (c) 2001 Greg Parker. All Rights Reserved.
6706f2543Smrg * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
7706f2543Smrg * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
8706f2543Smrg *
9706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
10706f2543Smrg * copy of this software and associated documentation files (the "Software"),
11706f2543Smrg * to deal in the Software without restriction, including without limitation
12706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
14706f2543Smrg * Software is furnished to do so, subject to the following conditions:
15706f2543Smrg *
16706f2543Smrg * The above copyright notice and this permission notice shall be included in
17706f2543Smrg * all copies or substantial portions of the Software.
18706f2543Smrg *
19706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22706f2543Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25706f2543Smrg * DEALINGS IN THE SOFTWARE.
26706f2543Smrg *
27706f2543Smrg * Except as contained in this notice, the name(s) of the above copyright
28706f2543Smrg * holders shall not be used in advertising or otherwise to promote the sale,
29706f2543Smrg * use or other dealings in this Software without prior written authorization.
30706f2543Smrg */
31706f2543Smrg
32706f2543Smrg
33706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
34706f2543Smrg#include <dix-config.h>
35706f2543Smrg#endif
36706f2543Smrg
37706f2543Smrg#include "mi.h"
38706f2543Smrg#include "scrnintstr.h"
39706f2543Smrg#include "gcstruct.h"
40706f2543Smrg#include "pixmapstr.h"
41706f2543Smrg#include "windowstr.h"
42706f2543Smrg#include "propertyst.h"
43706f2543Smrg#include "mivalidate.h"
44706f2543Smrg#include "picturestr.h"
45706f2543Smrg#include "colormapst.h"
46706f2543Smrg
47706f2543Smrg#include <sys/types.h>
48706f2543Smrg#include <sys/stat.h>
49706f2543Smrg#include <fcntl.h>
50706f2543Smrg#include <string.h>
51706f2543Smrg
52706f2543Smrg#include "rootlessCommon.h"
53706f2543Smrg#include "rootlessWindow.h"
54706f2543Smrg
55706f2543Smrg/* In milliseconds */
56706f2543Smrg#ifndef ROOTLESS_REDISPLAY_DELAY
57706f2543Smrg#define ROOTLESS_REDISPLAY_DELAY 10
58706f2543Smrg#endif
59706f2543Smrg
60706f2543Smrgextern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild,
61706f2543Smrg                                  VTKind kind);
62706f2543Smrgextern Bool RootlessCreateGC(GCPtr pGC);
63706f2543Smrg
64706f2543Smrg// Initialize globals
65706f2543SmrgDevPrivateKeyRec rootlessGCPrivateKeyRec;
66706f2543SmrgDevPrivateKeyRec rootlessScreenPrivateKeyRec;
67706f2543SmrgDevPrivateKeyRec rootlessWindowPrivateKeyRec;
68706f2543SmrgDevPrivateKeyRec rootlessWindowOldPixmapPrivateKeyRec;
69706f2543Smrg
70706f2543Smrg/*
71706f2543Smrg * RootlessUpdateScreenPixmap
72706f2543Smrg *  miCreateScreenResources does not like a null framebuffer pointer,
73706f2543Smrg *  it leaves the screen pixmap with an uninitialized data pointer.
74706f2543Smrg *  Thus, rootless implementations typically set the framebuffer width
75706f2543Smrg *  to zero so that miCreateScreenResources does not allocate a screen
76706f2543Smrg *  pixmap for us. We allocate our own screen pixmap here since we need
77706f2543Smrg *  the screen pixmap to be valid (e.g. CopyArea from the root window).
78706f2543Smrg */
79706f2543Smrgvoid
80706f2543SmrgRootlessUpdateScreenPixmap(ScreenPtr pScreen)
81706f2543Smrg{
82706f2543Smrg    RootlessScreenRec *s = SCREENREC(pScreen);
83706f2543Smrg    PixmapPtr pPix;
84706f2543Smrg    unsigned int rowbytes;
85706f2543Smrg
86706f2543Smrg    pPix = (*pScreen->GetScreenPixmap)(pScreen);
87706f2543Smrg    if (pPix == NULL) {
88706f2543Smrg        pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0);
89706f2543Smrg        (*pScreen->SetScreenPixmap)(pPix);
90706f2543Smrg    }
91706f2543Smrg
92706f2543Smrg    rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth);
93706f2543Smrg
94706f2543Smrg    if (s->pixmap_data_size < rowbytes) {
95706f2543Smrg        free(s->pixmap_data);
96706f2543Smrg
97706f2543Smrg        s->pixmap_data_size = rowbytes;
98706f2543Smrg        s->pixmap_data = malloc(s->pixmap_data_size);
99706f2543Smrg        if (s->pixmap_data == NULL)
100706f2543Smrg            return;
101706f2543Smrg
102706f2543Smrg        memset(s->pixmap_data, 0xFF, s->pixmap_data_size);
103706f2543Smrg
104706f2543Smrg        pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height,
105706f2543Smrg                                    pScreen->rootDepth,
106706f2543Smrg                                    BitsPerPixel(pScreen->rootDepth),
107706f2543Smrg                                    0, s->pixmap_data);
108706f2543Smrg        /* ModifyPixmapHeader ignores zero arguments, so install rowbytes
109706f2543Smrg           by hand. */
110706f2543Smrg        pPix->devKind = 0;
111706f2543Smrg    }
112706f2543Smrg}
113706f2543Smrg
114706f2543Smrg
115706f2543Smrg/*
116706f2543Smrg * RootlessCreateScreenResources
117706f2543Smrg *  Rootless implementations typically set a null framebuffer pointer, which
118706f2543Smrg *  causes problems with miCreateScreenResources. We fix things up here.
119706f2543Smrg */
120706f2543Smrgstatic Bool
121706f2543SmrgRootlessCreateScreenResources(ScreenPtr pScreen)
122706f2543Smrg{
123706f2543Smrg    Bool ret = TRUE;
124706f2543Smrg
125706f2543Smrg    SCREEN_UNWRAP(pScreen, CreateScreenResources);
126706f2543Smrg
127706f2543Smrg    if (pScreen->CreateScreenResources != NULL)
128706f2543Smrg        ret = (*pScreen->CreateScreenResources)(pScreen);
129706f2543Smrg
130706f2543Smrg    SCREEN_WRAP(pScreen, CreateScreenResources);
131706f2543Smrg
132706f2543Smrg    if (!ret)
133706f2543Smrg        return ret;
134706f2543Smrg
135706f2543Smrg    /* Make sure we have a valid screen pixmap. */
136706f2543Smrg
137706f2543Smrg    RootlessUpdateScreenPixmap(pScreen);
138706f2543Smrg
139706f2543Smrg    return ret;
140706f2543Smrg}
141706f2543Smrg
142706f2543Smrg
143706f2543Smrgstatic Bool
144706f2543SmrgRootlessCloseScreen(int i, ScreenPtr pScreen)
145706f2543Smrg{
146706f2543Smrg    RootlessScreenRec *s;
147706f2543Smrg
148706f2543Smrg    s = SCREENREC(pScreen);
149706f2543Smrg
150706f2543Smrg    // fixme unwrap everything that was wrapped?
151706f2543Smrg    pScreen->CloseScreen = s->CloseScreen;
152706f2543Smrg
153706f2543Smrg    if (s->pixmap_data != NULL) {
154706f2543Smrg        free(s->pixmap_data);
155706f2543Smrg        s->pixmap_data = NULL;
156706f2543Smrg        s->pixmap_data_size = 0;
157706f2543Smrg    }
158706f2543Smrg
159706f2543Smrg    free(s);
160706f2543Smrg    return pScreen->CloseScreen(i, pScreen);
161706f2543Smrg}
162706f2543Smrg
163706f2543Smrg
164706f2543Smrgstatic void
165706f2543SmrgRootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
166706f2543Smrg                 unsigned int format, unsigned long planeMask, char *pdstLine)
167706f2543Smrg{
168706f2543Smrg    ScreenPtr pScreen = pDrawable->pScreen;
169706f2543Smrg    SCREEN_UNWRAP(pScreen, GetImage);
170706f2543Smrg
171706f2543Smrg    if (pDrawable->type == DRAWABLE_WINDOW) {
172706f2543Smrg        int x0, y0, x1, y1;
173706f2543Smrg        RootlessWindowRec *winRec;
174706f2543Smrg
175706f2543Smrg        // Many apps use GetImage to sync with the visible frame buffer
176706f2543Smrg        // FIXME: entire screen or just window or all screens?
177706f2543Smrg        RootlessRedisplayScreen(pScreen);
178706f2543Smrg
179706f2543Smrg        // RedisplayScreen stops drawing, so we need to start it again
180706f2543Smrg        RootlessStartDrawing((WindowPtr)pDrawable);
181706f2543Smrg
182706f2543Smrg        /* Check that we have some place to read from. */
183706f2543Smrg        winRec = WINREC(TopLevelParent((WindowPtr) pDrawable));
184706f2543Smrg        if (winRec == NULL)
185706f2543Smrg            goto out;
186706f2543Smrg
187706f2543Smrg        /* Clip to top-level window bounds. */
188706f2543Smrg        /* FIXME: fbGetImage uses the width parameter to calculate the
189706f2543Smrg           stride of the destination pixmap. If w is clipped, the data
190706f2543Smrg           returned will be garbage, although we will not crash. */
191706f2543Smrg
192706f2543Smrg        x0 = pDrawable->x + sx;
193706f2543Smrg        y0 = pDrawable->y + sy;
194706f2543Smrg        x1 = x0 + w;
195706f2543Smrg        y1 = y0 + h;
196706f2543Smrg
197706f2543Smrg        x0 = max (x0, winRec->x);
198706f2543Smrg        y0 = max (y0, winRec->y);
199706f2543Smrg        x1 = min (x1, winRec->x + winRec->width);
200706f2543Smrg        y1 = min (y1, winRec->y + winRec->height);
201706f2543Smrg
202706f2543Smrg        sx = x0 - pDrawable->x;
203706f2543Smrg        sy = y0 - pDrawable->y;
204706f2543Smrg        w = x1 - x0;
205706f2543Smrg        h = y1 - y0;
206706f2543Smrg
207706f2543Smrg        if (w <= 0 || h <= 0)
208706f2543Smrg            goto out;
209706f2543Smrg    }
210706f2543Smrg
211706f2543Smrg    pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
212706f2543Smrg
213706f2543Smrgout:
214706f2543Smrg    SCREEN_WRAP(pScreen, GetImage);
215706f2543Smrg}
216706f2543Smrg
217706f2543Smrg
218706f2543Smrg/*
219706f2543Smrg * RootlessSourceValidate
220706f2543Smrg *  CopyArea and CopyPlane use a GC tied to the destination drawable.
221706f2543Smrg *  StartDrawing/StopDrawing wrappers won't be called if source is
222706f2543Smrg *  a visible window but the destination isn't. So, we call StartDrawing
223706f2543Smrg *  here and leave StopDrawing for the block handler.
224706f2543Smrg */
225706f2543Smrgstatic void
226706f2543SmrgRootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h,
227706f2543Smrg                       unsigned int subWindowMode)
228706f2543Smrg{
229706f2543Smrg    SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate);
230706f2543Smrg    if (pDrawable->type == DRAWABLE_WINDOW) {
231706f2543Smrg        WindowPtr pWin = (WindowPtr)pDrawable;
232706f2543Smrg        RootlessStartDrawing(pWin);
233706f2543Smrg    }
234706f2543Smrg    if (pDrawable->pScreen->SourceValidate) {
235706f2543Smrg        pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h, subWindowMode);
236706f2543Smrg    }
237706f2543Smrg    SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
238706f2543Smrg}
239706f2543Smrg
240706f2543Smrgstatic void
241706f2543SmrgRootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
242706f2543Smrg                  INT16 xSrc, INT16 ySrc, INT16  xMask, INT16  yMask,
243706f2543Smrg                  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
244706f2543Smrg{
245706f2543Smrg    ScreenPtr pScreen = pDst->pDrawable->pScreen;
246706f2543Smrg    PictureScreenPtr ps = GetPictureScreen(pScreen);
247706f2543Smrg    WindowPtr srcWin, dstWin, maskWin = NULL;
248706f2543Smrg
249706f2543Smrg    if (pMask) {                        // pMask can be NULL
250706f2543Smrg        maskWin = (pMask->pDrawable && pMask->pDrawable->type == DRAWABLE_WINDOW) ?
251706f2543Smrg                  (WindowPtr)pMask->pDrawable : NULL;
252706f2543Smrg    }
253706f2543Smrg    srcWin  = (pSrc->pDrawable && pSrc->pDrawable->type  == DRAWABLE_WINDOW) ?
254706f2543Smrg              (WindowPtr)pSrc->pDrawable  :  NULL;
255706f2543Smrg    dstWin  = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
256706f2543Smrg              (WindowPtr)pDst->pDrawable  :  NULL;
257706f2543Smrg
258706f2543Smrg    // SCREEN_UNWRAP(ps, Composite);
259706f2543Smrg    ps->Composite = SCREENREC(pScreen)->Composite;
260706f2543Smrg
261706f2543Smrg    if (srcWin  && IsFramedWindow(srcWin))
262706f2543Smrg        RootlessStartDrawing(srcWin);
263706f2543Smrg    if (maskWin && IsFramedWindow(maskWin))
264706f2543Smrg        RootlessStartDrawing(maskWin);
265706f2543Smrg    if (dstWin  && IsFramedWindow(dstWin))
266706f2543Smrg        RootlessStartDrawing(dstWin);
267706f2543Smrg
268706f2543Smrg    ps->Composite(op, pSrc, pMask, pDst,
269706f2543Smrg                  xSrc, ySrc, xMask, yMask,
270706f2543Smrg                  xDst, yDst, width, height);
271706f2543Smrg
272706f2543Smrg    if (dstWin  && IsFramedWindow(dstWin)) {
273706f2543Smrg        RootlessDamageRect(dstWin, xDst, yDst, width, height);
274706f2543Smrg    }
275706f2543Smrg
276706f2543Smrg    ps->Composite = RootlessComposite;
277706f2543Smrg    // SCREEN_WRAP(ps, Composite);
278706f2543Smrg}
279706f2543Smrg
280706f2543Smrg
281706f2543Smrgstatic void
282706f2543SmrgRootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
283706f2543Smrg               PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
284706f2543Smrg               int nlist, GlyphListPtr list, GlyphPtr *glyphs)
285706f2543Smrg{
286706f2543Smrg    ScreenPtr pScreen = pDst->pDrawable->pScreen;
287706f2543Smrg    PictureScreenPtr ps = GetPictureScreen(pScreen);
288706f2543Smrg    int x, y;
289706f2543Smrg    int n;
290706f2543Smrg    GlyphPtr glyph;
291706f2543Smrg    WindowPtr srcWin, dstWin;
292706f2543Smrg
293706f2543Smrg    srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
294706f2543Smrg             (WindowPtr)pSrc->pDrawable  :  NULL;
295706f2543Smrg    dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
296706f2543Smrg             (WindowPtr)pDst->pDrawable  :  NULL;
297706f2543Smrg
298706f2543Smrg    if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin);
299706f2543Smrg    if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin);
300706f2543Smrg
301706f2543Smrg    //SCREEN_UNWRAP(ps, Glyphs);
302706f2543Smrg    ps->Glyphs = SCREENREC(pScreen)->Glyphs;
303706f2543Smrg    ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
304706f2543Smrg    ps->Glyphs = RootlessGlyphs;
305706f2543Smrg    //SCREEN_WRAP(ps, Glyphs);
306706f2543Smrg
307706f2543Smrg    if (dstWin && IsFramedWindow(dstWin)) {
308706f2543Smrg        x = xSrc;
309706f2543Smrg        y = ySrc;
310706f2543Smrg
311706f2543Smrg        while (nlist--) {
312706f2543Smrg            x += list->xOff;
313706f2543Smrg            y += list->yOff;
314706f2543Smrg            n = list->len;
315706f2543Smrg
316706f2543Smrg            /* Calling DamageRect for the bounding box of each glyph is
317706f2543Smrg               inefficient. So compute the union of all glyphs in a list
318706f2543Smrg               and damage that. */
319706f2543Smrg
320706f2543Smrg            if (n > 0) {
321706f2543Smrg                BoxRec box;
322706f2543Smrg
323706f2543Smrg                glyph = *glyphs++;
324706f2543Smrg
325706f2543Smrg                box.x1 = x - glyph->info.x;
326706f2543Smrg                box.y1 = y - glyph->info.y;
327706f2543Smrg                box.x2 = box.x1 + glyph->info.width;
328706f2543Smrg                box.y2 = box.y1 + glyph->info.height;
329706f2543Smrg
330706f2543Smrg                x += glyph->info.xOff;
331706f2543Smrg                y += glyph->info.yOff;
332706f2543Smrg
333706f2543Smrg                while (--n > 0) {
334706f2543Smrg                    short x1, y1, x2, y2;
335706f2543Smrg
336706f2543Smrg                    glyph = *glyphs++;
337706f2543Smrg
338706f2543Smrg                    x1 = x - glyph->info.x;
339706f2543Smrg                    y1 = y - glyph->info.y;
340706f2543Smrg                    x2 = x1 + glyph->info.width;
341706f2543Smrg                    y2 = y1 + glyph->info.height;
342706f2543Smrg
343706f2543Smrg                    box.x1 = max (box.x1, x1);
344706f2543Smrg                    box.y1 = max (box.y1, y1);
345706f2543Smrg                    box.x2 = max (box.x2, x2);
346706f2543Smrg                    box.y2 = max (box.y2, y2);
347706f2543Smrg
348706f2543Smrg                    x += glyph->info.xOff;
349706f2543Smrg                    y += glyph->info.yOff;
350706f2543Smrg                }
351706f2543Smrg
352706f2543Smrg                RootlessDamageBox(dstWin, &box);
353706f2543Smrg            }
354706f2543Smrg            list++;
355706f2543Smrg        }
356706f2543Smrg    }
357706f2543Smrg}
358706f2543Smrg
359706f2543Smrg
360706f2543Smrg/*
361706f2543Smrg * RootlessValidateTree
362706f2543Smrg *  ValidateTree is modified in two ways:
363706f2543Smrg *   - top-level windows don't clip each other
364706f2543Smrg *   - windows aren't clipped against root.
365706f2543Smrg *  These only matter when validating from the root.
366706f2543Smrg */
367706f2543Smrgstatic int
368706f2543SmrgRootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
369706f2543Smrg{
370706f2543Smrg    int result;
371706f2543Smrg    RegionRec saveRoot;
372706f2543Smrg    ScreenPtr pScreen = pParent->drawable.pScreen;
373706f2543Smrg
374706f2543Smrg    SCREEN_UNWRAP(pScreen, ValidateTree);
375706f2543Smrg    RL_DEBUG_MSG("VALIDATETREE start ");
376706f2543Smrg
377706f2543Smrg    // Use our custom version to validate from root
378706f2543Smrg    if (IsRoot(pParent)) {
379706f2543Smrg        RL_DEBUG_MSG("custom ");
380706f2543Smrg        result = RootlessMiValidateTree(pParent, pChild, kind);
381706f2543Smrg    } else {
382706f2543Smrg        HUGE_ROOT(pParent);
383706f2543Smrg        result = pScreen->ValidateTree(pParent, pChild, kind);
384706f2543Smrg        NORMAL_ROOT(pParent);
385706f2543Smrg    }
386706f2543Smrg
387706f2543Smrg    SCREEN_WRAP(pScreen, ValidateTree);
388706f2543Smrg    RL_DEBUG_MSG("VALIDATETREE end\n");
389706f2543Smrg
390706f2543Smrg    return result;
391706f2543Smrg}
392706f2543Smrg
393706f2543Smrg
394706f2543Smrg/*
395706f2543Smrg * RootlessMarkOverlappedWindows
396706f2543Smrg *  MarkOverlappedWindows is modified to ignore overlapping
397706f2543Smrg *  top-level windows.
398706f2543Smrg */
399706f2543Smrgstatic Bool
400706f2543SmrgRootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
401706f2543Smrg                              WindowPtr *ppLayerWin)
402706f2543Smrg{
403706f2543Smrg    RegionRec saveRoot;
404706f2543Smrg    Bool result;
405706f2543Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
406706f2543Smrg    SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
407706f2543Smrg    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
408706f2543Smrg
409706f2543Smrg    HUGE_ROOT(pWin);
410706f2543Smrg    if (IsRoot(pWin)) {
411706f2543Smrg        // root - mark nothing
412706f2543Smrg        RL_DEBUG_MSG("is root not marking ");
413706f2543Smrg        result = FALSE;
414706f2543Smrg    }
415706f2543Smrg    else if (! IsTopLevel(pWin)) {
416706f2543Smrg        // not top-level window - mark normally
417706f2543Smrg        result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
418706f2543Smrg    }
419706f2543Smrg    else {
420706f2543Smrg        //top-level window - mark children ONLY - NO overlaps with sibs (?)
421706f2543Smrg        // This code copied from miMarkOverlappedWindows()
422706f2543Smrg
423706f2543Smrg        register WindowPtr pChild;
424706f2543Smrg        Bool anyMarked = FALSE;
425706f2543Smrg        MarkWindowProcPtr MarkWindow = pScreen->MarkWindow;
426706f2543Smrg
427706f2543Smrg        RL_DEBUG_MSG("is top level! ");
428706f2543Smrg        /* single layered systems are easy */
429706f2543Smrg        if (ppLayerWin) *ppLayerWin = pWin;
430706f2543Smrg
431706f2543Smrg        if (pWin == pFirst) {
432706f2543Smrg            /* Blindly mark pWin and all of its inferiors.   This is a slight
433706f2543Smrg             * overkill if there are mapped windows that outside pWin's border,
434706f2543Smrg             * but it's better than wasting time on RectIn checks.
435706f2543Smrg             */
436706f2543Smrg            pChild = pWin;
437706f2543Smrg            while (1) {
438706f2543Smrg                if (pChild->viewable) {
439706f2543Smrg                    if (RegionBroken(&pChild->winSize))
440706f2543Smrg                        SetWinSize (pChild);
441706f2543Smrg                    if (RegionBroken(&pChild->borderSize))
442706f2543Smrg                        SetBorderSize (pChild);
443706f2543Smrg                    (* MarkWindow)(pChild);
444706f2543Smrg                    if (pChild->firstChild) {
445706f2543Smrg                        pChild = pChild->firstChild;
446706f2543Smrg                        continue;
447706f2543Smrg                    }
448706f2543Smrg                }
449706f2543Smrg                while (!pChild->nextSib && (pChild != pWin))
450706f2543Smrg                    pChild = pChild->parent;
451706f2543Smrg                if (pChild == pWin)
452706f2543Smrg                    break;
453706f2543Smrg                pChild = pChild->nextSib;
454706f2543Smrg            }
455706f2543Smrg            anyMarked = TRUE;
456706f2543Smrg            pFirst = pFirst->nextSib;
457706f2543Smrg        }
458706f2543Smrg        if (anyMarked)
459706f2543Smrg            (* MarkWindow)(pWin->parent);
460706f2543Smrg        result = anyMarked;
461706f2543Smrg    }
462706f2543Smrg    NORMAL_ROOT(pWin);
463706f2543Smrg    SCREEN_WRAP(pScreen, MarkOverlappedWindows);
464706f2543Smrg    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
465706f2543Smrg
466706f2543Smrg    return result;
467706f2543Smrg}
468706f2543Smrg
469706f2543Smrgstatic void expose_1 (WindowPtr pWin) {
470706f2543Smrg    WindowPtr pChild;
471706f2543Smrg
472706f2543Smrg    if (!pWin->realized)
473706f2543Smrg        return;
474706f2543Smrg
475706f2543Smrg    miPaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND);
476706f2543Smrg
477706f2543Smrg    /* FIXME: comments in windowstr.h indicate that borderClip doesn't
478706f2543Smrg     include subwindow visibility. But I'm not so sure.. so we may
479706f2543Smrg     be exposing too much.. */
480706f2543Smrg
481706f2543Smrg    miSendExposures (pWin, &pWin->borderClip,
482706f2543Smrg                     pWin->drawable.x, pWin->drawable.y);
483706f2543Smrg
484706f2543Smrg    for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib)
485706f2543Smrg        expose_1 (pChild);
486706f2543Smrg}
487706f2543Smrg
488706f2543Smrgvoid
489706f2543SmrgRootlessScreenExpose (ScreenPtr pScreen)
490706f2543Smrg{
491706f2543Smrg    expose_1 (pScreen->root);
492706f2543Smrg}
493706f2543Smrg
494706f2543Smrg
495706f2543SmrgColormapPtr
496706f2543SmrgRootlessGetColormap (ScreenPtr pScreen)
497706f2543Smrg{
498706f2543Smrg  RootlessScreenRec *s = SCREENREC (pScreen);
499706f2543Smrg
500706f2543Smrg  return s->colormap;
501706f2543Smrg}
502706f2543Smrg
503706f2543Smrgstatic void
504706f2543SmrgRootlessInstallColormap (ColormapPtr pMap)
505706f2543Smrg{
506706f2543Smrg  ScreenPtr pScreen = pMap->pScreen;
507706f2543Smrg  RootlessScreenRec *s = SCREENREC (pScreen);
508706f2543Smrg
509706f2543Smrg  SCREEN_UNWRAP(pScreen, InstallColormap);
510706f2543Smrg
511706f2543Smrg  if (s->colormap != pMap) {
512706f2543Smrg    s->colormap = pMap;
513706f2543Smrg    s->colormap_changed = TRUE;
514706f2543Smrg    RootlessQueueRedisplay (pScreen);
515706f2543Smrg  }
516706f2543Smrg
517706f2543Smrg  pScreen->InstallColormap (pMap);
518706f2543Smrg
519706f2543Smrg  SCREEN_WRAP (pScreen, InstallColormap);
520706f2543Smrg}
521706f2543Smrg
522706f2543Smrgstatic void
523706f2543SmrgRootlessUninstallColormap (ColormapPtr pMap)
524706f2543Smrg{
525706f2543Smrg  ScreenPtr pScreen = pMap->pScreen;
526706f2543Smrg  RootlessScreenRec *s = SCREENREC (pScreen);
527706f2543Smrg
528706f2543Smrg  SCREEN_UNWRAP(pScreen, UninstallColormap);
529706f2543Smrg
530706f2543Smrg  if (s->colormap == pMap)
531706f2543Smrg    s->colormap = NULL;
532706f2543Smrg
533706f2543Smrg  pScreen->UninstallColormap (pMap);
534706f2543Smrg
535706f2543Smrg  SCREEN_WRAP(pScreen, UninstallColormap);
536706f2543Smrg}
537706f2543Smrg
538706f2543Smrgstatic void
539706f2543SmrgRootlessStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef)
540706f2543Smrg{
541706f2543Smrg  ScreenPtr pScreen = pMap->pScreen;
542706f2543Smrg  RootlessScreenRec *s = SCREENREC (pScreen);
543706f2543Smrg
544706f2543Smrg  SCREEN_UNWRAP(pScreen, StoreColors);
545706f2543Smrg
546706f2543Smrg  if (s->colormap == pMap && ndef > 0) {
547706f2543Smrg    s->colormap_changed = TRUE;
548706f2543Smrg    RootlessQueueRedisplay (pScreen);
549706f2543Smrg  }
550706f2543Smrg
551706f2543Smrg  pScreen->StoreColors (pMap, ndef, pdef);
552706f2543Smrg
553706f2543Smrg  SCREEN_WRAP(pScreen, StoreColors);
554706f2543Smrg}
555706f2543Smrg
556706f2543Smrg
557706f2543Smrgstatic CARD32
558706f2543SmrgRootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg)
559706f2543Smrg{
560706f2543Smrg    RootlessScreenRec *screenRec = arg;
561706f2543Smrg
562706f2543Smrg    if (!screenRec->redisplay_queued) {
563706f2543Smrg        /* No update needed. Stop the timer. */
564706f2543Smrg
565706f2543Smrg        screenRec->redisplay_timer_set = FALSE;
566706f2543Smrg        return 0;
567706f2543Smrg    }
568706f2543Smrg
569706f2543Smrg    screenRec->redisplay_queued = FALSE;
570706f2543Smrg
571706f2543Smrg    /* Mark that we should redisplay before waiting for I/O next time */
572706f2543Smrg    screenRec->redisplay_expired = TRUE;
573706f2543Smrg
574706f2543Smrg    /* Reinstall the timer immediately, so we get as close to our
575706f2543Smrg       redisplay interval as possible. */
576706f2543Smrg
577706f2543Smrg    return ROOTLESS_REDISPLAY_DELAY;
578706f2543Smrg}
579706f2543Smrg
580706f2543Smrg
581706f2543Smrg/*
582706f2543Smrg * RootlessQueueRedisplay
583706f2543Smrg *  Queue a redisplay after a timer delay to ensure we do not redisplay
584706f2543Smrg *  too frequently.
585706f2543Smrg */
586706f2543Smrgvoid
587706f2543SmrgRootlessQueueRedisplay(ScreenPtr pScreen)
588706f2543Smrg{
589706f2543Smrg    RootlessScreenRec *screenRec = SCREENREC(pScreen);
590706f2543Smrg
591706f2543Smrg    screenRec->redisplay_queued = TRUE;
592706f2543Smrg
593706f2543Smrg    if (screenRec->redisplay_timer_set)
594706f2543Smrg        return;
595706f2543Smrg
596706f2543Smrg    screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer,
597706f2543Smrg                                          0, ROOTLESS_REDISPLAY_DELAY,
598706f2543Smrg                                          RootlessRedisplayCallback,
599706f2543Smrg                                          screenRec);
600706f2543Smrg    screenRec->redisplay_timer_set = TRUE;
601706f2543Smrg}
602706f2543Smrg
603706f2543Smrg
604706f2543Smrg/*
605706f2543Smrg * RootlessBlockHandler
606706f2543Smrg *  If the redisplay timer has expired, flush drawing before blocking
607706f2543Smrg *  on select().
608706f2543Smrg */
609706f2543Smrgstatic void
610706f2543SmrgRootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask)
611706f2543Smrg{
612706f2543Smrg    ScreenPtr pScreen = pbdata;
613706f2543Smrg    RootlessScreenRec *screenRec = SCREENREC(pScreen);
614706f2543Smrg
615706f2543Smrg    if (screenRec->redisplay_expired) {
616706f2543Smrg        screenRec->redisplay_expired = FALSE;
617706f2543Smrg
618706f2543Smrg        RootlessRedisplayScreen(pScreen);
619706f2543Smrg    }
620706f2543Smrg}
621706f2543Smrg
622706f2543Smrg
623706f2543Smrgstatic void
624706f2543SmrgRootlessWakeupHandler(pointer data, int i, pointer LastSelectMask)
625706f2543Smrg{
626706f2543Smrg    // nothing here
627706f2543Smrg}
628706f2543Smrg
629706f2543Smrg
630706f2543Smrgstatic Bool
631706f2543SmrgRootlessAllocatePrivates(ScreenPtr pScreen)
632706f2543Smrg{
633706f2543Smrg    RootlessScreenRec *s;
634706f2543Smrg
635706f2543Smrg    if (!dixRegisterPrivateKey(&rootlessGCPrivateKeyRec, PRIVATE_GC, sizeof(RootlessGCRec)))
636706f2543Smrg        return FALSE;
637706f2543Smrg    if (!dixRegisterPrivateKey(&rootlessScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
638706f2543Smrg        return FALSE;
639706f2543Smrg    if (!dixRegisterPrivateKey(&rootlessWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
640706f2543Smrg        return FALSE;
641706f2543Smrg    if (!dixRegisterPrivateKey(&rootlessWindowOldPixmapPrivateKeyRec, PRIVATE_WINDOW, 0))
642706f2543Smrg        return FALSE;
643706f2543Smrg
644706f2543Smrg    s = malloc(sizeof(RootlessScreenRec));
645706f2543Smrg    if (! s) return FALSE;
646706f2543Smrg    SETSCREENREC(pScreen, s);
647706f2543Smrg
648706f2543Smrg    s->pixmap_data = NULL;
649706f2543Smrg    s->pixmap_data_size = 0;
650706f2543Smrg
651706f2543Smrg    s->redisplay_timer = NULL;
652706f2543Smrg    s->redisplay_timer_set = FALSE;
653706f2543Smrg
654706f2543Smrg    return TRUE;
655706f2543Smrg}
656706f2543Smrg
657706f2543Smrg
658706f2543Smrgstatic void
659706f2543SmrgRootlessWrap(ScreenPtr pScreen)
660706f2543Smrg{
661706f2543Smrg    RootlessScreenRec *s = SCREENREC(pScreen);
662706f2543Smrg
663706f2543Smrg#define WRAP(a) \
664706f2543Smrg    if (pScreen->a) { \
665706f2543Smrg        s->a = pScreen->a; \
666706f2543Smrg    } else { \
667706f2543Smrg        RL_DEBUG_MSG("null screen fn " #a "\n"); \
668706f2543Smrg        s->a = NULL; \
669706f2543Smrg    } \
670706f2543Smrg    pScreen->a = Rootless##a
671706f2543Smrg
672706f2543Smrg    WRAP(CreateScreenResources);
673706f2543Smrg    WRAP(CloseScreen);
674706f2543Smrg    WRAP(CreateGC);
675706f2543Smrg    WRAP(CopyWindow);
676706f2543Smrg    WRAP(GetImage);
677706f2543Smrg    WRAP(SourceValidate);
678706f2543Smrg    WRAP(CreateWindow);
679706f2543Smrg    WRAP(DestroyWindow);
680706f2543Smrg    WRAP(RealizeWindow);
681706f2543Smrg    WRAP(UnrealizeWindow);
682706f2543Smrg    WRAP(MoveWindow);
683706f2543Smrg    WRAP(PositionWindow);
684706f2543Smrg    WRAP(ResizeWindow);
685706f2543Smrg    WRAP(RestackWindow);
686706f2543Smrg    WRAP(ReparentWindow);
687706f2543Smrg    WRAP(ChangeBorderWidth);
688706f2543Smrg    WRAP(MarkOverlappedWindows);
689706f2543Smrg    WRAP(ValidateTree);
690706f2543Smrg    WRAP(ChangeWindowAttributes);
691706f2543Smrg    WRAP(InstallColormap);
692706f2543Smrg    WRAP(UninstallColormap);
693706f2543Smrg    WRAP(StoreColors);
694706f2543Smrg
695706f2543Smrg    WRAP(SetShape);
696706f2543Smrg
697706f2543Smrg    {
698706f2543Smrg        // Composite and Glyphs don't use normal screen wrapping
699706f2543Smrg        PictureScreenPtr ps = GetPictureScreen(pScreen);
700706f2543Smrg        s->Composite = ps->Composite;
701706f2543Smrg        ps->Composite = RootlessComposite;
702706f2543Smrg        s->Glyphs = ps->Glyphs;
703706f2543Smrg        ps->Glyphs = RootlessGlyphs;
704706f2543Smrg    }
705706f2543Smrg
706706f2543Smrg    // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
707706f2543Smrg
708706f2543Smrg#undef WRAP
709706f2543Smrg}
710706f2543Smrg
711706f2543Smrg
712706f2543Smrg/*
713706f2543Smrg * RootlessInit
714706f2543Smrg *  Called by the rootless implementation to initialize the rootless layer.
715706f2543Smrg *  Rootless wraps lots of stuff and needs a bunch of devPrivates.
716706f2543Smrg */
717706f2543SmrgBool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
718706f2543Smrg{
719706f2543Smrg    RootlessScreenRec *s;
720706f2543Smrg
721706f2543Smrg    if (!RootlessAllocatePrivates(pScreen))
722706f2543Smrg        return FALSE;
723706f2543Smrg
724706f2543Smrg    s = SCREENREC(pScreen);
725706f2543Smrg
726706f2543Smrg    s->imp = procs;
727706f2543Smrg    s->colormap = NULL;
728706f2543Smrg    s->redisplay_expired = FALSE;
729706f2543Smrg
730706f2543Smrg    RootlessWrap(pScreen);
731706f2543Smrg
732706f2543Smrg    if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler,
733706f2543Smrg                                        RootlessWakeupHandler,
734706f2543Smrg                                        (pointer) pScreen))
735706f2543Smrg    {
736706f2543Smrg        return FALSE;
737706f2543Smrg    }
738706f2543Smrg
739706f2543Smrg    return TRUE;
740706f2543Smrg}
741706f2543Smrg
742706f2543Smrgvoid RootlessUpdateRooted (Bool state) {
743706f2543Smrg    int i;
744706f2543Smrg
745706f2543Smrg    if (!state)
746706f2543Smrg    {
747706f2543Smrg        for (i = 0; i < screenInfo.numScreens; i++)
748706f2543Smrg            RootlessDisableRoot (screenInfo.screens[i]);
749706f2543Smrg    }
750706f2543Smrg    else
751706f2543Smrg    {
752706f2543Smrg        for (i = 0; i < screenInfo.numScreens; i++)
753706f2543Smrg            RootlessEnableRoot (screenInfo.screens[i]);
754706f2543Smrg    }
755706f2543Smrg}
756