2 * Screen routines for Mac OS X rootless X server
4 * Greg Parker gparker@cs.stanford.edu
6 * February 2001 Created
7 * March 3, 2001 Restructured as generic rootless mode
10 /* Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
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:
20 The above copyright notice and this permission notice shall be
21 included in all copies or substantial portions of the Software.
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.
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. */
37 /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessScreen.c,v 1.2 2002/04/03 00:06:32 torrey Exp $ */
41 #include "scrnintstr.h"
43 #include "pixmapstr.h"
44 #include "windowstr.h"
45 #include "propertyst.h"
46 #include "mivalidate.h"
47 #include "picturestr.h"
50 #include "colormapst.h"
52 #include <sys/types.h>
56 #include "rootless-common.h"
57 #include "rootless-window.h"
59 /* In milcroseconds */
60 #define REDISPLAY_DELAY 10
61 #define REDISPLAY_MAX_DELAY 60
63 extern int RootlessMiValidateTree(WindowPtr pRoot,
64 WindowPtr pChild, VTKind kind);
65 extern Bool RootlessCreateGC(GCPtr pGC);
67 int rootlessGCPrivateIndex = -1;
68 int rootlessScreenPrivateIndex = -1;
69 int rootlessWindowPrivateIndex = -1;
72 RootlessUpdateScreenPixmap (ScreenPtr pScreen)
74 RootlessScreenRec *s = SCREENREC(pScreen);
76 unsigned int rowbytes;
78 pPix = (*pScreen->GetScreenPixmap) (pScreen);
81 pPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth);
82 (*pScreen->SetScreenPixmap) (pPix);
85 rowbytes = PixmapBytePad (pScreen->width, pScreen->rootDepth);
87 if (s->pixmap_data_size < rowbytes)
89 if (s->pixmap_data != NULL)
90 xfree (s->pixmap_data);
92 s->pixmap_data_size = rowbytes;
93 s->pixmap_data = xalloc (s->pixmap_data_size);
94 if (s->pixmap_data == NULL)
97 xp_fill_bytes (s->pixmap_data_size, 1, ~0,
98 s->pixmap_data, s->pixmap_data_size);
100 pScreen->ModifyPixmapHeader (pPix, pScreen->width, pScreen->height,
102 BitsPerPixel (pScreen->rootDepth),
104 /* ModifyPixmapHeader ignores zero arguments, so install rowbytes
111 RootlessCreateScreenResources (ScreenPtr pScreen)
115 SCREEN_UNWRAP (pScreen, CreateScreenResources);
117 if (pScreen->CreateScreenResources != NULL)
118 ret = (*pScreen->CreateScreenResources) (pScreen);
120 SCREEN_WRAP(pScreen, CreateScreenResources);
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) */
131 RootlessUpdateScreenPixmap (pScreen);
137 RootlessCloseScreen(int i, ScreenPtr pScreen)
139 RootlessScreenRec *s;
141 s = SCREENREC(pScreen);
143 /* FIXME: unwrap everything that was wrapped? */
144 pScreen->CloseScreen = s->CloseScreen;
146 if (s->pixmap_data != NULL)
148 xfree (s->pixmap_data);
149 s->pixmap_data = NULL;
150 s->pixmap_data_size = 0;
154 return pScreen->CloseScreen(i, pScreen);
158 RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
159 unsigned int format, unsigned long planeMask, char *pdstLine)
161 ScreenPtr pScreen = pDrawable->pScreen;
162 SCREEN_UNWRAP(pScreen, GetImage);
164 if (pDrawable->type == DRAWABLE_WINDOW)
168 RootlessWindowRec *winRec;
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);
174 /* RedisplayScreen stops drawing, so we need to start it again */
175 RootlessStartDrawing ((WindowPtr) pDrawable);
177 /* Check that we have some place to read from. */
178 winRec = WINREC (TopLevelParent ((WindowPtr) pDrawable));
182 /* Clip to top-level window bounds. */
184 x0 = pDrawable->x + sx;
185 y0 = pDrawable->y + sy;
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);
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.. */
198 sx = x0 - pDrawable->x;
199 sy = y0 - pDrawable->y;
203 if (w <= 0 || h <= 0)
207 pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
210 SCREEN_WRAP(pScreen, GetImage);
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.
221 RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h)
223 SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate);
224 if (pDrawable->type == DRAWABLE_WINDOW) {
225 WindowPtr pWin = (WindowPtr)pDrawable;
226 RootlessStartDrawing(pWin);
228 if (pDrawable->pScreen->SourceValidate) {
229 pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h);
231 SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
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)
241 ScreenPtr pScreen = pDst->pDrawable->pScreen;
242 PictureScreenPtr ps = GetPictureScreen(pScreen);
243 WindowPtr srcWin, dstWin, maskWin = NULL;
246 maskWin = (pMask->pDrawable->type == DRAWABLE_WINDOW) ?
247 (WindowPtr)pMask->pDrawable : NULL;
249 srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
250 (WindowPtr)pSrc->pDrawable : NULL;
251 dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
252 (WindowPtr)pDst->pDrawable : NULL;
254 ps->Composite = SCREENREC(pScreen)->Composite;
256 if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin);
257 if (maskWin && IsFramedWindow(maskWin)) RootlessStartDrawing(maskWin);
258 if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin);
260 ps->Composite(op, pSrc, pMask, pDst,
261 xSrc, ySrc, xMask, yMask,
262 xDst, yDst, width, height);
264 if (dstWin && IsFramedWindow(dstWin)) {
265 RootlessDamageRect(dstWin, xDst, yDst, width, height);
268 ps->Composite = RootlessComposite;
272 RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
273 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
274 int nlist, GlyphListPtr list, GlyphPtr *glyphs)
276 ScreenPtr pScreen = pDst->pDrawable->pScreen;
277 PictureScreenPtr ps = GetPictureScreen(pScreen);
281 WindowPtr srcWin, dstWin;
283 srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
284 (WindowPtr)pSrc->pDrawable : NULL;
285 dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
286 (WindowPtr)pDst->pDrawable : NULL;
288 if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin);
289 if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin);
291 ps->Glyphs = SCREENREC(pScreen)->Glyphs;
292 ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
293 ps->Glyphs = RootlessGlyphs;
295 if (dstWin && IsFramedWindow(dstWin))
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. */
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;
323 x += glyph->info.xOff;
324 y += glyph->info.yOff;
328 short x1, y1, x2, y2;
332 x1 = x - glyph->info.x;
333 y1 = y - glyph->info.y;
334 x2 = x1 + glyph->info.width;
335 y2 = y1 + glyph->info.height;
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);
342 x += glyph->info.xOff;
343 y += glyph->info.yOff;
346 RootlessDamageBox (dstWin, &box);
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. */
361 RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
365 ScreenPtr pScreen = pParent->drawable.pScreen;
367 SCREEN_UNWRAP(pScreen, ValidateTree);
368 RL_DEBUG_MSG("VALIDATETREE start ");
370 /* Use our custom version to validate from root */
371 if (IsRoot(pParent)) {
372 RL_DEBUG_MSG("custom ");
373 result = RootlessMiValidateTree(pParent, pChild, kind);
376 result = pScreen->ValidateTree(pParent, pChild, kind);
377 NORMAL_ROOT(pParent);
380 SCREEN_WRAP(pScreen, ValidateTree);
381 RL_DEBUG_MSG("VALIDATETREE end\n");
386 /* MarkOverlappedWindows is modified to ignore overlapping top-level
389 RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
390 WindowPtr *ppLayerWin)
394 ScreenPtr pScreen = pWin->drawable.pScreen;
395 SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
396 RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
400 /* root - mark nothing */
401 RL_DEBUG_MSG("is root not marking ");
404 else if (! IsTopLevel(pWin)) {
405 /* not top-level window - mark normally */
406 result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
409 /* top-level window - mark children ONLY - NO overlaps with sibs (?)
410 This code copied from miMarkOverlappedWindows() */
412 register WindowPtr pChild;
413 Bool anyMarked = FALSE;
414 void (* MarkWindow)() = pScreen->MarkWindow;
416 RL_DEBUG_MSG("is top level! ");
417 /* single layered systems are easy */
418 if (ppLayerWin) *ppLayerWin = pWin;
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.
427 if (pChild->viewable) {
428 if (REGION_BROKEN (pScreen, &pChild->winSize))
430 if (REGION_BROKEN (pScreen, &pChild->borderSize))
431 SetBorderSize (pChild);
432 (* MarkWindow)(pChild);
433 if (pChild->firstChild) {
434 pChild = pChild->firstChild;
438 while (!pChild->nextSib && (pChild != pWin))
439 pChild = pChild->parent;
442 pChild = pChild->nextSib;
445 pFirst = pFirst->nextSib;
448 (* MarkWindow)(pWin->parent);
452 SCREEN_WRAP(pScreen, MarkOverlappedWindows);
453 RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
458 expose_1 (WindowPtr pWin)
465 (*pWin->drawable.pScreen->PaintWindowBackground) (pWin, &pWin->borderClip,
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.. */
472 miSendExposures (pWin, &pWin->borderClip,
473 pWin->drawable.x, pWin->drawable.y);
475 for (pChild = pWin->firstChild; pChild != NULL; pChild = pChild->nextSib)
480 RootlessScreenExpose (ScreenPtr pScreen)
482 expose_1 (WindowTable[pScreen->myNum]);
486 RootlessGetColormap (ScreenPtr pScreen)
488 RootlessScreenRec *s = SCREENREC (pScreen);
494 RootlessInstallColormap (ColormapPtr pMap)
496 ScreenPtr pScreen = pMap->pScreen;
497 RootlessScreenRec *s = SCREENREC (pScreen);
499 SCREEN_UNWRAP(pScreen, InstallColormap);
501 if (s->colormap != pMap)
504 s->colormap_changed = TRUE;
505 RootlessQueueRedisplay (pScreen);
508 pScreen->InstallColormap (pMap);
510 SCREEN_WRAP (pScreen, InstallColormap);
514 RootlessUninstallColormap (ColormapPtr pMap)
516 ScreenPtr pScreen = pMap->pScreen;
517 RootlessScreenRec *s = SCREENREC (pScreen);
519 SCREEN_UNWRAP(pScreen, UninstallColormap);
521 if (s->colormap == pMap)
524 pScreen->UninstallColormap (pMap);
526 SCREEN_WRAP(pScreen, UninstallColormap);
530 RootlessStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef)
532 ScreenPtr pScreen = pMap->pScreen;
533 RootlessScreenRec *s = SCREENREC (pScreen);
535 SCREEN_UNWRAP(pScreen, StoreColors);
537 if (s->colormap == pMap && ndef > 0)
539 s->colormap_changed = TRUE;
540 RootlessQueueRedisplay (pScreen);
543 pScreen->StoreColors (pMap, ndef, pdef);
545 SCREEN_WRAP(pScreen, StoreColors);
549 redisplay_callback (OsTimerPtr timer, CARD32 time, void *arg)
551 RootlessScreenRec *screenRec = arg;
553 if (!screenRec->redisplay_queued)
555 /* No update needed. Stop the timer. */
557 screenRec->redisplay_timer_set = FALSE;
561 screenRec->redisplay_queued = FALSE;
563 /* Mark that we should redisplay before waiting for I/O next time */
564 screenRec->redisplay_expired = TRUE;
566 /* Reinstall the timer immediately, so we get as close to our
567 redisplay interval as possible. */
569 return REDISPLAY_DELAY;
573 RootlessQueueRedisplay (ScreenPtr pScreen)
575 RootlessScreenRec *screenRec = SCREENREC (pScreen);
577 screenRec->redisplay_queued = TRUE;
579 if (screenRec->redisplay_timer_set)
582 screenRec->redisplay_timer = TimerSet (screenRec->redisplay_timer,
584 redisplay_callback, screenRec);
585 screenRec->redisplay_timer_set = TRUE;
588 /* Call this function when it might be a good idea to flush updates.
589 Note that it will unlock window buffers! */
591 RootlessMayRedisplay (ScreenPtr pScreen)
593 RootlessScreenRec *screenRec = SCREENREC (pScreen);
595 if (!screenRec->redisplay_queued)
598 /* If the timer has fired, or it's been long enough since the last
599 update, redisplay everything now. */
601 if (!screenRec->redisplay_expired)
603 CARD32 now = GetTimeInMillis ();
605 if (screenRec->last_redisplay + REDISPLAY_MAX_DELAY >= now)
609 if (screenRec->redisplay_timer_set)
611 TimerCancel (screenRec->redisplay_timer);
612 screenRec->redisplay_timer_set = FALSE;
615 RootlessRedisplayScreen (screenRec->pScreen);
616 screenRec->redisplay_expired = FALSE;
621 /* Flush drawing before blocking on select(). */
623 RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask)
625 ScreenPtr pScreen = pbdata;
626 RootlessScreenRec *screenRec = SCREENREC (pScreen);
628 if (screenRec->redisplay_expired)
630 screenRec->redisplay_expired = FALSE;
632 if (screenRec->colormap_changed)
634 RootlessFlushScreenColormaps (screenRec->pScreen);
635 screenRec->colormap_changed = FALSE;
638 RootlessRedisplayScreen (screenRec->pScreen);
643 RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask)
648 RootlessAllocatePrivates(ScreenPtr pScreen)
650 RootlessScreenRec *s;
651 static unsigned int rootlessGeneration = -1;
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;
663 /* no allocation needed for screen privates */
664 if (!AllocateGCPrivate(pScreen, rootlessGCPrivateIndex,
665 sizeof(RootlessGCRec)))
667 if (!AllocateWindowPrivate(pScreen, rootlessWindowPrivateIndex, 0))
670 s = xalloc(sizeof(RootlessScreenRec));
671 if (! s) return FALSE;
672 SCREENREC(pScreen) = s;
674 s->pixmap_data = NULL;
675 s->pixmap_data_size = 0;
677 s->redisplay_timer = NULL;
678 s->redisplay_timer_set = FALSE;
684 RootlessWrap(ScreenPtr pScreen)
686 RootlessScreenRec *s = (RootlessScreenRec*)
687 pScreen->devPrivates[rootlessScreenPrivateIndex].ptr;
693 RL_DEBUG_MSG("null screen fn " #a "\n"); \
696 pScreen->a = Rootless##a
698 WRAP(CreateScreenResources);
701 WRAP(PaintWindowBackground);
702 WRAP(PaintWindowBorder);
705 WRAP(SourceValidate);
709 WRAP(UnrealizeWindow);
710 WRAP(ReparentWindow);
712 WRAP(PositionWindow);
715 WRAP(ChangeBorderWidth);
716 WRAP(MarkOverlappedWindows);
718 WRAP(ChangeWindowAttributes);
719 WRAP(InstallColormap);
720 WRAP(UninstallColormap);
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;
738 // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
739 // WRAP(RestoreAreas); fixme put this back?
745 RootlessSetupScreen(int index, ScreenPtr pScreen)
747 RootlessScreenRec *s;
749 /* Add replacements for fb screen functions */
750 pScreen->PaintWindowBackground = RootlessPaintWindow;
751 pScreen->PaintWindowBorder = RootlessPaintWindow;
755 PictureScreenPtr ps = GetPictureScreen(pScreen);
756 ps->Composite = RootlessComposite;
760 if (!RootlessAllocatePrivates(pScreen))
763 s = ((RootlessScreenRec*)
764 pScreen->devPrivates[rootlessScreenPrivateIndex].ptr);
766 s->pScreen = pScreen;
767 RootlessWrap(pScreen);
769 if (!RegisterBlockAndWakeupHandlers (RootlessBlockHandler,
770 RootlessWakeupHandler,
780 RootlessUpdateRooted (Bool state)
786 for (i = 0; i < screenInfo.numScreens; i++)
787 RootlessDisableRoot (screenInfo.screens[i]);
791 for (i = 0; i < screenInfo.numScreens; i++)
792 RootlessEnableRoot (screenInfo.screens[i]);