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.
32 #ifdef HAVE_DIX_CONFIG_H
33 #include <dix-config.h>
37 #include "scrnintstr.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"
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 DevPrivateKeyRec rootlessGCPrivateKeyRec
;
65 DevPrivateKeyRec rootlessScreenPrivateKeyRec
;
66 DevPrivateKeyRec rootlessWindowPrivateKeyRec
;
67 DevPrivateKeyRec rootlessWindowOldPixmapPrivateKeyRec
;
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
, 0);
88 (*pScreen
->SetScreenPixmap
) (pPix
);
91 rowbytes
= PixmapBytePad(pScreen
->width
, pScreen
->rootDepth
);
93 if (s
->pixmap_data_size
< rowbytes
) {
96 s
->pixmap_data_size
= rowbytes
;
97 s
->pixmap_data
= malloc(s
->pixmap_data_size
);
98 if (s
->pixmap_data
== NULL
)
101 memset(s
->pixmap_data
, 0xFF, s
->pixmap_data_size
);
103 pScreen
->ModifyPixmapHeader(pPix
, pScreen
->width
, pScreen
->height
,
105 BitsPerPixel(pScreen
->rootDepth
),
107 /* ModifyPixmapHeader ignores zero arguments, so install rowbytes
114 * RootlessCreateScreenResources
115 * Rootless implementations typically set a null framebuffer pointer, which
116 * causes problems with miCreateScreenResources. We fix things up here.
119 RootlessCreateScreenResources(ScreenPtr pScreen
)
123 SCREEN_UNWRAP(pScreen
, CreateScreenResources
);
125 if (pScreen
->CreateScreenResources
!= NULL
)
126 ret
= (*pScreen
->CreateScreenResources
) (pScreen
);
128 SCREEN_WRAP(pScreen
, CreateScreenResources
);
133 /* Make sure we have a valid screen pixmap. */
135 RootlessUpdateScreenPixmap(pScreen
);
141 RootlessCloseScreen(ScreenPtr pScreen
)
143 RootlessScreenRec
*s
;
145 s
= SCREENREC(pScreen
);
147 // fixme unwrap everything that was wrapped?
148 pScreen
->CloseScreen
= s
->CloseScreen
;
150 if (s
->pixmap_data
!= NULL
) {
151 free(s
->pixmap_data
);
152 s
->pixmap_data
= NULL
;
153 s
->pixmap_data_size
= 0;
157 return pScreen
->CloseScreen(pScreen
);
161 RootlessGetImage(DrawablePtr pDrawable
, int sx
, int sy
, int w
, int h
,
162 unsigned int format
, unsigned long planeMask
, char *pdstLine
)
164 ScreenPtr pScreen
= pDrawable
->pScreen
;
166 SCREEN_UNWRAP(pScreen
, GetImage
);
168 if (pDrawable
->type
== DRAWABLE_WINDOW
) {
170 RootlessWindowRec
*winRec
;
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
);
176 // RedisplayScreen stops drawing, so we need to start it again
177 RootlessStartDrawing((WindowPtr
) pDrawable
);
179 /* Check that we have some place to read from. */
180 winRec
= WINREC(TopLevelParent((WindowPtr
) pDrawable
));
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. */
189 x0
= pDrawable
->x
+ sx
;
190 y0
= pDrawable
->y
+ sy
;
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
);
199 sx
= x0
- pDrawable
->x
;
200 sy
= y0
- pDrawable
->y
;
204 if (w
<= 0 || h
<= 0)
208 pScreen
->GetImage(pDrawable
, sx
, sy
, w
, h
, format
, planeMask
, pdstLine
);
211 SCREEN_WRAP(pScreen
, GetImage
);
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.
222 RootlessSourceValidate(DrawablePtr pDrawable
, int x
, int y
, int w
, int h
,
223 unsigned int subWindowMode
)
225 SCREEN_UNWRAP(pDrawable
->pScreen
, SourceValidate
);
226 if (pDrawable
->type
== DRAWABLE_WINDOW
) {
227 WindowPtr pWin
= (WindowPtr
) pDrawable
;
229 RootlessStartDrawing(pWin
);
231 if (pDrawable
->pScreen
->SourceValidate
) {
232 pDrawable
->pScreen
->SourceValidate(pDrawable
, x
, y
, w
, h
,
235 SCREEN_WRAP(pDrawable
->pScreen
, SourceValidate
);
239 RootlessComposite(CARD8 op
, PicturePtr pSrc
, PicturePtr pMask
, PicturePtr pDst
,
240 INT16 xSrc
, INT16 ySrc
, INT16 xMask
, INT16 yMask
,
241 INT16 xDst
, INT16 yDst
, CARD16 width
, CARD16 height
)
243 ScreenPtr pScreen
= pDst
->pDrawable
->pScreen
;
244 PictureScreenPtr ps
= GetPictureScreen(pScreen
);
245 WindowPtr srcWin
, dstWin
, maskWin
= NULL
;
247 if (pMask
) { // pMask can be NULL
248 maskWin
= (pMask
->pDrawable
&&
249 pMask
->pDrawable
->type
==
250 DRAWABLE_WINDOW
) ? (WindowPtr
) pMask
->pDrawable
: NULL
;
252 srcWin
= (pSrc
->pDrawable
&& pSrc
->pDrawable
->type
== DRAWABLE_WINDOW
) ?
253 (WindowPtr
) pSrc
->pDrawable
: NULL
;
254 dstWin
= (pDst
->pDrawable
->type
== DRAWABLE_WINDOW
) ?
255 (WindowPtr
) pDst
->pDrawable
: NULL
;
257 // SCREEN_UNWRAP(ps, Composite);
258 ps
->Composite
= SCREENREC(pScreen
)->Composite
;
260 if (srcWin
&& IsFramedWindow(srcWin
))
261 RootlessStartDrawing(srcWin
);
262 if (maskWin
&& IsFramedWindow(maskWin
))
263 RootlessStartDrawing(maskWin
);
264 if (dstWin
&& IsFramedWindow(dstWin
))
265 RootlessStartDrawing(dstWin
);
267 ps
->Composite(op
, pSrc
, pMask
, pDst
,
268 xSrc
, ySrc
, xMask
, yMask
, xDst
, yDst
, width
, height
);
270 if (dstWin
&& IsFramedWindow(dstWin
)) {
271 RootlessDamageRect(dstWin
, xDst
, yDst
, width
, height
);
274 ps
->Composite
= RootlessComposite
;
275 // SCREEN_WRAP(ps, Composite);
279 RootlessGlyphs(CARD8 op
, PicturePtr pSrc
, PicturePtr pDst
,
280 PictFormatPtr maskFormat
, INT16 xSrc
, INT16 ySrc
,
281 int nlist
, GlyphListPtr list
, GlyphPtr
* glyphs
)
283 ScreenPtr pScreen
= pDst
->pDrawable
->pScreen
;
284 PictureScreenPtr ps
= GetPictureScreen(pScreen
);
288 WindowPtr srcWin
, dstWin
;
290 srcWin
= (pSrc
->pDrawable
&& pSrc
->pDrawable
->type
== DRAWABLE_WINDOW
) ?
291 (WindowPtr
) pSrc
->pDrawable
: NULL
;
292 dstWin
= (pDst
->pDrawable
->type
== DRAWABLE_WINDOW
) ?
293 (WindowPtr
) pDst
->pDrawable
: NULL
;
295 if (srcWin
&& IsFramedWindow(srcWin
))
296 RootlessStartDrawing(srcWin
);
297 if (dstWin
&& IsFramedWindow(dstWin
))
298 RootlessStartDrawing(dstWin
);
300 //SCREEN_UNWRAP(ps, Glyphs);
301 ps
->Glyphs
= SCREENREC(pScreen
)->Glyphs
;
302 ps
->Glyphs(op
, pSrc
, pDst
, maskFormat
, xSrc
, ySrc
, nlist
, list
, glyphs
);
303 ps
->Glyphs
= RootlessGlyphs
;
304 //SCREEN_WRAP(ps, Glyphs);
306 if (dstWin
&& IsFramedWindow(dstWin
)) {
315 /* Calling DamageRect for the bounding box of each glyph is
316 inefficient. So compute the union of all glyphs in a list
324 box
.x1
= x
- glyph
->info
.x
;
325 box
.y1
= y
- glyph
->info
.y
;
326 box
.x2
= box
.x1
+ glyph
->info
.width
;
327 box
.y2
= box
.y1
+ glyph
->info
.height
;
329 x
+= glyph
->info
.xOff
;
330 y
+= glyph
->info
.yOff
;
333 short x1
, y1
, x2
, y2
;
337 x1
= x
- glyph
->info
.x
;
338 y1
= y
- glyph
->info
.y
;
339 x2
= x1
+ glyph
->info
.width
;
340 y2
= y1
+ glyph
->info
.height
;
342 box
.x1
= max(box
.x1
, x1
);
343 box
.y1
= max(box
.y1
, y1
);
344 box
.x2
= max(box
.x2
, x2
);
345 box
.y2
= max(box
.y2
, y2
);
347 x
+= glyph
->info
.xOff
;
348 y
+= glyph
->info
.yOff
;
351 RootlessDamageBox(dstWin
, &box
);
359 * RootlessValidateTree
360 * ValidateTree is modified in two ways:
361 * - top-level windows don't clip each other
362 * - windows aren't clipped against root.
363 * These only matter when validating from the root.
366 RootlessValidateTree(WindowPtr pParent
, WindowPtr pChild
, VTKind kind
)
370 ScreenPtr pScreen
= pParent
->drawable
.pScreen
;
372 SCREEN_UNWRAP(pScreen
, ValidateTree
);
373 RL_DEBUG_MSG("VALIDATETREE start ");
375 // Use our custom version to validate from root
376 if (IsRoot(pParent
)) {
377 RL_DEBUG_MSG("custom ");
378 result
= RootlessMiValidateTree(pParent
, pChild
, kind
);
382 result
= pScreen
->ValidateTree(pParent
, pChild
, kind
);
383 NORMAL_ROOT(pParent
);
386 SCREEN_WRAP(pScreen
, ValidateTree
);
387 RL_DEBUG_MSG("VALIDATETREE end\n");
393 * RootlessMarkOverlappedWindows
394 * MarkOverlappedWindows is modified to ignore overlapping
398 RootlessMarkOverlappedWindows(WindowPtr pWin
, WindowPtr pFirst
,
399 WindowPtr
*ppLayerWin
)
403 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
405 SCREEN_UNWRAP(pScreen
, MarkOverlappedWindows
);
406 RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
410 // root - mark nothing
411 RL_DEBUG_MSG("is root not marking ");
414 else if (!IsTopLevel(pWin
)) {
415 // not top-level window - mark normally
416 result
= pScreen
->MarkOverlappedWindows(pWin
, pFirst
, ppLayerWin
);
419 //top-level window - mark children ONLY - NO overlaps with sibs (?)
420 // This code copied from miMarkOverlappedWindows()
422 register WindowPtr pChild
;
423 Bool anyMarked
= FALSE
;
424 MarkWindowProcPtr MarkWindow
= pScreen
->MarkWindow
;
426 RL_DEBUG_MSG("is top level! ");
427 /* single layered systems are easy */
431 if (pWin
== pFirst
) {
432 /* Blindly mark pWin and all of its inferiors. This is a slight
433 * overkill if there are mapped windows that outside pWin's border,
434 * but it's better than wasting time on RectIn checks.
438 if (pChild
->viewable
) {
439 if (RegionBroken(&pChild
->winSize
))
441 if (RegionBroken(&pChild
->borderSize
))
442 SetBorderSize(pChild
);
443 (*MarkWindow
) (pChild
);
444 if (pChild
->firstChild
) {
445 pChild
= pChild
->firstChild
;
449 while (!pChild
->nextSib
&& (pChild
!= pWin
))
450 pChild
= pChild
->parent
;
453 pChild
= pChild
->nextSib
;
458 (*MarkWindow
) (pWin
->parent
);
462 SCREEN_WRAP(pScreen
, MarkOverlappedWindows
);
463 RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
469 expose_1(WindowPtr pWin
)
476 miPaintWindow(pWin
, &pWin
->borderClip
, PW_BACKGROUND
);
478 /* FIXME: comments in windowstr.h indicate that borderClip doesn't
479 include subwindow visibility. But I'm not so sure.. so we may
480 be exposing too much.. */
482 miSendExposures(pWin
, &pWin
->borderClip
,
483 pWin
->drawable
.x
, pWin
->drawable
.y
);
485 for (pChild
= pWin
->firstChild
; pChild
!= NULL
; pChild
= pChild
->nextSib
)
490 RootlessScreenExpose(ScreenPtr pScreen
)
492 expose_1(pScreen
->root
);
496 RootlessGetColormap(ScreenPtr pScreen
)
498 RootlessScreenRec
*s
= SCREENREC(pScreen
);
504 RootlessInstallColormap(ColormapPtr pMap
)
506 ScreenPtr pScreen
= pMap
->pScreen
;
507 RootlessScreenRec
*s
= SCREENREC(pScreen
);
509 SCREEN_UNWRAP(pScreen
, InstallColormap
);
511 if (s
->colormap
!= pMap
) {
513 s
->colormap_changed
= TRUE
;
514 RootlessQueueRedisplay(pScreen
);
517 pScreen
->InstallColormap(pMap
);
519 SCREEN_WRAP(pScreen
, InstallColormap
);
523 RootlessUninstallColormap(ColormapPtr pMap
)
525 ScreenPtr pScreen
= pMap
->pScreen
;
526 RootlessScreenRec
*s
= SCREENREC(pScreen
);
528 SCREEN_UNWRAP(pScreen
, UninstallColormap
);
530 if (s
->colormap
== pMap
)
533 pScreen
->UninstallColormap(pMap
);
535 SCREEN_WRAP(pScreen
, UninstallColormap
);
539 RootlessStoreColors(ColormapPtr pMap
, int ndef
, xColorItem
* pdef
)
541 ScreenPtr pScreen
= pMap
->pScreen
;
542 RootlessScreenRec
*s
= SCREENREC(pScreen
);
544 SCREEN_UNWRAP(pScreen
, StoreColors
);
546 if (s
->colormap
== pMap
&& ndef
> 0) {
547 s
->colormap_changed
= TRUE
;
548 RootlessQueueRedisplay(pScreen
);
551 pScreen
->StoreColors(pMap
, ndef
, pdef
);
553 SCREEN_WRAP(pScreen
, StoreColors
);
557 RootlessRedisplayCallback(OsTimerPtr timer
, CARD32 time
, void *arg
)
559 RootlessScreenRec
*screenRec
= arg
;
561 if (!screenRec
->redisplay_queued
) {
562 /* No update needed. Stop the timer. */
564 screenRec
->redisplay_timer_set
= FALSE
;
568 screenRec
->redisplay_queued
= FALSE
;
570 /* Mark that we should redisplay before waiting for I/O next time */
571 screenRec
->redisplay_expired
= TRUE
;
573 /* Reinstall the timer immediately, so we get as close to our
574 redisplay interval as possible. */
576 return ROOTLESS_REDISPLAY_DELAY
;
580 * RootlessQueueRedisplay
581 * Queue a redisplay after a timer delay to ensure we do not redisplay
585 RootlessQueueRedisplay(ScreenPtr pScreen
)
587 RootlessScreenRec
*screenRec
= SCREENREC(pScreen
);
589 screenRec
->redisplay_queued
= TRUE
;
591 if (screenRec
->redisplay_timer_set
)
594 screenRec
->redisplay_timer
= TimerSet(screenRec
->redisplay_timer
,
595 0, ROOTLESS_REDISPLAY_DELAY
,
596 RootlessRedisplayCallback
, screenRec
);
597 screenRec
->redisplay_timer_set
= TRUE
;
601 * RootlessBlockHandler
602 * If the redisplay timer has expired, flush drawing before blocking
606 RootlessBlockHandler(pointer pbdata
, OSTimePtr pTimeout
, pointer pReadmask
)
608 ScreenPtr pScreen
= pbdata
;
609 RootlessScreenRec
*screenRec
= SCREENREC(pScreen
);
611 if (screenRec
->redisplay_expired
) {
612 screenRec
->redisplay_expired
= FALSE
;
614 RootlessRedisplayScreen(pScreen
);
619 RootlessWakeupHandler(pointer data
, int i
, pointer LastSelectMask
)
625 RootlessAllocatePrivates(ScreenPtr pScreen
)
627 RootlessScreenRec
*s
;
629 if (!dixRegisterPrivateKey
630 (&rootlessGCPrivateKeyRec
, PRIVATE_GC
, sizeof(RootlessGCRec
)))
632 if (!dixRegisterPrivateKey(&rootlessScreenPrivateKeyRec
, PRIVATE_SCREEN
, 0))
634 if (!dixRegisterPrivateKey(&rootlessWindowPrivateKeyRec
, PRIVATE_WINDOW
, 0))
636 if (!dixRegisterPrivateKey
637 (&rootlessWindowOldPixmapPrivateKeyRec
, PRIVATE_WINDOW
, 0))
640 s
= malloc(sizeof(RootlessScreenRec
));
643 SETSCREENREC(pScreen
, s
);
645 s
->pixmap_data
= NULL
;
646 s
->pixmap_data_size
= 0;
648 s
->redisplay_timer
= NULL
;
649 s
->redisplay_timer_set
= FALSE
;
655 RootlessWrap(ScreenPtr pScreen
)
657 RootlessScreenRec
*s
= SCREENREC(pScreen
);
663 RL_DEBUG_MSG("null screen fn " #a "\n"); \
666 pScreen->a = Rootless##a
668 WRAP(CreateScreenResources
);
673 WRAP(SourceValidate
);
677 WRAP(UnrealizeWindow
);
679 WRAP(PositionWindow
);
682 WRAP(ReparentWindow
);
683 WRAP(ChangeBorderWidth
);
684 WRAP(MarkOverlappedWindows
);
686 WRAP(ChangeWindowAttributes
);
687 WRAP(InstallColormap
);
688 WRAP(UninstallColormap
);
694 // Composite and Glyphs don't use normal screen wrapping
695 PictureScreenPtr ps
= GetPictureScreen(pScreen
);
697 s
->Composite
= ps
->Composite
;
698 ps
->Composite
= RootlessComposite
;
699 s
->Glyphs
= ps
->Glyphs
;
700 ps
->Glyphs
= RootlessGlyphs
;
703 // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
710 * Called by the rootless implementation to initialize the rootless layer.
711 * Rootless wraps lots of stuff and needs a bunch of devPrivates.
714 RootlessInit(ScreenPtr pScreen
, RootlessFrameProcsPtr procs
)
716 RootlessScreenRec
*s
;
718 if (!RootlessAllocatePrivates(pScreen
))
721 s
= SCREENREC(pScreen
);
725 s
->redisplay_expired
= FALSE
;
727 RootlessWrap(pScreen
);
729 if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler
,
730 RootlessWakeupHandler
,
731 (pointer
) pScreen
)) {
739 RootlessUpdateRooted(Bool state
)
744 for (i
= 0; i
< screenInfo
.numScreens
; i
++)
745 RootlessDisableRoot(screenInfo
.screens
[i
]);
748 for (i
= 0; i
< screenInfo
.numScreens
; i
++)
749 RootlessEnableRoot(screenInfo
.screens
[i
]);