2003-11-25 20:29:01 +01:00
/*
* Common rootless definitions and code
*/
/*
* Copyright ( c ) 2001 Greg Parker . All Rights Reserved .
* Copyright ( c ) 2002 - 2003 Torrey T . Lyons . All Rights Reserved .
* Copyright ( c ) 2002 Apple Computer , Inc . All rights reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE ABOVE LISTED COPYRIGHT HOLDER ( S ) BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE .
*
* Except as contained in this notice , the name ( s ) of the above copyright
* holders shall not be used in advertising or otherwise to promote the sale ,
* use or other dealings in this Software without prior written authorization .
*/
2005-07-03 09:02:09 +02:00
# ifdef HAVE_DIX_CONFIG_H
# include <dix-config.h>
# endif
2007-02-16 13:12:26 +01:00
# include <stddef.h> /* For NULL */
# include <limits.h> /* For CHAR_BIT */
2003-11-25 20:29:01 +01:00
# include "rootlessCommon.h"
2007-11-11 13:30:34 +01:00
# include "colormapst.h"
2003-11-25 20:29:01 +01:00
unsigned int rootless_CopyBytes_threshold = 0 ;
unsigned int rootless_FillBytes_threshold = 0 ;
unsigned int rootless_CompositePixels_threshold = 0 ;
unsigned int rootless_CopyWindow_threshold = 0 ;
# ifdef ROOTLESS_GLOBAL_COORDS
int rootlessGlobalOffsetX = 0 ;
int rootlessGlobalOffsetY = 0 ;
# endif
RegionRec rootlessHugeRoot = { { - 32767 , - 32767 , 32767 , 32767 } , NULL } ;
/* Following macro from miregion.c */
/* true iff two Boxes overlap */
# define EXTENTCHECK(r1,r2) \
( ! ( ( ( r1 ) - > x2 < = ( r2 ) - > x1 ) | | \
( ( r1 ) - > x1 > = ( r2 ) - > x2 ) | | \
( ( r1 ) - > y2 < = ( r2 ) - > y1 ) | | \
( ( r1 ) - > y1 > = ( r2 ) - > y2 ) ) )
/*
* TopLevelParent
* Returns the top - level parent of pWindow .
* The root is the top - level parent of itself , even though the root is
* not otherwise considered to be a top - level window .
*/
WindowPtr
TopLevelParent ( WindowPtr pWindow )
{
WindowPtr top ;
if ( IsRoot ( pWindow ) )
return pWindow ;
top = pWindow ;
while ( top & & ! IsTopLevel ( top ) )
top = top - > parent ;
return top ;
}
/*
* IsFramedWindow
* Returns TRUE if this window is visible inside a frame
* ( e . g . it is visible and has a top - level or root parent )
*/
Bool
IsFramedWindow ( WindowPtr pWin )
{
WindowPtr top ;
if ( ! pWin - > realized )
return FALSE ;
top = TopLevelParent ( pWin ) ;
return ( top & & WINREC ( top ) ) ;
}
2007-11-11 13:30:34 +01:00
Bool
RootlessResolveColormap ( ScreenPtr pScreen , int first_color ,
int n_colors , uint32_t * colors )
{
int last , i ;
ColormapPtr map ;
map = RootlessGetColormap ( pScreen ) ;
if ( map = = NULL | | map - > class ! = PseudoColor ) return FALSE ;
last = MIN ( map - > pVisual - > ColormapEntries , first_color + n_colors ) ;
for ( i = MAX ( 0 , first_color ) ; i < last ; i + + ) {
Entry * ent = map - > red + i ;
uint16_t red , green , blue ;
if ( ! ent - > refcnt ) continue ;
if ( ent - > fShared ) {
red = ent - > co . shco . red - > color ;
green = ent - > co . shco . green - > color ;
blue = ent - > co . shco . blue - > color ;
} else {
red = ent - > co . local . red ;
green = ent - > co . local . green ;
blue = ent - > co . local . blue ;
}
colors [ i - first_color ] = ( 0xFF000000UL
| ( ( uint32_t ) red & 0xff00 ) < < 8
| ( green & 0xff00 )
| ( blue > > 8 ) ) ;
}
return TRUE ;
}
2003-11-25 20:29:01 +01:00
/*
* RootlessStartDrawing
* Prepare a window for direct access to its backing buffer .
* Each top - level parent has a Pixmap representing its backing buffer ,
* which all of its children inherit .
*/
void RootlessStartDrawing ( WindowPtr pWindow )
{
ScreenPtr pScreen = pWindow - > drawable . pScreen ;
WindowPtr top = TopLevelParent ( pWindow ) ;
RootlessWindowRec * winRec ;
if ( top = = NULL )
return ;
winRec = WINREC ( top ) ;
if ( winRec = = NULL )
return ;
// Make sure the window's top-level parent is prepared for drawing.
if ( ! winRec - > is_drawing ) {
int bw = wBorderWidth ( top ) ;
SCREENREC ( pScreen ) - > imp - > StartDrawing ( winRec - > wid , & winRec - > pixelData ,
& winRec - > bytesPerRow ) ;
winRec - > pixmap =
GetScratchPixmapHeader ( pScreen , winRec - > width , winRec - > height ,
top - > drawable . depth ,
top - > drawable . bitsPerPixel ,
winRec - > bytesPerRow ,
winRec - > pixelData ) ;
SetPixmapBaseToScreen ( winRec - > pixmap ,
top - > drawable . x - bw , top - > drawable . y - bw ) ;
winRec - > is_drawing = TRUE ;
}
2007-11-15 09:56:54 +01:00
PixmapPtr curPixmap = pScreen - > GetWindowPixmap ( pWindow ) ;
if ( curPixmap = = winRec - > pixmap )
{
RL_DEBUG_MSG ( " Window %p already has winRec->pixmap %p; not pushing \n " , pWindow , winRec - > pixmap ) ;
}
else
{
PixmapPtr oldPixmap = pWindow - > devPrivates [ rootlessWindowOldPixmapPrivateIndex ] . ptr ;
if ( oldPixmap ! = NULL )
{
if ( oldPixmap = = curPixmap )
RL_DEBUG_MSG ( " Window %p's curPixmap %p is the same as its oldPixmap; strange \n " , pWindow , curPixmap ) ;
else
RL_DEBUG_MSG ( " Window %p's existing oldPixmap %p being lost! \n " , pWindow , oldPixmap ) ;
}
pWindow - > devPrivates [ rootlessWindowOldPixmapPrivateIndex ] . ptr = curPixmap ;
pScreen - > SetWindowPixmap ( pWindow , winRec - > pixmap ) ;
}
2003-11-25 20:29:01 +01:00
}
/*
* RootlessStopDrawing
* Stop drawing to a window ' s backing buffer . If flush is true ,
* damaged regions are flushed to the screen .
*/
2007-11-15 09:56:54 +01:00
static int RestorePreDrawingPixmapVisitor ( WindowPtr pWindow , pointer data )
{
RootlessWindowRec * winRec = ( RootlessWindowRec * ) data ;
ScreenPtr pScreen = pWindow - > drawable . pScreen ;
PixmapPtr exPixmap = pScreen - > GetWindowPixmap ( pWindow ) ;
PixmapPtr oldPixmap = pWindow - > devPrivates [ rootlessWindowOldPixmapPrivateIndex ] . ptr ;
if ( oldPixmap = = NULL )
{
if ( exPixmap = = winRec - > pixmap )
RL_DEBUG_MSG ( " Window %p appears to be in drawing mode (ex-pixmap %p equals winRec->pixmap, which is being freed) but has no oldPixmap! \n " , pWindow , exPixmap ) ;
}
else
{
if ( exPixmap ! = winRec - > pixmap )
RL_DEBUG_MSG ( " Window %p appears to be in drawing mode (oldPixmap %p) but ex-pixmap %p not winRec->pixmap %p! \n " , pWindow , oldPixmap , exPixmap , winRec - > pixmap ) ;
if ( oldPixmap = = winRec - > pixmap )
RL_DEBUG_MSG ( " Window %p's oldPixmap %p is winRec->pixmap, which has just been freed! \n " , pWindow , oldPixmap ) ;
pScreen - > SetWindowPixmap ( pWindow , oldPixmap ) ;
pWindow - > devPrivates [ rootlessWindowOldPixmapPrivateIndex ] . ptr = NULL ;
}
return WT_WALKCHILDREN ;
}
2003-11-25 20:29:01 +01:00
void RootlessStopDrawing ( WindowPtr pWindow , Bool flush )
{
ScreenPtr pScreen = pWindow - > drawable . pScreen ;
WindowPtr top = TopLevelParent ( pWindow ) ;
RootlessWindowRec * winRec ;
if ( top = = NULL )
return ;
winRec = WINREC ( top ) ;
if ( winRec = = NULL )
return ;
if ( winRec - > is_drawing ) {
SCREENREC ( pScreen ) - > imp - > StopDrawing ( winRec - > wid , flush ) ;
FreeScratchPixmapHeader ( winRec - > pixmap ) ;
2007-11-15 09:56:54 +01:00
TraverseTree ( top , RestorePreDrawingPixmapVisitor , ( pointer ) winRec ) ;
2003-11-25 20:29:01 +01:00
winRec - > pixmap = NULL ;
winRec - > is_drawing = FALSE ;
}
else if ( flush ) {
SCREENREC ( pScreen ) - > imp - > UpdateRegion ( winRec - > wid , NULL ) ;
}
if ( flush & & winRec - > is_reorder_pending ) {
2004-07-30 21:12:18 +02:00
winRec - > is_reorder_pending = FALSE ;
RootlessReorderWindow ( pWindow ) ;
2003-11-25 20:29:01 +01:00
}
}
/*
* RootlessDamageRegion
* Mark a damaged region as requiring redisplay to screen .
* pRegion is in GLOBAL coordinates .
*/
void
RootlessDamageRegion ( WindowPtr pWindow , RegionPtr pRegion )
{
ScreenPtr pScreen = pWindow - > drawable . pScreen ;
RootlessWindowRec * winRec ;
RegionRec clipped ;
WindowPtr pTop ;
BoxPtr b1 , b2 ;
RL_DEBUG_MSG ( " Damaged win 0x%x " , pWindow ) ;
pTop = TopLevelParent ( pWindow ) ;
if ( pTop = = NULL )
2004-07-30 21:12:18 +02:00
return ;
2003-11-25 20:29:01 +01:00
winRec = WINREC ( pTop ) ;
if ( winRec = = NULL )
2004-07-30 21:12:18 +02:00
return ;
2003-11-25 20:29:01 +01:00
/* We need to intersect the drawn region with the clip of the window
to avoid marking places we didn ' t actually draw ( which can cause
problems when the window has an extra client - side backing store )
But this is a costly operation and since we ' ll normally just be
drawing inside the clip , go to some lengths to avoid the general
case intersection . */
b1 = REGION_EXTENTS ( pScreen , & pWindow - > borderClip ) ;
b2 = REGION_EXTENTS ( pScreen , pRegion ) ;
if ( EXTENTCHECK ( b1 , b2 ) ) {
2004-07-30 21:12:18 +02:00
/* Regions may overlap. */
2003-11-25 20:29:01 +01:00
2004-07-30 21:12:18 +02:00
if ( REGION_NUM_RECTS ( pRegion ) = = 1 ) {
int in ;
2003-11-25 20:29:01 +01:00
2004-07-30 21:12:18 +02:00
/* Damaged region only has a single rect, so we can
just compare that against the region */
2003-11-25 20:29:01 +01:00
2004-07-30 21:12:18 +02:00
in = RECT_IN_REGION ( pScreen , & pWindow - > borderClip ,
2003-11-25 20:29:01 +01:00
REGION_RECTS ( pRegion ) ) ;
2004-07-30 21:12:18 +02:00
if ( in = = rgnIN ) {
/* clip totally contains pRegion */
2003-11-25 20:29:01 +01:00
# ifdef ROOTLESS_TRACK_DAMAGE
REGION_UNION ( pScreen , & winRec - > damage ,
2004-07-30 21:12:18 +02:00
& winRec - > damage , ( pRegion ) ) ;
2003-11-25 20:29:01 +01:00
# else
2004-07-30 21:12:18 +02:00
SCREENREC ( pScreen ) - > imp - > DamageRects ( winRec - > wid ,
2003-11-25 20:29:01 +01:00
REGION_NUM_RECTS ( pRegion ) ,
2004-07-30 21:12:18 +02:00
REGION_RECTS ( pRegion ) ,
- winRec - > x , - winRec - > y ) ;
2003-11-25 20:29:01 +01:00
# endif
2004-07-30 21:12:18 +02:00
RootlessQueueRedisplay ( pTop - > drawable . pScreen ) ;
goto out ;
}
else if ( in = = rgnOUT ) {
/* clip doesn't contain pRegion */
2003-11-25 20:29:01 +01:00
2004-07-30 21:12:18 +02:00
goto out ;
}
}
2003-11-25 20:29:01 +01:00
2004-07-30 21:12:18 +02:00
/* clip overlaps pRegion, need to intersect */
2003-11-25 20:29:01 +01:00
2004-07-30 21:12:18 +02:00
REGION_NULL ( pScreen , & clipped ) ;
REGION_INTERSECT ( pScreen , & clipped , & pWindow - > borderClip , pRegion ) ;
2003-11-25 20:29:01 +01:00
# ifdef ROOTLESS_TRACK_DAMAGE
REGION_UNION ( pScreen , & winRec - > damage ,
& winRec - > damage , ( pRegion ) ) ;
# else
SCREENREC ( pScreen ) - > imp - > DamageRects ( winRec - > wid ,
REGION_NUM_RECTS ( & clipped ) ,
REGION_RECTS ( & clipped ) ,
- winRec - > x , - winRec - > y ) ;
# endif
2004-07-30 21:12:18 +02:00
REGION_UNINIT ( pScreen , & clipped ) ;
2003-11-25 20:29:01 +01:00
2004-07-30 21:12:18 +02:00
RootlessQueueRedisplay ( pTop - > drawable . pScreen ) ;
2003-11-25 20:29:01 +01:00
}
out :
# ifdef ROOTLESSDEBUG
{
BoxRec * box = REGION_RECTS ( pRegion ) , * end ;
int numBox = REGION_NUM_RECTS ( pRegion ) ;
for ( end = box + numBox ; box < end ; box + + ) {
RL_DEBUG_MSG ( " Damage rect: %i, %i, %i, %i \n " ,
box - > x1 , box - > x2 , box - > y1 , box - > y2 ) ;
}
}
# endif
return ;
}
/*
* RootlessDamageBox
* Mark a damaged box as requiring redisplay to screen .
* pRegion is in GLOBAL coordinates .
*/
void
RootlessDamageBox ( WindowPtr pWindow , BoxPtr pBox )
{
RegionRec region ;
REGION_INIT ( pWindow - > drawable . pScreen , & region , pBox , 1 ) ;
RootlessDamageRegion ( pWindow , & region ) ;
2004-07-30 21:12:18 +02:00
REGION_UNINIT ( pWindow - > drawable . pScreen , & region ) ; /* no-op */
2003-11-25 20:29:01 +01:00
}
/*
* RootlessDamageRect
* Mark a damaged rectangle as requiring redisplay to screen .
* ( x , y , w , h ) is in window - local coordinates .
*/
void
RootlessDamageRect ( WindowPtr pWindow , int x , int y , int w , int h )
{
BoxRec box ;
RegionRec region ;
x + = pWindow - > drawable . x ;
y + = pWindow - > drawable . y ;
box . x1 = x ;
box . x2 = x + w ;
box . y1 = y ;
box . y2 = y + h ;
REGION_INIT ( pWindow - > drawable . pScreen , & region , & box , 1 ) ;
RootlessDamageRegion ( pWindow , & region ) ;
2004-07-30 21:12:18 +02:00
REGION_UNINIT ( pWindow - > drawable . pScreen , & region ) ; /* no-op */
2003-11-25 20:29:01 +01:00
}
/*
* RootlessRedisplay
* Stop drawing and redisplay the damaged region of a window .
*/
void
RootlessRedisplay ( WindowPtr pWindow )
{
# ifdef ROOTLESS_TRACK_DAMAGE
RootlessWindowRec * winRec = WINREC ( pWindow ) ;
ScreenPtr pScreen = pWindow - > drawable . pScreen ;
RootlessStopDrawing ( pWindow , FALSE ) ;
if ( REGION_NOTEMPTY ( pScreen , & winRec - > damage ) ) {
RL_DEBUG_MSG ( " Redisplay Win 0x%x, %i x %i @ (%i, %i) \n " ,
pWindow , winRec - > width , winRec - > height ,
winRec - > x , winRec - > y ) ;
// move region to window local coords
REGION_TRANSLATE ( pScreen , & winRec - > damage ,
- winRec - > x , - winRec - > y ) ;
SCREENREC ( pScreen ) - > imp - > UpdateRegion ( winRec - > wid , & winRec - > damage ) ;
REGION_EMPTY ( pScreen , & winRec - > damage ) ;
}
2004-07-30 21:12:18 +02:00
# else /* !ROOTLESS_TRACK_DAMAGE */
2003-11-25 20:29:01 +01:00
RootlessStopDrawing ( pWindow , TRUE ) ;
# endif
}
2004-07-30 21:12:18 +02:00
/*
* RootlessRepositionWindows
* Reposition all windows on a screen to their correct positions .
*/
void
RootlessRepositionWindows ( ScreenPtr pScreen )
{
WindowPtr root = WindowTable [ pScreen - > myNum ] ;
WindowPtr win ;
if ( root ! = NULL ) {
RootlessRepositionWindow ( root ) ;
for ( win = root - > firstChild ; win ; win = win - > nextSib ) {
if ( WINREC ( win ) ! = NULL )
RootlessRepositionWindow ( win ) ;
}
}
}
2003-11-25 20:29:01 +01:00
/*
* RootlessRedisplayScreen
* Walk every window on a screen and redisplay the damaged regions .
*/
void
RootlessRedisplayScreen ( ScreenPtr pScreen )
{
WindowPtr root = WindowTable [ pScreen - > myNum ] ;
if ( root ! = NULL ) {
WindowPtr win ;
RootlessRedisplay ( root ) ;
for ( win = root - > firstChild ; win ; win = win - > nextSib ) {
if ( WINREC ( win ) ! = NULL ) {
RootlessRedisplay ( win ) ;
}
}
}
}