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
RootlessUpdateScreenPixmap(ScreenPtr pScreen)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
RootlessCreateScreenResources(ScreenPtr pScreen)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
RootlessCloseScreen(int i,ScreenPtr pScreen)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
RootlessGetImage(DrawablePtr pDrawable,int sx,int sy,int w,int h,unsigned int format,unsigned long planeMask,char * pdstLine)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
RootlessSourceValidate(DrawablePtr pDrawable,int x,int y,int w,int h)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
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) {
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
RootlessGlyphs(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int nlist,GlyphListPtr list,GlyphPtr * glyphs)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
RootlessValidateTree(WindowPtr pParent,WindowPtr pChild,VTKind kind)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
RootlessMarkOverlappedWindows(WindowPtr pWin,WindowPtr pFirst,WindowPtr * ppLayerWin)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
expose_1(WindowPtr pWin)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
RootlessScreenExpose(ScreenPtr pScreen)480 RootlessScreenExpose (ScreenPtr pScreen)
481 {
482     expose_1 (WindowTable[pScreen->myNum]);
483 }
484 
485 ColormapPtr
RootlessGetColormap(ScreenPtr pScreen)486 RootlessGetColormap (ScreenPtr pScreen)
487 {
488     RootlessScreenRec *s = SCREENREC (pScreen);
489 
490     return s->colormap;
491 }
492 
493 static void
RootlessInstallColormap(ColormapPtr pMap)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
RootlessUninstallColormap(ColormapPtr pMap)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
RootlessStoreColors(ColormapPtr pMap,int ndef,xColorItem * pdef)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
redisplay_callback(OsTimerPtr timer,CARD32 time,void * arg)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
RootlessQueueRedisplay(ScreenPtr pScreen)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
RootlessMayRedisplay(ScreenPtr pScreen)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
RootlessBlockHandler(pointer pbdata,OSTimePtr pTimeout,pointer pReadmask)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
RootlessWakeupHandler(pointer data,int i,pointer LastSelectMask)643 RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask)
644 {
645 }
646 
647 static Bool
RootlessAllocatePrivates(ScreenPtr pScreen)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
RootlessWrap(ScreenPtr pScreen)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
RootlessSetupScreen(int index,ScreenPtr pScreen)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
RootlessUpdateRooted(Bool state)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 }
795