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