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     pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h,
232                                        subWindowMode);
233     SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
234 }
235 
236 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)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) {                // pMask can be NULL
246         maskWin = (pMask->pDrawable &&
247                    pMask->pDrawable->type ==
248                    DRAWABLE_WINDOW) ? (WindowPtr) pMask->pDrawable : NULL;
249     }
250     srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
251         (WindowPtr) pSrc->pDrawable : NULL;
252     dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
253         (WindowPtr) pDst->pDrawable : NULL;
254 
255     // SCREEN_UNWRAP(ps, Composite);
256     ps->Composite = SCREENREC(pScreen)->Composite;
257 
258     if (srcWin && IsFramedWindow(srcWin))
259         RootlessStartDrawing(srcWin);
260     if (maskWin && IsFramedWindow(maskWin))
261         RootlessStartDrawing(maskWin);
262     if (dstWin && IsFramedWindow(dstWin))
263         RootlessStartDrawing(dstWin);
264 
265     ps->Composite(op, pSrc, pMask, pDst,
266                   xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
267 
268     if (dstWin && IsFramedWindow(dstWin)) {
269         RootlessDamageRect(dstWin, xDst, yDst, width, height);
270     }
271 
272     ps->Composite = RootlessComposite;
273     // SCREEN_WRAP(ps, Composite);
274 }
275 
276 static void
RootlessGlyphs(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int nlist,GlyphListPtr list,GlyphPtr * glyphs)277 RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
278                PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
279                int nlist, GlyphListPtr list, GlyphPtr * glyphs)
280 {
281     ScreenPtr pScreen = pDst->pDrawable->pScreen;
282     PictureScreenPtr ps = GetPictureScreen(pScreen);
283     int x, y;
284     int n;
285     GlyphPtr glyph;
286     WindowPtr srcWin, dstWin;
287 
288     srcWin = (pSrc->pDrawable && pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
289         (WindowPtr) pSrc->pDrawable : NULL;
290     dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
291         (WindowPtr) pDst->pDrawable : NULL;
292 
293     if (srcWin && IsFramedWindow(srcWin))
294         RootlessStartDrawing(srcWin);
295     if (dstWin && IsFramedWindow(dstWin))
296         RootlessStartDrawing(dstWin);
297 
298     //SCREEN_UNWRAP(ps, Glyphs);
299     ps->Glyphs = SCREENREC(pScreen)->Glyphs;
300     ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
301     ps->Glyphs = RootlessGlyphs;
302     //SCREEN_WRAP(ps, Glyphs);
303 
304     if (dstWin && IsFramedWindow(dstWin)) {
305         x = xSrc;
306         y = ySrc;
307 
308         while (nlist--) {
309             x += list->xOff;
310             y += list->yOff;
311             n = list->len;
312 
313             /* Calling DamageRect for the bounding box of each glyph is
314                inefficient. So compute the union of all glyphs in a list
315                and damage that. */
316 
317             if (n > 0) {
318                 BoxRec box;
319 
320                 glyph = *glyphs++;
321 
322                 box.x1 = x - glyph->info.x;
323                 box.y1 = y - glyph->info.y;
324                 box.x2 = box.x1 + glyph->info.width;
325                 box.y2 = box.y1 + glyph->info.height;
326 
327                 x += glyph->info.xOff;
328                 y += glyph->info.yOff;
329 
330                 while (--n > 0) {
331                     short x1, y1, x2, y2;
332 
333                     glyph = *glyphs++;
334 
335                     x1 = x - glyph->info.x;
336                     y1 = y - glyph->info.y;
337                     x2 = x1 + glyph->info.width;
338                     y2 = y1 + glyph->info.height;
339 
340                     box.x1 = max(box.x1, x1);
341                     box.y1 = max(box.y1, y1);
342                     box.x2 = max(box.x2, x2);
343                     box.y2 = max(box.y2, y2);
344 
345                     x += glyph->info.xOff;
346                     y += glyph->info.yOff;
347                 }
348 
349                 RootlessDamageBox(dstWin, &box);
350             }
351             list++;
352         }
353     }
354 }
355 
356 /*
357  * RootlessValidateTree
358  *  ValidateTree is modified in two ways:
359  *   - top-level windows don't clip each other
360  *   - windows aren't clipped against root.
361  *  These only matter when validating from the root.
362  */
363 static int
RootlessValidateTree(WindowPtr pParent,WindowPtr pChild,VTKind kind)364 RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
365 {
366     int result;
367     RegionRec saveRoot;
368     ScreenPtr pScreen = pParent->drawable.pScreen;
369 
370     SCREEN_UNWRAP(pScreen, ValidateTree);
371     RL_DEBUG_MSG("VALIDATETREE start ");
372 
373     // Use our custom version to validate from root
374     if (IsRoot(pParent)) {
375         RL_DEBUG_MSG("custom ");
376         result = RootlessMiValidateTree(pParent, pChild, kind);
377     }
378     else {
379         HUGE_ROOT(pParent);
380         result = pScreen->ValidateTree(pParent, pChild, kind);
381         NORMAL_ROOT(pParent);
382     }
383 
384     SCREEN_WRAP(pScreen, ValidateTree);
385     RL_DEBUG_MSG("VALIDATETREE end\n");
386 
387     return result;
388 }
389 
390 /*
391  * RootlessMarkOverlappedWindows
392  *  MarkOverlappedWindows is modified to ignore overlapping
393  *  top-level windows.
394  */
395 static Bool
RootlessMarkOverlappedWindows(WindowPtr pWin,WindowPtr pFirst,WindowPtr * ppLayerWin)396 RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
397                               WindowPtr *ppLayerWin)
398 {
399     RegionRec saveRoot;
400     Bool result;
401     ScreenPtr pScreen = pWin->drawable.pScreen;
402 
403     SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
404     RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
405 
406     HUGE_ROOT(pWin);
407     if (IsRoot(pWin)) {
408         // root - mark nothing
409         RL_DEBUG_MSG("is root not marking ");
410         result = FALSE;
411     }
412     else if (!IsTopLevel(pWin)) {
413         // not top-level window - mark normally
414         result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
415     }
416     else {
417         //top-level window - mark children ONLY - NO overlaps with sibs (?)
418         // This code copied from miMarkOverlappedWindows()
419 
420         register WindowPtr pChild;
421         Bool anyMarked = FALSE;
422         MarkWindowProcPtr MarkWindow = pScreen->MarkWindow;
423 
424         RL_DEBUG_MSG("is top level! ");
425         /* single layered systems are easy */
426         if (ppLayerWin)
427             *ppLayerWin = pWin;
428 
429         if (pWin == pFirst) {
430             /* Blindly mark pWin and all of its inferiors.   This is a slight
431              * overkill if there are mapped windows that outside pWin's border,
432              * but it's better than wasting time on RectIn checks.
433              */
434             pChild = pWin;
435             while (1) {
436                 if (pChild->viewable) {
437                     if (RegionBroken(&pChild->winSize))
438                         SetWinSize(pChild);
439                     if (RegionBroken(&pChild->borderSize))
440                         SetBorderSize(pChild);
441                     (*MarkWindow) (pChild);
442                     if (pChild->firstChild) {
443                         pChild = pChild->firstChild;
444                         continue;
445                     }
446                 }
447                 while (!pChild->nextSib && (pChild != pWin))
448                     pChild = pChild->parent;
449                 if (pChild == pWin)
450                     break;
451                 pChild = pChild->nextSib;
452             }
453             anyMarked = TRUE;
454         }
455         if (anyMarked)
456             (*MarkWindow) (pWin->parent);
457         result = anyMarked;
458     }
459     NORMAL_ROOT(pWin);
460     SCREEN_WRAP(pScreen, MarkOverlappedWindows);
461     RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
462 
463     return result;
464 }
465 
466 static void
expose_1(WindowPtr pWin)467 expose_1(WindowPtr pWin)
468 {
469     WindowPtr pChild;
470 
471     if (!pWin->realized)
472         return;
473 
474     pWin->drawable.pScreen->PaintWindow(pWin, &pWin->borderClip, PW_BACKGROUND);
475 
476     /* FIXME: comments in windowstr.h indicate that borderClip doesn't
477        include subwindow visibility. But I'm not so sure.. so we may
478        be exposing too much.. */
479 
480     miSendExposures(pWin, &pWin->borderClip,
481                     pWin->drawable.x, pWin->drawable.y);
482 
483     for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib)
484         expose_1(pChild);
485 }
486 
487 void
RootlessScreenExpose(ScreenPtr pScreen)488 RootlessScreenExpose(ScreenPtr pScreen)
489 {
490     expose_1(pScreen->root);
491 }
492 
493 ColormapPtr
RootlessGetColormap(ScreenPtr pScreen)494 RootlessGetColormap(ScreenPtr pScreen)
495 {
496     RootlessScreenRec *s = SCREENREC(pScreen);
497 
498     return s->colormap;
499 }
500 
501 static void
RootlessInstallColormap(ColormapPtr pMap)502 RootlessInstallColormap(ColormapPtr pMap)
503 {
504     ScreenPtr pScreen = pMap->pScreen;
505     RootlessScreenRec *s = SCREENREC(pScreen);
506 
507     SCREEN_UNWRAP(pScreen, InstallColormap);
508 
509     if (s->colormap != pMap) {
510         s->colormap = pMap;
511         s->colormap_changed = TRUE;
512         RootlessQueueRedisplay(pScreen);
513     }
514 
515     pScreen->InstallColormap(pMap);
516 
517     SCREEN_WRAP(pScreen, InstallColormap);
518 }
519 
520 static void
RootlessUninstallColormap(ColormapPtr pMap)521 RootlessUninstallColormap(ColormapPtr pMap)
522 {
523     ScreenPtr pScreen = pMap->pScreen;
524     RootlessScreenRec *s = SCREENREC(pScreen);
525 
526     SCREEN_UNWRAP(pScreen, UninstallColormap);
527 
528     if (s->colormap == pMap)
529         s->colormap = NULL;
530 
531     pScreen->UninstallColormap(pMap);
532 
533     SCREEN_WRAP(pScreen, UninstallColormap);
534 }
535 
536 static void
RootlessStoreColors(ColormapPtr pMap,int ndef,xColorItem * pdef)537 RootlessStoreColors(ColormapPtr pMap, int ndef, xColorItem * pdef)
538 {
539     ScreenPtr pScreen = pMap->pScreen;
540     RootlessScreenRec *s = SCREENREC(pScreen);
541 
542     SCREEN_UNWRAP(pScreen, StoreColors);
543 
544     if (s->colormap == pMap && ndef > 0) {
545         s->colormap_changed = TRUE;
546         RootlessQueueRedisplay(pScreen);
547     }
548 
549     pScreen->StoreColors(pMap, ndef, pdef);
550 
551     SCREEN_WRAP(pScreen, StoreColors);
552 }
553 
554 static CARD32
RootlessRedisplayCallback(OsTimerPtr timer,CARD32 time,void * arg)555 RootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg)
556 {
557     RootlessScreenRec *screenRec = arg;
558 
559     if (!screenRec->redisplay_queued) {
560         /* No update needed. Stop the timer. */
561 
562         screenRec->redisplay_timer_set = FALSE;
563         return 0;
564     }
565 
566     screenRec->redisplay_queued = FALSE;
567 
568     /* Mark that we should redisplay before waiting for I/O next time */
569     screenRec->redisplay_expired = TRUE;
570 
571     /* Reinstall the timer immediately, so we get as close to our
572        redisplay interval as possible. */
573 
574     return ROOTLESS_REDISPLAY_DELAY;
575 }
576 
577 /*
578  * RootlessQueueRedisplay
579  *  Queue a redisplay after a timer delay to ensure we do not redisplay
580  *  too frequently.
581  */
582 void
RootlessQueueRedisplay(ScreenPtr pScreen)583 RootlessQueueRedisplay(ScreenPtr pScreen)
584 {
585     RootlessScreenRec *screenRec = SCREENREC(pScreen);
586 
587     screenRec->redisplay_queued = TRUE;
588 
589     if (screenRec->redisplay_timer_set)
590         return;
591 
592     screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer,
593                                           0, ROOTLESS_REDISPLAY_DELAY,
594                                           RootlessRedisplayCallback, screenRec);
595     screenRec->redisplay_timer_set = TRUE;
596 }
597 
598 /*
599  * RootlessBlockHandler
600  *  If the redisplay timer has expired, flush drawing before blocking
601  *  on select().
602  */
603 static void
RootlessBlockHandler(void * pbdata,void * ptimeout)604 RootlessBlockHandler(void *pbdata, void *ptimeout)
605 {
606     ScreenPtr pScreen = pbdata;
607     RootlessScreenRec *screenRec = SCREENREC(pScreen);
608 
609     if (screenRec->redisplay_expired) {
610         screenRec->redisplay_expired = FALSE;
611 
612         RootlessRedisplayScreen(pScreen);
613     }
614 }
615 
616 static void
RootlessWakeupHandler(void * data,int result)617 RootlessWakeupHandler(void *data, int result)
618 {
619     // nothing here
620 }
621 
622 static Bool
RootlessAllocatePrivates(ScreenPtr pScreen)623 RootlessAllocatePrivates(ScreenPtr pScreen)
624 {
625     RootlessScreenRec *s;
626 
627     if (!dixRegisterPrivateKey
628         (&rootlessGCPrivateKeyRec, PRIVATE_GC, sizeof(RootlessGCRec)))
629         return FALSE;
630     if (!dixRegisterPrivateKey(&rootlessScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
631         return FALSE;
632     if (!dixRegisterPrivateKey(&rootlessWindowPrivateKeyRec, PRIVATE_WINDOW, 0))
633         return FALSE;
634     if (!dixRegisterPrivateKey
635         (&rootlessWindowOldPixmapPrivateKeyRec, PRIVATE_WINDOW, 0))
636         return FALSE;
637 
638     s = malloc(sizeof(RootlessScreenRec));
639     if (!s)
640         return FALSE;
641     SETSCREENREC(pScreen, s);
642 
643     s->pixmap_data = NULL;
644     s->pixmap_data_size = 0;
645 
646     s->redisplay_timer = NULL;
647     s->redisplay_timer_set = FALSE;
648 
649     return TRUE;
650 }
651 
652 static void
RootlessWrap(ScreenPtr pScreen)653 RootlessWrap(ScreenPtr pScreen)
654 {
655     RootlessScreenRec *s = SCREENREC(pScreen);
656 
657 #define WRAP(a) \
658     if (pScreen->a) { \
659         s->a = pScreen->a; \
660     } else { \
661         RL_DEBUG_MSG("null screen fn " #a "\n"); \
662         s->a = NULL; \
663     } \
664     pScreen->a = Rootless##a
665 
666     WRAP(CreateScreenResources);
667     WRAP(CloseScreen);
668     WRAP(CreateGC);
669     WRAP(CopyWindow);
670     WRAP(PaintWindow);
671     WRAP(GetImage);
672     WRAP(SourceValidate);
673     WRAP(CreateWindow);
674     WRAP(DestroyWindow);
675     WRAP(RealizeWindow);
676     WRAP(UnrealizeWindow);
677     WRAP(MoveWindow);
678     WRAP(PositionWindow);
679     WRAP(ResizeWindow);
680     WRAP(RestackWindow);
681     WRAP(ReparentWindow);
682     WRAP(ChangeBorderWidth);
683     WRAP(MarkOverlappedWindows);
684     WRAP(ValidateTree);
685     WRAP(ChangeWindowAttributes);
686     WRAP(InstallColormap);
687     WRAP(UninstallColormap);
688     WRAP(StoreColors);
689 
690     WRAP(SetShape);
691 
692     {
693         // Composite and Glyphs don't use normal screen wrapping
694         PictureScreenPtr ps = GetPictureScreen(pScreen);
695 
696         s->Composite = ps->Composite;
697         ps->Composite = RootlessComposite;
698         s->Glyphs = ps->Glyphs;
699         ps->Glyphs = RootlessGlyphs;
700     }
701 
702     // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
703 
704 #undef WRAP
705 }
706 
707 /*
708  * RootlessInit
709  *  Called by the rootless implementation to initialize the rootless layer.
710  *  Rootless wraps lots of stuff and needs a bunch of devPrivates.
711  */
712 Bool
RootlessInit(ScreenPtr pScreen,RootlessFrameProcsPtr procs)713 RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
714 {
715     RootlessScreenRec *s;
716 
717     if (!RootlessAllocatePrivates(pScreen))
718         return FALSE;
719 
720     s = SCREENREC(pScreen);
721 
722     s->imp = procs;
723     s->colormap = NULL;
724     s->redisplay_expired = FALSE;
725 
726     RootlessWrap(pScreen);
727 
728     if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler,
729                                         RootlessWakeupHandler,
730                                         (void *) pScreen)) {
731         return FALSE;
732     }
733 
734     return TRUE;
735 }
736 
737 void
RootlessUpdateRooted(Bool state)738 RootlessUpdateRooted(Bool state)
739 {
740     int i;
741 
742     if (!state) {
743         for (i = 0; i < screenInfo.numScreens; i++)
744             RootlessDisableRoot(screenInfo.screens[i]);
745     }
746     else {
747         for (i = 0; i < screenInfo.numScreens; i++)
748             RootlessEnableRoot(screenInfo.screens[i]);
749     }
750 }
751