rootlessScreen.c revision 1b5d61b8
1/*
2 * Screen routines for generic rootless X server
3 */
4/*
5 * Copyright (c) 2001 Greg Parker. All Rights Reserved.
6 * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
7 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the sale,
29 * use or other dealings in this Software without prior written authorization.
30 */
31
32#ifdef HAVE_DIX_CONFIG_H
33#include <dix-config.h>
34#endif
35
36#include "mi.h"
37#include "scrnintstr.h"
38#include "gcstruct.h"
39#include "pixmapstr.h"
40#include "windowstr.h"
41#include "propertyst.h"
42#include "mivalidate.h"
43#include "picturestr.h"
44#include "colormapst.h"
45
46#include <sys/types.h>
47#include <sys/stat.h>
48#include <fcntl.h>
49#include <string.h>
50
51#include "rootlessCommon.h"
52#include "rootlessWindow.h"
53
54/* In milliseconds */
55#ifndef ROOTLESS_REDISPLAY_DELAY
56#define ROOTLESS_REDISPLAY_DELAY 10
57#endif
58
59extern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild,
60                                  VTKind kind);
61extern Bool RootlessCreateGC(GCPtr pGC);
62
63// Initialize globals
64DevPrivateKeyRec rootlessGCPrivateKeyRec;
65DevPrivateKeyRec rootlessScreenPrivateKeyRec;
66DevPrivateKeyRec rootlessWindowPrivateKeyRec;
67DevPrivateKeyRec rootlessWindowOldPixmapPrivateKeyRec;
68
69/*
70 * RootlessUpdateScreenPixmap
71 *  miCreateScreenResources does not like a null framebuffer pointer,
72 *  it leaves the screen pixmap with an uninitialized data pointer.
73 *  Thus, rootless implementations typically set the framebuffer width
74 *  to zero so that miCreateScreenResources does not allocate a screen
75 *  pixmap for us. We allocate our own screen pixmap here since we need
76 *  the screen pixmap to be valid (e.g. CopyArea from the root window).
77 */
78void
79RootlessUpdateScreenPixmap(ScreenPtr pScreen)
80{
81    RootlessScreenRec *s = SCREENREC(pScreen);
82    PixmapPtr pPix;
83    unsigned int rowbytes;
84
85    pPix = (*pScreen->GetScreenPixmap) (pScreen);
86    if (pPix == NULL) {
87        pPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
88        (*pScreen->SetScreenPixmap) (pPix);
89    }
90
91    rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth);
92
93    if (s->pixmap_data_size < rowbytes) {
94        free(s->pixmap_data);
95
96        s->pixmap_data_size = rowbytes;
97        s->pixmap_data = malloc(s->pixmap_data_size);
98        if (s->pixmap_data == NULL)
99            return;
100
101        memset(s->pixmap_data, 0xFF, s->pixmap_data_size);
102
103        pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height,
104                                    pScreen->rootDepth,
105                                    BitsPerPixel(pScreen->rootDepth),
106                                    0, s->pixmap_data);
107        /* ModifyPixmapHeader ignores zero arguments, so install rowbytes
108           by hand. */
109        pPix->devKind = 0;
110    }
111}
112
113/*
114 * RootlessCreateScreenResources
115 *  Rootless implementations typically set a null framebuffer pointer, which
116 *  causes problems with miCreateScreenResources. We fix things up here.
117 */
118static Bool
119RootlessCreateScreenResources(ScreenPtr pScreen)
120{
121    Bool ret = TRUE;
122
123    SCREEN_UNWRAP(pScreen, CreateScreenResources);
124
125    if (pScreen->CreateScreenResources != NULL)
126        ret = (*pScreen->CreateScreenResources) (pScreen);
127
128    SCREEN_WRAP(pScreen, CreateScreenResources);
129
130    if (!ret)
131        return ret;
132
133    /* Make sure we have a valid screen pixmap. */
134
135    RootlessUpdateScreenPixmap(pScreen);
136
137    return ret;
138}
139
140static Bool
141RootlessCloseScreen(ScreenPtr pScreen)
142{
143    RootlessScreenRec *s;
144
145    s = SCREENREC(pScreen);
146
147    // fixme unwrap everything that was wrapped?
148    pScreen->CloseScreen = s->CloseScreen;
149
150    if (s->pixmap_data != NULL) {
151        free(s->pixmap_data);
152        s->pixmap_data = NULL;
153        s->pixmap_data_size = 0;
154    }
155
156    free(s);
157    return pScreen->CloseScreen(pScreen);
158}
159
160static void
161RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
162                 unsigned int format, unsigned long planeMask, char *pdstLine)
163{
164    ScreenPtr pScreen = pDrawable->pScreen;
165
166    SCREEN_UNWRAP(pScreen, GetImage);
167
168    if (pDrawable->type == DRAWABLE_WINDOW) {
169        int x0, y0, x1, y1;
170        RootlessWindowRec *winRec;
171
172        // Many apps use GetImage to sync with the visible frame buffer
173        // FIXME: entire screen or just window or all screens?
174        RootlessRedisplayScreen(pScreen);
175
176        // RedisplayScreen stops drawing, so we need to start it again
177        RootlessStartDrawing((WindowPtr) pDrawable);
178
179        /* Check that we have some place to read from. */
180        winRec = WINREC(TopLevelParent((WindowPtr) pDrawable));
181        if (winRec == NULL)
182            goto out;
183
184        /* Clip to top-level window bounds. */
185        /* FIXME: fbGetImage uses the width parameter to calculate the
186           stride of the destination pixmap. If w is clipped, the data
187           returned will be garbage, although we will not crash. */
188
189        x0 = pDrawable->x + sx;
190        y0 = pDrawable->y + sy;
191        x1 = x0 + w;
192        y1 = y0 + h;
193
194        x0 = max(x0, winRec->x);
195        y0 = max(y0, winRec->y);
196        x1 = min(x1, winRec->x + winRec->width);
197        y1 = min(y1, winRec->y + winRec->height);
198
199        sx = x0 - pDrawable->x;
200        sy = y0 - pDrawable->y;
201        w = x1 - x0;
202        h = y1 - y0;
203
204        if (w <= 0 || h <= 0)
205            goto out;
206    }
207
208    pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
209
210 out:
211    SCREEN_WRAP(pScreen, GetImage);
212}
213
214/*
215 * RootlessSourceValidate
216 *  CopyArea and CopyPlane use a GC tied to the destination drawable.
217 *  StartDrawing/StopDrawing wrappers won't be called if source is
218 *  a visible window but the destination isn't. So, we call StartDrawing
219 *  here and leave StopDrawing for the block handler.
220 */
221static void
222RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h,
223                       unsigned int subWindowMode)
224{
225    SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate);
226    if (pDrawable->type == DRAWABLE_WINDOW) {
227        WindowPtr pWin = (WindowPtr) pDrawable;
228
229        RootlessStartDrawing(pWin);
230    }
231    if (pDrawable->pScreen->SourceValidate) {
232        pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h,
233                                           subWindowMode);
234    }
235    SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
236}
237
238static void
239RootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
240                  INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask,
241                  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
242{
243    ScreenPtr pScreen = pDst->pDrawable->pScreen;
244    PictureScreenPtr ps = GetPictureScreen(pScreen);
245    WindowPtr srcWin, dstWin, maskWin = NULL;
246
247    if (pMask) {                // pMask can be NULL
248        maskWin = (pMask->pDrawable &&
249                   pMask->pDrawable->type ==
250                   DRAWABLE_WINDOW) ? (WindowPtr) pMask->pDrawable : NULL;
251    }
252    srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
253        (WindowPtr) pSrc->pDrawable : NULL;
254    dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
255        (WindowPtr) pDst->pDrawable : NULL;
256
257    // SCREEN_UNWRAP(ps, Composite);
258    ps->Composite = SCREENREC(pScreen)->Composite;
259
260    if (srcWin && IsFramedWindow(srcWin))
261        RootlessStartDrawing(srcWin);
262    if (maskWin && IsFramedWindow(maskWin))
263        RootlessStartDrawing(maskWin);
264    if (dstWin && IsFramedWindow(dstWin))
265        RootlessStartDrawing(dstWin);
266
267    ps->Composite(op, pSrc, pMask, pDst,
268                  xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
269
270    if (dstWin && IsFramedWindow(dstWin)) {
271        RootlessDamageRect(dstWin, xDst, yDst, width, height);
272    }
273
274    ps->Composite = RootlessComposite;
275    // SCREEN_WRAP(ps, Composite);
276}
277
278static void
279RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
280               PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
281               int nlist, GlyphListPtr list, GlyphPtr * glyphs)
282{
283    ScreenPtr pScreen = pDst->pDrawable->pScreen;
284    PictureScreenPtr ps = GetPictureScreen(pScreen);
285    int x, y;
286    int n;
287    GlyphPtr glyph;
288    WindowPtr srcWin, dstWin;
289
290    srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
291        (WindowPtr) pSrc->pDrawable : NULL;
292    dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
293        (WindowPtr) pDst->pDrawable : NULL;
294
295    if (srcWin && IsFramedWindow(srcWin))
296        RootlessStartDrawing(srcWin);
297    if (dstWin && IsFramedWindow(dstWin))
298        RootlessStartDrawing(dstWin);
299
300    //SCREEN_UNWRAP(ps, Glyphs);
301    ps->Glyphs = SCREENREC(pScreen)->Glyphs;
302    ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
303    ps->Glyphs = RootlessGlyphs;
304    //SCREEN_WRAP(ps, Glyphs);
305
306    if (dstWin && IsFramedWindow(dstWin)) {
307        x = xSrc;
308        y = ySrc;
309
310        while (nlist--) {
311            x += list->xOff;
312            y += list->yOff;
313            n = list->len;
314
315            /* Calling DamageRect for the bounding box of each glyph is
316               inefficient. So compute the union of all glyphs in a list
317               and damage that. */
318
319            if (n > 0) {
320                BoxRec box;
321
322                glyph = *glyphs++;
323
324                box.x1 = x - glyph->info.x;
325                box.y1 = y - glyph->info.y;
326                box.x2 = box.x1 + glyph->info.width;
327                box.y2 = box.y1 + glyph->info.height;
328
329                x += glyph->info.xOff;
330                y += glyph->info.yOff;
331
332                while (--n > 0) {
333                    short x1, y1, x2, y2;
334
335                    glyph = *glyphs++;
336
337                    x1 = x - glyph->info.x;
338                    y1 = y - glyph->info.y;
339                    x2 = x1 + glyph->info.width;
340                    y2 = y1 + glyph->info.height;
341
342                    box.x1 = max(box.x1, x1);
343                    box.y1 = max(box.y1, y1);
344                    box.x2 = max(box.x2, x2);
345                    box.y2 = max(box.y2, y2);
346
347                    x += glyph->info.xOff;
348                    y += glyph->info.yOff;
349                }
350
351                RootlessDamageBox(dstWin, &box);
352            }
353            list++;
354        }
355    }
356}
357
358/*
359 * RootlessValidateTree
360 *  ValidateTree is modified in two ways:
361 *   - top-level windows don't clip each other
362 *   - windows aren't clipped against root.
363 *  These only matter when validating from the root.
364 */
365static int
366RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
367{
368    int result;
369    RegionRec saveRoot;
370    ScreenPtr pScreen = pParent->drawable.pScreen;
371
372    SCREEN_UNWRAP(pScreen, ValidateTree);
373    RL_DEBUG_MSG("VALIDATETREE start ");
374
375    // Use our custom version to validate from root
376    if (IsRoot(pParent)) {
377        RL_DEBUG_MSG("custom ");
378        result = RootlessMiValidateTree(pParent, pChild, kind);
379    }
380    else {
381        HUGE_ROOT(pParent);
382        result = pScreen->ValidateTree(pParent, pChild, kind);
383        NORMAL_ROOT(pParent);
384    }
385
386    SCREEN_WRAP(pScreen, ValidateTree);
387    RL_DEBUG_MSG("VALIDATETREE end\n");
388
389    return result;
390}
391
392/*
393 * RootlessMarkOverlappedWindows
394 *  MarkOverlappedWindows is modified to ignore overlapping
395 *  top-level windows.
396 */
397static Bool
398RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
399                              WindowPtr *ppLayerWin)
400{
401    RegionRec saveRoot;
402    Bool result;
403    ScreenPtr pScreen = pWin->drawable.pScreen;
404
405    SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
406    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
407
408    HUGE_ROOT(pWin);
409    if (IsRoot(pWin)) {
410        // root - mark nothing
411        RL_DEBUG_MSG("is root not marking ");
412        result = FALSE;
413    }
414    else if (!IsTopLevel(pWin)) {
415        // not top-level window - mark normally
416        result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
417    }
418    else {
419        //top-level window - mark children ONLY - NO overlaps with sibs (?)
420        // This code copied from miMarkOverlappedWindows()
421
422        register WindowPtr pChild;
423        Bool anyMarked = FALSE;
424        MarkWindowProcPtr MarkWindow = pScreen->MarkWindow;
425
426        RL_DEBUG_MSG("is top level! ");
427        /* single layered systems are easy */
428        if (ppLayerWin)
429            *ppLayerWin = pWin;
430
431        if (pWin == pFirst) {
432            /* Blindly mark pWin and all of its inferiors.   This is a slight
433             * overkill if there are mapped windows that outside pWin's border,
434             * but it's better than wasting time on RectIn checks.
435             */
436            pChild = pWin;
437            while (1) {
438                if (pChild->viewable) {
439                    if (RegionBroken(&pChild->winSize))
440                        SetWinSize(pChild);
441                    if (RegionBroken(&pChild->borderSize))
442                        SetBorderSize(pChild);
443                    (*MarkWindow) (pChild);
444                    if (pChild->firstChild) {
445                        pChild = pChild->firstChild;
446                        continue;
447                    }
448                }
449                while (!pChild->nextSib && (pChild != pWin))
450                    pChild = pChild->parent;
451                if (pChild == pWin)
452                    break;
453                pChild = pChild->nextSib;
454            }
455            anyMarked = TRUE;
456        }
457        if (anyMarked)
458            (*MarkWindow) (pWin->parent);
459        result = anyMarked;
460    }
461    NORMAL_ROOT(pWin);
462    SCREEN_WRAP(pScreen, MarkOverlappedWindows);
463    RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
464
465    return result;
466}
467
468static void
469expose_1(WindowPtr pWin)
470{
471    WindowPtr pChild;
472
473    if (!pWin->realized)
474        return;
475
476    pWin->drawable.pScreen->PaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND);
477
478    /* FIXME: comments in windowstr.h indicate that borderClip doesn't
479       include subwindow visibility. But I'm not so sure.. so we may
480       be exposing too much.. */
481
482    miSendExposures(pWin, &pWin->borderClip,
483                    pWin->drawable.x, pWin->drawable.y);
484
485    for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib)
486        expose_1(pChild);
487}
488
489void
490RootlessScreenExpose(ScreenPtr pScreen)
491{
492    expose_1(pScreen->root);
493}
494
495ColormapPtr
496RootlessGetColormap(ScreenPtr pScreen)
497{
498    RootlessScreenRec *s = SCREENREC(pScreen);
499
500    return s->colormap;
501}
502
503static void
504RootlessInstallColormap(ColormapPtr pMap)
505{
506    ScreenPtr pScreen = pMap->pScreen;
507    RootlessScreenRec *s = SCREENREC(pScreen);
508
509    SCREEN_UNWRAP(pScreen, InstallColormap);
510
511    if (s->colormap != pMap) {
512        s->colormap = pMap;
513        s->colormap_changed = TRUE;
514        RootlessQueueRedisplay(pScreen);
515    }
516
517    pScreen->InstallColormap(pMap);
518
519    SCREEN_WRAP(pScreen, InstallColormap);
520}
521
522static void
523RootlessUninstallColormap(ColormapPtr pMap)
524{
525    ScreenPtr pScreen = pMap->pScreen;
526    RootlessScreenRec *s = SCREENREC(pScreen);
527
528    SCREEN_UNWRAP(pScreen, UninstallColormap);
529
530    if (s->colormap == pMap)
531        s->colormap = NULL;
532
533    pScreen->UninstallColormap(pMap);
534
535    SCREEN_WRAP(pScreen, UninstallColormap);
536}
537
538static void
539RootlessStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef)
540{
541    ScreenPtr pScreen = pMap->pScreen;
542    RootlessScreenRec *s = SCREENREC(pScreen);
543
544    SCREEN_UNWRAP(pScreen, StoreColors);
545
546    if (s->colormap == pMap && ndef > 0) {
547        s->colormap_changed = TRUE;
548        RootlessQueueRedisplay(pScreen);
549    }
550
551    pScreen->StoreColors(pMap, ndef, pdef);
552
553    SCREEN_WRAP(pScreen, StoreColors);
554}
555
556static CARD32
557RootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg)
558{
559    RootlessScreenRec *screenRec = arg;
560
561    if (!screenRec->redisplay_queued) {
562        /* No update needed. Stop the timer. */
563
564        screenRec->redisplay_timer_set = FALSE;
565        return 0;
566    }
567
568    screenRec->redisplay_queued = FALSE;
569
570    /* Mark that we should redisplay before waiting for I/O next time */
571    screenRec->redisplay_expired = TRUE;
572
573    /* Reinstall the timer immediately, so we get as close to our
574       redisplay interval as possible. */
575
576    return ROOTLESS_REDISPLAY_DELAY;
577}
578
579/*
580 * RootlessQueueRedisplay
581 *  Queue a redisplay after a timer delay to ensure we do not redisplay
582 *  too frequently.
583 */
584void
585RootlessQueueRedisplay(ScreenPtr pScreen)
586{
587    RootlessScreenRec *screenRec = SCREENREC(pScreen);
588
589    screenRec->redisplay_queued = TRUE;
590
591    if (screenRec->redisplay_timer_set)
592        return;
593
594    screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer,
595                                          0, ROOTLESS_REDISPLAY_DELAY,
596                                          RootlessRedisplayCallback, screenRec);
597    screenRec->redisplay_timer_set = TRUE;
598}
599
600/*
601 * RootlessBlockHandler
602 *  If the redisplay timer has expired, flush drawing before blocking
603 *  on select().
604 */
605static void
606RootlessBlockHandler(void *pbdata, void *ptimeout)
607{
608    ScreenPtr pScreen = pbdata;
609    RootlessScreenRec *screenRec = SCREENREC(pScreen);
610
611    if (screenRec->redisplay_expired) {
612        screenRec->redisplay_expired = FALSE;
613
614        RootlessRedisplayScreen(pScreen);
615    }
616}
617
618static void
619RootlessWakeupHandler(void *data, int result)
620{
621    // nothing here
622}
623
624static Bool
625RootlessAllocatePrivates(ScreenPtr pScreen)
626{
627    RootlessScreenRec *s;
628
629    if (!dixRegisterPrivateKey
630        (&rootlessGCPrivateKeyRec, PRIVATE_GC, sizeof(RootlessGCRec)))
631        return FALSE;
632    if (!dixRegisterPrivateKey(&rootlessScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
633        return FALSE;
634    if (!dixRegisterPrivateKey(&rootlessWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
635        return FALSE;
636    if (!dixRegisterPrivateKey
637        (&rootlessWindowOldPixmapPrivateKeyRec, PRIVATE_WINDOW, 0))
638        return FALSE;
639
640    s = malloc(sizeof(RootlessScreenRec));
641    if (!s)
642        return FALSE;
643    SETSCREENREC(pScreen, s);
644
645    s->pixmap_data = NULL;
646    s->pixmap_data_size = 0;
647
648    s->redisplay_timer = NULL;
649    s->redisplay_timer_set = FALSE;
650
651    return TRUE;
652}
653
654static void
655RootlessWrap(ScreenPtr pScreen)
656{
657    RootlessScreenRec *s = SCREENREC(pScreen);
658
659#define WRAP(a) \
660    if (pScreen->a) { \
661        s->a = pScreen->a; \
662    } else { \
663        RL_DEBUG_MSG("null screen fn " #a "\n"); \
664        s->a = NULL; \
665    } \
666    pScreen->a = Rootless##a
667
668    WRAP(CreateScreenResources);
669    WRAP(CloseScreen);
670    WRAP(CreateGC);
671    WRAP(CopyWindow);
672    WRAP(PaintWindow);
673    WRAP(GetImage);
674    WRAP(SourceValidate);
675    WRAP(CreateWindow);
676    WRAP(DestroyWindow);
677    WRAP(RealizeWindow);
678    WRAP(UnrealizeWindow);
679    WRAP(MoveWindow);
680    WRAP(PositionWindow);
681    WRAP(ResizeWindow);
682    WRAP(RestackWindow);
683    WRAP(ReparentWindow);
684    WRAP(ChangeBorderWidth);
685    WRAP(MarkOverlappedWindows);
686    WRAP(ValidateTree);
687    WRAP(ChangeWindowAttributes);
688    WRAP(InstallColormap);
689    WRAP(UninstallColormap);
690    WRAP(StoreColors);
691
692    WRAP(SetShape);
693
694    {
695        // Composite and Glyphs don't use normal screen wrapping
696        PictureScreenPtr ps = GetPictureScreen(pScreen);
697
698        s->Composite = ps->Composite;
699        ps->Composite = RootlessComposite;
700        s->Glyphs = ps->Glyphs;
701        ps->Glyphs = RootlessGlyphs;
702    }
703
704    // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
705
706#undef WRAP
707}
708
709/*
710 * RootlessInit
711 *  Called by the rootless implementation to initialize the rootless layer.
712 *  Rootless wraps lots of stuff and needs a bunch of devPrivates.
713 */
714Bool
715RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
716{
717    RootlessScreenRec *s;
718
719    if (!RootlessAllocatePrivates(pScreen))
720        return FALSE;
721
722    s = SCREENREC(pScreen);
723
724    s->imp = procs;
725    s->colormap = NULL;
726    s->redisplay_expired = FALSE;
727
728    RootlessWrap(pScreen);
729
730    if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler,
731                                        RootlessWakeupHandler,
732                                        (void *) pScreen)) {
733        return FALSE;
734    }
735
736    return TRUE;
737}
738
739void
740RootlessUpdateRooted(Bool state)
741{
742    int i;
743
744    if (!state) {
745        for (i = 0; i < screenInfo.numScreens; i++)
746            RootlessDisableRoot(screenInfo.screens[i]);
747    }
748    else {
749        for (i = 0; i < screenInfo.numScreens; i++)
750            RootlessEnableRoot(screenInfo.screens[i]);
751    }
752}
753