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 
59 extern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild,
60                                   VTKind kind);
61 extern Bool RootlessCreateGC(GCPtr pGC);
62 
63 // Initialize globals
64 DevPrivateKeyRec rootlessGCPrivateKeyRec;
65 DevPrivateKeyRec rootlessScreenPrivateKeyRec;
66 DevPrivateKeyRec rootlessWindowPrivateKeyRec;
67 DevPrivateKeyRec 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  */
78 void
RootlessUpdateScreenPixmap(ScreenPtr pScreen)79 RootlessUpdateScreenPixmap(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  */
118 static Bool
RootlessCreateScreenResources(ScreenPtr pScreen)119 RootlessCreateScreenResources(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 
140 static Bool
RootlessCloseScreen(ScreenPtr pScreen)141 RootlessCloseScreen(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 
160 static void
RootlessGetImage(DrawablePtr pDrawable,int sx,int sy,int w,int h,unsigned int format,unsigned long planeMask,char * pdstLine)161 RootlessGetImage(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  */
221 static void
RootlessSourceValidate(DrawablePtr pDrawable,int x,int y,int w,int h,unsigned int subWindowMode)222 RootlessSourceValidate(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 
238 static void
RootlessComposite(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)239 RootlessComposite(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 
278 static void
RootlessGlyphs(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int nlist,GlyphListPtr list,GlyphPtr * glyphs)279 RootlessGlyphs(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  */
365 static int
RootlessValidateTree(WindowPtr pParent,WindowPtr pChild,VTKind kind)366 RootlessValidateTree(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  */
397 static Bool
RootlessMarkOverlappedWindows(WindowPtr pWin,WindowPtr pFirst,WindowPtr * ppLayerWin)398 RootlessMarkOverlappedWindows(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 
468 static void
expose_1(WindowPtr pWin)469 expose_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 
489 void
RootlessScreenExpose(ScreenPtr pScreen)490 RootlessScreenExpose(ScreenPtr pScreen)
491 {
492     expose_1(pScreen->root);
493 }
494 
495 ColormapPtr
RootlessGetColormap(ScreenPtr pScreen)496 RootlessGetColormap(ScreenPtr pScreen)
497 {
498     RootlessScreenRec *s = SCREENREC(pScreen);
499 
500     return s->colormap;
501 }
502 
503 static void
RootlessInstallColormap(ColormapPtr pMap)504 RootlessInstallColormap(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 
522 static void
RootlessUninstallColormap(ColormapPtr pMap)523 RootlessUninstallColormap(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 
538 static void
RootlessStoreColors(ColormapPtr pMap,int ndef,xColorItem * pdef)539 RootlessStoreColors(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 
556 static CARD32
RootlessRedisplayCallback(OsTimerPtr timer,CARD32 time,void * arg)557 RootlessRedisplayCallback(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  */
584 void
RootlessQueueRedisplay(ScreenPtr pScreen)585 RootlessQueueRedisplay(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  */
605 static void
RootlessBlockHandler(void * pbdata,void * ptimeout)606 RootlessBlockHandler(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 
618 static void
RootlessWakeupHandler(void * data,int result)619 RootlessWakeupHandler(void *data, int result)
620 {
621     // nothing here
622 }
623 
624 static Bool
RootlessAllocatePrivates(ScreenPtr pScreen)625 RootlessAllocatePrivates(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 
654 static void
RootlessWrap(ScreenPtr pScreen)655 RootlessWrap(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  */
714 Bool
RootlessInit(ScreenPtr pScreen,RootlessFrameProcsPtr procs)715 RootlessInit(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 
739 void
RootlessUpdateRooted(Bool state)740 RootlessUpdateRooted(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