First import
[xorg_rtime.git] / xorg-server-1.4 / miext / rootless / rootlessScreen.c
blob356fec79855e0a0e37c755027c000ea93f459352
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.
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:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
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.
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.
33 #ifdef HAVE_DIX_CONFIG_H
34 #include <dix-config.h>
35 #endif
37 #include "mi.h"
38 #include "scrnintstr.h"
39 #include "gcstruct.h"
40 #include "pixmapstr.h"
41 #include "windowstr.h"
42 #include "propertyst.h"
43 #include "mivalidate.h"
44 #include "picturestr.h"
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #include <string.h>
51 #include "rootlessCommon.h"
52 #include "rootlessWindow.h"
54 /* In milliseconds */
55 #ifndef ROOTLESS_REDISPLAY_DELAY
56 #define ROOTLESS_REDISPLAY_DELAY 10
57 #endif
59 extern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild,
60 VTKind kind);
61 extern Bool RootlessCreateGC(GCPtr pGC);
63 // Initialize globals
64 int rootlessGCPrivateIndex = -1;
65 int rootlessScreenPrivateIndex = -1;
66 int rootlessWindowPrivateIndex = -1;
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).
78 void
79 RootlessUpdateScreenPixmap(ScreenPtr pScreen)
81 RootlessScreenRec *s = SCREENREC(pScreen);
82 PixmapPtr pPix;
83 unsigned int rowbytes;
85 pPix = (*pScreen->GetScreenPixmap)(pScreen);
86 if (pPix == NULL) {
87 pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth);
88 (*pScreen->SetScreenPixmap)(pPix);
91 rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth);
93 if (s->pixmap_data_size < rowbytes) {
94 if (s->pixmap_data != NULL)
95 xfree(s->pixmap_data);
97 s->pixmap_data_size = rowbytes;
98 s->pixmap_data = xalloc(s->pixmap_data_size);
99 if (s->pixmap_data == NULL)
100 return;
102 memset(s->pixmap_data, 0xFF, s->pixmap_data_size);
104 pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height,
105 pScreen->rootDepth,
106 BitsPerPixel(pScreen->rootDepth),
107 0, s->pixmap_data);
108 /* ModifyPixmapHeader ignores zero arguments, so install rowbytes
109 by hand. */
110 pPix->devKind = 0;
116 * RootlessCreateScreenResources
117 * Rootless implementations typically set a null framebuffer pointer, which
118 * causes problems with miCreateScreenResources. We fix things up here.
120 static Bool
121 RootlessCreateScreenResources(ScreenPtr pScreen)
123 Bool ret = TRUE;
125 SCREEN_UNWRAP(pScreen, CreateScreenResources);
127 if (pScreen->CreateScreenResources != NULL)
128 ret = (*pScreen->CreateScreenResources)(pScreen);
130 SCREEN_WRAP(pScreen, CreateScreenResources);
132 if (!ret)
133 return ret;
135 /* Make sure we have a valid screen pixmap. */
137 RootlessUpdateScreenPixmap(pScreen);
139 return ret;
143 static Bool
144 RootlessCloseScreen(int i, ScreenPtr pScreen)
146 RootlessScreenRec *s;
148 s = SCREENREC(pScreen);
150 // fixme unwrap everything that was wrapped?
151 pScreen->CloseScreen = s->CloseScreen;
153 if (s->pixmap_data != NULL) {
154 xfree (s->pixmap_data);
155 s->pixmap_data = NULL;
156 s->pixmap_data_size = 0;
159 xfree(s);
160 return pScreen->CloseScreen(i, pScreen);
164 static void
165 RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
166 unsigned int format, unsigned long planeMask, char *pdstLine)
168 ScreenPtr pScreen = pDrawable->pScreen;
169 SCREEN_UNWRAP(pScreen, GetImage);
171 if (pDrawable->type == DRAWABLE_WINDOW) {
172 int x0, y0, x1, y1;
173 RootlessWindowRec *winRec;
175 // Many apps use GetImage to sync with the visible frame buffer
176 // FIXME: entire screen or just window or all screens?
177 RootlessRedisplayScreen(pScreen);
179 // RedisplayScreen stops drawing, so we need to start it again
180 RootlessStartDrawing((WindowPtr)pDrawable);
182 /* Check that we have some place to read from. */
183 winRec = WINREC(TopLevelParent((WindowPtr) pDrawable));
184 if (winRec == NULL)
185 goto out;
187 /* Clip to top-level window bounds. */
188 /* FIXME: fbGetImage uses the width parameter to calculate the
189 stride of the destination pixmap. If w is clipped, the data
190 returned will be garbage, although we will not crash. */
192 x0 = pDrawable->x + sx;
193 y0 = pDrawable->y + sy;
194 x1 = x0 + w;
195 y1 = y0 + h;
197 x0 = MAX (x0, winRec->x);
198 y0 = MAX (y0, winRec->y);
199 x1 = MIN (x1, winRec->x + winRec->width);
200 y1 = MIN (y1, winRec->y + winRec->height);
202 sx = x0 - pDrawable->x;
203 sy = y0 - pDrawable->y;
204 w = x1 - x0;
205 h = y1 - y0;
207 if (w <= 0 || h <= 0)
208 goto out;
211 pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
213 out:
214 SCREEN_WRAP(pScreen, GetImage);
219 * RootlessSourceValidate
220 * CopyArea and CopyPlane use a GC tied to the destination drawable.
221 * StartDrawing/StopDrawing wrappers won't be called if source is
222 * a visible window but the destination isn't. So, we call StartDrawing
223 * here and leave StopDrawing for the block handler.
225 static void
226 RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h)
228 SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate);
229 if (pDrawable->type == DRAWABLE_WINDOW) {
230 WindowPtr pWin = (WindowPtr)pDrawable;
231 RootlessStartDrawing(pWin);
233 if (pDrawable->pScreen->SourceValidate) {
234 pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h);
236 SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
239 #ifdef RENDER
241 static void
242 RootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
243 INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask,
244 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
246 ScreenPtr pScreen = pDst->pDrawable->pScreen;
247 PictureScreenPtr ps = GetPictureScreen(pScreen);
248 WindowPtr srcWin, dstWin, maskWin = NULL;
250 if (pMask) { // pMask can be NULL
251 maskWin = (pMask->pDrawable->type == DRAWABLE_WINDOW) ?
252 (WindowPtr)pMask->pDrawable : NULL;
254 srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
255 (WindowPtr)pSrc->pDrawable : NULL;
256 dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
257 (WindowPtr)pDst->pDrawable : NULL;
259 // SCREEN_UNWRAP(ps, Composite);
260 ps->Composite = SCREENREC(pScreen)->Composite;
262 if (srcWin && IsFramedWindow(srcWin))
263 RootlessStartDrawing(srcWin);
264 if (maskWin && IsFramedWindow(maskWin))
265 RootlessStartDrawing(maskWin);
266 if (dstWin && IsFramedWindow(dstWin))
267 RootlessStartDrawing(dstWin);
269 ps->Composite(op, pSrc, pMask, pDst,
270 xSrc, ySrc, xMask, yMask,
271 xDst, yDst, width, height);
273 if (dstWin && IsFramedWindow(dstWin)) {
274 RootlessDamageRect(dstWin, xDst, yDst, width, height);
277 ps->Composite = RootlessComposite;
278 // SCREEN_WRAP(ps, Composite);
282 static void
283 RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
284 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
285 int nlist, GlyphListPtr list, GlyphPtr *glyphs)
287 ScreenPtr pScreen = pDst->pDrawable->pScreen;
288 PictureScreenPtr ps = GetPictureScreen(pScreen);
289 int x, y;
290 int n;
291 GlyphPtr glyph;
292 WindowPtr srcWin, dstWin;
294 srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
295 (WindowPtr)pSrc->pDrawable : NULL;
296 dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
297 (WindowPtr)pDst->pDrawable : NULL;
299 if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin);
300 if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin);
302 //SCREEN_UNWRAP(ps, Glyphs);
303 ps->Glyphs = SCREENREC(pScreen)->Glyphs;
304 ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
305 ps->Glyphs = RootlessGlyphs;
306 //SCREEN_WRAP(ps, Glyphs);
308 if (dstWin && IsFramedWindow(dstWin)) {
309 x = xSrc;
310 y = ySrc;
312 while (nlist--) {
313 x += list->xOff;
314 y += list->yOff;
315 n = list->len;
317 /* Calling DamageRect for the bounding box of each glyph is
318 inefficient. So compute the union of all glyphs in a list
319 and damage that. */
321 if (n > 0) {
322 BoxRec box;
324 glyph = *glyphs++;
326 box.x1 = x - glyph->info.x;
327 box.y1 = y - glyph->info.y;
328 box.x2 = box.x1 + glyph->info.width;
329 box.y2 = box.y2 + glyph->info.height;
331 x += glyph->info.xOff;
332 y += glyph->info.yOff;
334 while (--n > 0) {
335 short x1, y1, x2, y2;
337 glyph = *glyphs++;
339 x1 = x - glyph->info.x;
340 y1 = y - glyph->info.y;
341 x2 = x1 + glyph->info.width;
342 y2 = y1 + glyph->info.height;
344 box.x1 = MAX (box.x1, x1);
345 box.y1 = MAX (box.y1, y1);
346 box.x2 = MAX (box.x2, x2);
347 box.y2 = MAX (box.y2, y2);
349 x += glyph->info.xOff;
350 y += glyph->info.yOff;
353 RootlessDamageBox(dstWin, &box);
355 list++;
360 #endif // RENDER
364 * RootlessValidateTree
365 * ValidateTree is modified in two ways:
366 * - top-level windows don't clip each other
367 * - windows aren't clipped against root.
368 * These only matter when validating from the root.
370 static int
371 RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
373 int result;
374 RegionRec saveRoot;
375 ScreenPtr pScreen = pParent->drawable.pScreen;
377 SCREEN_UNWRAP(pScreen, ValidateTree);
378 RL_DEBUG_MSG("VALIDATETREE start ");
380 // Use our custom version to validate from root
381 if (IsRoot(pParent)) {
382 RL_DEBUG_MSG("custom ");
383 result = RootlessMiValidateTree(pParent, pChild, kind);
384 } else {
385 HUGE_ROOT(pParent);
386 result = pScreen->ValidateTree(pParent, pChild, kind);
387 NORMAL_ROOT(pParent);
390 SCREEN_WRAP(pScreen, ValidateTree);
391 RL_DEBUG_MSG("VALIDATETREE end\n");
393 return result;
398 * RootlessMarkOverlappedWindows
399 * MarkOverlappedWindows is modified to ignore overlapping
400 * top-level windows.
402 static Bool
403 RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
404 WindowPtr *ppLayerWin)
406 RegionRec saveRoot;
407 Bool result;
408 ScreenPtr pScreen = pWin->drawable.pScreen;
409 SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
410 RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
412 HUGE_ROOT(pWin);
413 if (IsRoot(pWin)) {
414 // root - mark nothing
415 RL_DEBUG_MSG("is root not marking ");
416 result = FALSE;
418 else if (! IsTopLevel(pWin)) {
419 // not top-level window - mark normally
420 result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
422 else {
423 //top-level window - mark children ONLY - NO overlaps with sibs (?)
424 // This code copied from miMarkOverlappedWindows()
426 register WindowPtr pChild;
427 Bool anyMarked = FALSE;
428 void (* MarkWindow)() = pScreen->MarkWindow;
430 RL_DEBUG_MSG("is top level! ");
431 /* single layered systems are easy */
432 if (ppLayerWin) *ppLayerWin = pWin;
434 if (pWin == pFirst) {
435 /* Blindly mark pWin and all of its inferiors. This is a slight
436 * overkill if there are mapped windows that outside pWin's border,
437 * but it's better than wasting time on RectIn checks.
439 pChild = pWin;
440 while (1) {
441 if (pChild->viewable) {
442 if (REGION_BROKEN (pScreen, &pChild->winSize))
443 SetWinSize (pChild);
444 if (REGION_BROKEN (pScreen, &pChild->borderSize))
445 SetBorderSize (pChild);
446 (* MarkWindow)(pChild);
447 if (pChild->firstChild) {
448 pChild = pChild->firstChild;
449 continue;
452 while (!pChild->nextSib && (pChild != pWin))
453 pChild = pChild->parent;
454 if (pChild == pWin)
455 break;
456 pChild = pChild->nextSib;
458 anyMarked = TRUE;
459 pFirst = pFirst->nextSib;
461 if (anyMarked)
462 (* MarkWindow)(pWin->parent);
463 result = anyMarked;
465 NORMAL_ROOT(pWin);
466 SCREEN_WRAP(pScreen, MarkOverlappedWindows);
467 RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
469 return result;
473 static CARD32
474 RootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg)
476 RootlessScreenRec *screenRec = arg;
478 if (!screenRec->redisplay_queued) {
479 /* No update needed. Stop the timer. */
481 screenRec->redisplay_timer_set = FALSE;
482 return 0;
485 screenRec->redisplay_queued = FALSE;
487 /* Mark that we should redisplay before waiting for I/O next time */
488 screenRec->redisplay_expired = TRUE;
490 /* Reinstall the timer immediately, so we get as close to our
491 redisplay interval as possible. */
493 return ROOTLESS_REDISPLAY_DELAY;
498 * RootlessQueueRedisplay
499 * Queue a redisplay after a timer delay to ensure we do not redisplay
500 * too frequently.
502 void
503 RootlessQueueRedisplay(ScreenPtr pScreen)
505 RootlessScreenRec *screenRec = SCREENREC(pScreen);
507 screenRec->redisplay_queued = TRUE;
509 if (screenRec->redisplay_timer_set)
510 return;
512 screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer,
513 0, ROOTLESS_REDISPLAY_DELAY,
514 RootlessRedisplayCallback,
515 screenRec);
516 screenRec->redisplay_timer_set = TRUE;
521 * RootlessBlockHandler
522 * If the redisplay timer has expired, flush drawing before blocking
523 * on select().
525 static void
526 RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask)
528 ScreenPtr pScreen = pbdata;
529 RootlessScreenRec *screenRec = SCREENREC(pScreen);
531 if (screenRec->redisplay_expired) {
532 screenRec->redisplay_expired = FALSE;
534 RootlessRedisplayScreen(pScreen);
539 static void
540 RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask)
542 // nothing here
546 static Bool
547 RootlessAllocatePrivates(ScreenPtr pScreen)
549 RootlessScreenRec *s;
550 static unsigned long rootlessGeneration = 0;
552 if (rootlessGeneration != serverGeneration) {
553 rootlessScreenPrivateIndex = AllocateScreenPrivateIndex();
554 if (rootlessScreenPrivateIndex == -1) return FALSE;
555 rootlessGCPrivateIndex = AllocateGCPrivateIndex();
556 if (rootlessGCPrivateIndex == -1) return FALSE;
557 rootlessWindowPrivateIndex = AllocateWindowPrivateIndex();
558 if (rootlessWindowPrivateIndex == -1) return FALSE;
559 rootlessGeneration = serverGeneration;
562 // no allocation needed for screen privates
563 if (!AllocateGCPrivate(pScreen, rootlessGCPrivateIndex,
564 sizeof(RootlessGCRec)))
565 return FALSE;
566 if (!AllocateWindowPrivate(pScreen, rootlessWindowPrivateIndex, 0))
567 return FALSE;
569 s = xalloc(sizeof(RootlessScreenRec));
570 if (! s) return FALSE;
571 SCREENREC(pScreen) = s;
573 s->pixmap_data = NULL;
574 s->pixmap_data_size = 0;
576 s->redisplay_timer = NULL;
577 s->redisplay_timer_set = FALSE;
579 return TRUE;
583 static void
584 RootlessWrap(ScreenPtr pScreen)
586 RootlessScreenRec *s = (RootlessScreenRec*)
587 pScreen->devPrivates[rootlessScreenPrivateIndex].ptr;
589 #define WRAP(a) \
590 if (pScreen->a) { \
591 s->a = pScreen->a; \
592 } else { \
593 RL_DEBUG_MSG("null screen fn " #a "\n"); \
594 s->a = NULL; \
596 pScreen->a = Rootless##a
598 WRAP(CreateScreenResources);
599 WRAP(CloseScreen);
600 WRAP(CreateGC);
601 WRAP(PaintWindowBackground);
602 WRAP(PaintWindowBorder);
603 WRAP(CopyWindow);
604 WRAP(GetImage);
605 WRAP(SourceValidate);
606 WRAP(CreateWindow);
607 WRAP(DestroyWindow);
608 WRAP(RealizeWindow);
609 WRAP(UnrealizeWindow);
610 WRAP(MoveWindow);
611 WRAP(PositionWindow);
612 WRAP(ResizeWindow);
613 WRAP(RestackWindow);
614 WRAP(ReparentWindow);
615 WRAP(ChangeBorderWidth);
616 WRAP(MarkOverlappedWindows);
617 WRAP(ValidateTree);
618 WRAP(ChangeWindowAttributes);
620 #ifdef SHAPE
621 WRAP(SetShape);
622 #endif
624 #ifdef RENDER
626 // Composite and Glyphs don't use normal screen wrapping
627 PictureScreenPtr ps = GetPictureScreen(pScreen);
628 s->Composite = ps->Composite;
629 ps->Composite = RootlessComposite;
630 s->Glyphs = ps->Glyphs;
631 ps->Glyphs = RootlessGlyphs;
633 #endif
635 // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
636 // WRAP(RestoreAreas); fixme put this back?
638 #undef WRAP
643 * RootlessInit
644 * Called by the rootless implementation to initialize the rootless layer.
645 * Rootless wraps lots of stuff and needs a bunch of devPrivates.
647 Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
649 RootlessScreenRec *s;
651 if (!RootlessAllocatePrivates(pScreen))
652 return FALSE;
654 s = (RootlessScreenRec*)
655 pScreen->devPrivates[rootlessScreenPrivateIndex].ptr;
657 s->imp = procs;
659 RootlessWrap(pScreen);
661 if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler,
662 RootlessWakeupHandler,
663 (pointer) pScreen))
665 return FALSE;
668 return TRUE;