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