2 * Screen routines for generic rootless X server
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>
38 #include "scrnintstr.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>
51 #include "rootlessCommon.h"
52 #include "rootlessWindow.h"
55 #ifndef ROOTLESS_REDISPLAY_DELAY
56 #define ROOTLESS_REDISPLAY_DELAY 10
59 extern int RootlessMiValidateTree(WindowPtr pRoot
, WindowPtr pChild
,
61 extern Bool
RootlessCreateGC(GCPtr pGC
);
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).
79 RootlessUpdateScreenPixmap(ScreenPtr pScreen
)
81 RootlessScreenRec
*s
= SCREENREC(pScreen
);
83 unsigned int rowbytes
;
85 pPix
= (*pScreen
->GetScreenPixmap
)(pScreen
);
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
)
102 memset(s
->pixmap_data
, 0xFF, s
->pixmap_data_size
);
104 pScreen
->ModifyPixmapHeader(pPix
, pScreen
->width
, pScreen
->height
,
106 BitsPerPixel(pScreen
->rootDepth
),
108 /* ModifyPixmapHeader ignores zero arguments, so install rowbytes
116 * RootlessCreateScreenResources
117 * Rootless implementations typically set a null framebuffer pointer, which
118 * causes problems with miCreateScreenResources. We fix things up here.
121 RootlessCreateScreenResources(ScreenPtr pScreen
)
125 SCREEN_UNWRAP(pScreen
, CreateScreenResources
);
127 if (pScreen
->CreateScreenResources
!= NULL
)
128 ret
= (*pScreen
->CreateScreenResources
)(pScreen
);
130 SCREEN_WRAP(pScreen
, CreateScreenResources
);
135 /* Make sure we have a valid screen pixmap. */
137 RootlessUpdateScreenPixmap(pScreen
);
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;
160 return pScreen
->CloseScreen(i
, pScreen
);
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
) {
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
));
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
;
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
;
207 if (w
<= 0 || h
<= 0)
211 pScreen
->GetImage(pDrawable
, sx
, sy
, w
, h
, format
, planeMask
, pdstLine
);
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.
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
);
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);
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
);
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
)) {
317 /* Calling DamageRect for the bounding box of each glyph is
318 inefficient. So compute the union of all glyphs in a list
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
;
335 short x1
, y1
, x2
, y2
;
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
);
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.
371 RootlessValidateTree(WindowPtr pParent
, WindowPtr pChild
, VTKind kind
)
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
);
386 result
= pScreen
->ValidateTree(pParent
, pChild
, kind
);
387 NORMAL_ROOT(pParent
);
390 SCREEN_WRAP(pScreen
, ValidateTree
);
391 RL_DEBUG_MSG("VALIDATETREE end\n");
398 * RootlessMarkOverlappedWindows
399 * MarkOverlappedWindows is modified to ignore overlapping
403 RootlessMarkOverlappedWindows(WindowPtr pWin
, WindowPtr pFirst
,
404 WindowPtr
*ppLayerWin
)
408 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
409 SCREEN_UNWRAP(pScreen
, MarkOverlappedWindows
);
410 RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
414 // root - mark nothing
415 RL_DEBUG_MSG("is root not marking ");
418 else if (! IsTopLevel(pWin
)) {
419 // not top-level window - mark normally
420 result
= pScreen
->MarkOverlappedWindows(pWin
, pFirst
, ppLayerWin
);
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.
441 if (pChild
->viewable
) {
442 if (REGION_BROKEN (pScreen
, &pChild
->winSize
))
444 if (REGION_BROKEN (pScreen
, &pChild
->borderSize
))
445 SetBorderSize (pChild
);
446 (* MarkWindow
)(pChild
);
447 if (pChild
->firstChild
) {
448 pChild
= pChild
->firstChild
;
452 while (!pChild
->nextSib
&& (pChild
!= pWin
))
453 pChild
= pChild
->parent
;
456 pChild
= pChild
->nextSib
;
459 pFirst
= pFirst
->nextSib
;
462 (* MarkWindow
)(pWin
->parent
);
466 SCREEN_WRAP(pScreen
, MarkOverlappedWindows
);
467 RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
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
;
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
503 RootlessQueueRedisplay(ScreenPtr pScreen
)
505 RootlessScreenRec
*screenRec
= SCREENREC(pScreen
);
507 screenRec
->redisplay_queued
= TRUE
;
509 if (screenRec
->redisplay_timer_set
)
512 screenRec
->redisplay_timer
= TimerSet(screenRec
->redisplay_timer
,
513 0, ROOTLESS_REDISPLAY_DELAY
,
514 RootlessRedisplayCallback
,
516 screenRec
->redisplay_timer_set
= TRUE
;
521 * RootlessBlockHandler
522 * If the redisplay timer has expired, flush drawing before blocking
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
);
540 RootlessWakeupHandler(pointer data
, int i
, pointer LastSelectMask
)
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
)))
566 if (!AllocateWindowPrivate(pScreen
, rootlessWindowPrivateIndex
, 0))
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
;
584 RootlessWrap(ScreenPtr pScreen
)
586 RootlessScreenRec
*s
= (RootlessScreenRec
*)
587 pScreen
->devPrivates
[rootlessScreenPrivateIndex
].ptr
;
593 RL_DEBUG_MSG("null screen fn " #a "\n"); \
596 pScreen->a = Rootless##a
598 WRAP(CreateScreenResources
);
601 WRAP(PaintWindowBackground
);
602 WRAP(PaintWindowBorder
);
605 WRAP(SourceValidate
);
609 WRAP(UnrealizeWindow
);
611 WRAP(PositionWindow
);
614 WRAP(ReparentWindow
);
615 WRAP(ChangeBorderWidth
);
616 WRAP(MarkOverlappedWindows
);
618 WRAP(ChangeWindowAttributes
);
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
;
635 // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
636 // WRAP(RestoreAreas); fixme put this back?
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
))
654 s
= (RootlessScreenRec
*)
655 pScreen
->devPrivates
[rootlessScreenPrivateIndex
].ptr
;
659 RootlessWrap(pScreen
);
661 if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler
,
662 RootlessWakeupHandler
,