Edit

IABSD.fr/xenocara/xserver/composite/compwindow.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2007-11-24 17:55:21
    Hash : b14d6de7
    Message : xserver 1.4

  • xserver/composite/compwindow.c
  • /*
     * Copyright © 2006 Sun Microsystems
     *
     * Permission to use, copy, modify, distribute, and sell this software and its
     * documentation for any purpose is hereby granted without fee, provided that
     * the above copyright notice appear in all copies and that both that
     * copyright notice and this permission notice appear in supporting
     * documentation, and that the name of Sun Microsystems not be used in
     * advertising or publicity pertaining to distribution of the software without
     * specific, written prior permission.  Sun Microsystems makes no
     * representations about the suitability of this software for any purpose.  It
     * is provided "as is" without express or implied warranty.
     *
     * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     * PERFORMANCE OF THIS SOFTWARE.
     *
     * Copyright © 2003 Keith Packard
     *
     * Permission to use, copy, modify, distribute, and sell this software and its
     * documentation for any purpose is hereby granted without fee, provided that
     * the above copyright notice appear in all copies and that both that
     * copyright notice and this permission notice appear in supporting
     * documentation, and that the name of Keith Packard not be used in
     * advertising or publicity pertaining to distribution of the software without
     * specific, written prior permission.  Keith Packard makes no
     * representations about the suitability of this software for any purpose.  It
     * is provided "as is" without express or implied warranty.
     *
     * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     * PERFORMANCE OF THIS SOFTWARE.
     */
    
    #ifdef HAVE_DIX_CONFIG_H
    #include <dix-config.h>
    #endif
    
    #include "compint.h"
    
    #ifdef COMPOSITE_DEBUG
    static int
    compCheckWindow (WindowPtr pWin, pointer data)
    {
        ScreenPtr	pScreen = pWin->drawable.pScreen;
        PixmapPtr	pWinPixmap = (*pScreen->GetWindowPixmap) (pWin);
        PixmapPtr	pParentPixmap = pWin->parent ? (*pScreen->GetWindowPixmap) (pWin->parent) : 0;
        PixmapPtr	pScreenPixmap = (*pScreen->GetScreenPixmap) (pScreen);
        
        if (!pWin->parent)
        {
    	assert (pWin->redirectDraw == RedirectDrawNone);
    	assert (pWinPixmap == pScreenPixmap);
        }
        else if (pWin->redirectDraw != RedirectDrawNone)
        {
    	assert (pWinPixmap != pParentPixmap);
    	assert (pWinPixmap != pScreenPixmap);
        }
        else
        {
    	assert (pWinPixmap == pParentPixmap);
        }
        assert (0 < pWinPixmap->refcnt && pWinPixmap->refcnt < 3);
        assert (0 < pScreenPixmap->refcnt && pScreenPixmap->refcnt < 3);
        if (pParentPixmap)
    	assert (0 <= pParentPixmap->refcnt && pParentPixmap->refcnt < 3);
        return WT_WALKCHILDREN;
    }
    
    void
    compCheckTree (ScreenPtr pScreen)
    {
        WalkTree (pScreen, compCheckWindow, 0);
    }
    #endif
    
    typedef struct _compPixmapVisit {
        WindowPtr	pWindow;
        PixmapPtr	pPixmap;
    } CompPixmapVisitRec, *CompPixmapVisitPtr;
    
    static Bool
    compRepaintBorder (ClientPtr pClient, pointer closure)
    {
        WindowPtr pWindow;
        int rc = dixLookupWindow(&pWindow, (XID)closure, pClient,DixUnknownAccess);
    
        if (rc == Success) {
    	RegionRec exposed;
    
    	REGION_NULL(pScreen, &exposed);
    	REGION_SUBTRACT(pScreen, &exposed, &pWindow->borderClip, &pWindow->winSize);
    	(*pWindow->drawable.pScreen->PaintWindowBorder)(pWindow, &exposed, PW_BORDER);
    	REGION_UNINIT(pScreen, &exposed);
        }
        return TRUE;
    }
    
    static int
    compSetPixmapVisitWindow (WindowPtr pWindow, pointer data)
    {
        CompPixmapVisitPtr	pVisit = (CompPixmapVisitPtr) data;
        ScreenPtr		pScreen = pWindow->drawable.pScreen;
    
        if (pWindow != pVisit->pWindow && pWindow->redirectDraw != RedirectDrawNone)
    	return WT_DONTWALKCHILDREN;
        (*pScreen->SetWindowPixmap) (pWindow, pVisit->pPixmap);
        /*
         * Recompute winSize and borderSize.  This is duplicate effort
         * when resizing pixmaps, but necessary when changing redirection.
         * Might be nice to fix this.
         */
        SetWinSize (pWindow);
        SetBorderSize (pWindow);
        if (HasBorder (pWindow))
    	QueueWorkProc (compRepaintBorder, serverClient, 
    		       (pointer) pWindow->drawable.id);
        return WT_WALKCHILDREN;
    }
    
    void
    compSetPixmap (WindowPtr pWindow, PixmapPtr pPixmap)
    {
        CompPixmapVisitRec	visitRec;
    
        visitRec.pWindow = pWindow;
        visitRec.pPixmap = pPixmap;
        TraverseTree (pWindow, compSetPixmapVisitWindow, (pointer) &visitRec);
        compCheckTree (pWindow->drawable.pScreen);
    }
    
    Bool
    compCheckRedirect (WindowPtr pWin)
    {
        CompWindowPtr   cw = GetCompWindow (pWin);
        CompScreenPtr   cs = GetCompScreen(pWin->drawable.pScreen);
        Bool	    should;
    
        should = pWin->realized && (pWin->drawable.class != InputOnly) &&
    	     (cw != NULL);
        
        /* Never redirect the overlay window */
        if (cs->pOverlayWin != NULL) {
    	if (pWin == cs->pOverlayWin) {
    	    should = FALSE;
    	}
        }	
        
        if (should != (pWin->redirectDraw != RedirectDrawNone))
        {
    	if (should)
    	    return compAllocPixmap (pWin);
    	else
    	    compFreePixmap (pWin);
        }
        return TRUE;
    }
    
    Bool
    compPositionWindow (WindowPtr pWin, int x, int y)
    {
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        CompScreenPtr   cs = GetCompScreen (pScreen);
        Bool	    ret = TRUE;
    
        pScreen->PositionWindow = cs->PositionWindow;
        /*
         * "Shouldn't need this as all possible places should be wrapped
         *
        compCheckRedirect (pWin);
         */
    #ifdef COMPOSITE_DEBUG
        if ((pWin->redirectDraw != RedirectDrawNone) !=
    	(pWin->viewable && (GetCompWindow(pWin) != NULL)))
    	abort ();
    #endif
        if (pWin->redirectDraw != RedirectDrawNone)
        {
    	PixmapPtr   pPixmap = (*pScreen->GetWindowPixmap) (pWin);
    	int	    bw = wBorderWidth (pWin);
    	int	    nx = pWin->drawable.x - bw;
    	int	    ny = pWin->drawable.y - bw;
    
    	if (pPixmap->screen_x != nx || pPixmap->screen_y != ny)
    	{
    	    pPixmap->screen_x = nx;
    	    pPixmap->screen_y = ny;
    	    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
    	}
        }
    
        if (!(*pScreen->PositionWindow) (pWin, x, y))
    	ret = FALSE;
        cs->PositionWindow = pScreen->PositionWindow;
        pScreen->PositionWindow = compPositionWindow;
        compCheckTree (pWin->drawable.pScreen);
        return ret;
    }
    
    Bool
    compRealizeWindow (WindowPtr pWin)
    {
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        CompScreenPtr   cs = GetCompScreen (pScreen);
        Bool	    ret = TRUE;
    
        pScreen->RealizeWindow = cs->RealizeWindow;
        compCheckRedirect (pWin);
        if (!(*pScreen->RealizeWindow) (pWin))
    	ret = FALSE;
        cs->RealizeWindow = pScreen->RealizeWindow;
        pScreen->RealizeWindow = compRealizeWindow;
        compCheckTree (pWin->drawable.pScreen);
        return ret;
    }
    
    Bool
    compUnrealizeWindow (WindowPtr pWin)
    {
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        CompScreenPtr   cs = GetCompScreen (pScreen);
        Bool	    ret = TRUE;
    
        pScreen->UnrealizeWindow = cs->UnrealizeWindow;
        compCheckRedirect (pWin);
        if (!(*pScreen->UnrealizeWindow) (pWin))
    	ret = FALSE;
        cs->UnrealizeWindow = pScreen->UnrealizeWindow;
        pScreen->UnrealizeWindow = compUnrealizeWindow;
        compCheckTree (pWin->drawable.pScreen);
        return ret;
    }
    
    void
    compPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what)
    {
        ScreenPtr		pScreen = pWin->drawable.pScreen;
        CompSubwindowsPtr	csw = GetCompSubwindows (pWin);
        CompScreenPtr	cs = GetCompScreen (pScreen);
        
        if (csw && csw->update == CompositeRedirectManual)
    	return;
        pScreen->PaintWindowBackground = cs->PaintWindowBackground;
        (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
        cs->PaintWindowBackground = pScreen->PaintWindowBackground;
        pScreen->PaintWindowBackground = compPaintWindowBackground;
    }
    
    /*
     * Called after the borderClip for the window has settled down
     * We use this to make sure our extra borderClip has the right origin
     */
    
    void
    compClipNotify (WindowPtr pWin, int dx, int dy)
    {
        ScreenPtr		pScreen = pWin->drawable.pScreen;
        CompScreenPtr	cs = GetCompScreen (pScreen);
        CompWindowPtr	cw = GetCompWindow (pWin);
        
        if (cw)
        {
    	if (cw->borderClipX != pWin->drawable.x || 
    	    cw->borderClipY != pWin->drawable.y)
    	{
    	    REGION_TRANSLATE (pScreen, &cw->borderClip,
    			      pWin->drawable.x - cw->borderClipX,
    			      pWin->drawable.y - cw->borderClipY);
    	    cw->borderClipX = pWin->drawable.x;
    	    cw->borderClipY = pWin->drawable.y;
    	}
        }
        if (cs->ClipNotify)
        {
    	pScreen->ClipNotify = cs->ClipNotify;
    	(*pScreen->ClipNotify) (pWin, dx, dy);
    	cs->ClipNotify = pScreen->ClipNotify;
    	pScreen->ClipNotify = compClipNotify;
        }
    }
    
    /*
     * Returns TRUE if the window needs server-provided automatic redirect,
     * which is true if the child and parent aren't both regular or ARGB visuals
     */
    
    static Bool
    compIsAlternateVisual (ScreenPtr    pScreen,
    		       XID	    visual)
    {
        CompScreenPtr	cs = GetCompScreen (pScreen);
        int			i;
    
        for (i = 0; i < cs->numAlternateVisuals; i++)
    	if (cs->alternateVisuals[i] == visual)
    	    return TRUE;
        return FALSE;
    }
    
    static Bool
    compImplicitRedirect (WindowPtr pWin, WindowPtr pParent)
    {
        if (pParent)
        {
    	ScreenPtr	pScreen = pWin->drawable.pScreen;
    	XID		winVisual = wVisual (pWin);
    	XID		parentVisual = wVisual (pParent);
        
    	if (winVisual != parentVisual &&
    	    (compIsAlternateVisual (pScreen, winVisual) ||
    	     compIsAlternateVisual (pScreen, parentVisual)))
    	    return TRUE;
        }
        return FALSE;
    }
    
    void
    compMoveWindow (WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
    {
        ScreenPtr		pScreen = pWin->drawable.pScreen;
        CompScreenPtr	cs = GetCompScreen (pScreen);
    
        compCheckTree (pScreen);
        if (pWin->redirectDraw != RedirectDrawNone)
        {
    	WindowPtr		pParent;
    	int			draw_x, draw_y;
    	unsigned int		w, h, bw;
    	
    	/* if this is a root window, can't be moved */
    	if (!(pParent = pWin->parent))
    	   return;
    	
    	bw = wBorderWidth (pWin);
    	draw_x = pParent->drawable.x + x + (int)bw;
    	draw_y = pParent->drawable.y + y + (int)bw;
    	w = pWin->drawable.width;
    	h = pWin->drawable.height;
    	compReallocPixmap (pWin, draw_x, draw_y, w, h, bw);
        }
        compCheckTree (pScreen);
    
        pScreen->MoveWindow = cs->MoveWindow;
        (*pScreen->MoveWindow) (pWin, x, y, pSib, kind);
        cs->MoveWindow = pScreen->MoveWindow;
        pScreen->MoveWindow = compMoveWindow;
    
        if (pWin->redirectDraw != RedirectDrawNone)
        {
    	CompWindowPtr	cw = GetCompWindow (pWin);
    	if (cw->pOldPixmap)
    	{
    	    (*pScreen->DestroyPixmap) (cw->pOldPixmap);
    	    cw->pOldPixmap = NullPixmap;
    	}
        }
    
        compCheckTree (pScreen);
    }
    
    void
    compResizeWindow (WindowPtr pWin, int x, int y,
    		  unsigned int w, unsigned int h, WindowPtr pSib)
    {
        ScreenPtr		pScreen = pWin->drawable.pScreen;
        CompScreenPtr	cs = GetCompScreen (pScreen);
    
        compCheckTree (pScreen);
        if (pWin->redirectDraw != RedirectDrawNone)
        {
    	WindowPtr		pParent;
    	int			draw_x, draw_y;
    	unsigned int		bw;
    	
    	/* if this is a root window, can't be moved */
    	if (!(pParent = pWin->parent))
    	   return;
    	
    	bw = wBorderWidth (pWin);
    	draw_x = pParent->drawable.x + x + (int)bw;
    	draw_y = pParent->drawable.y + y + (int)bw;
    	compReallocPixmap (pWin, draw_x, draw_y, w, h, bw);
        }
        compCheckTree (pScreen);
        
        pScreen->ResizeWindow = cs->ResizeWindow;
        (*pScreen->ResizeWindow) (pWin, x, y, w, h, pSib);
        cs->ResizeWindow = pScreen->ResizeWindow;
        pScreen->ResizeWindow = compResizeWindow;
        if (pWin->redirectDraw != RedirectDrawNone)
        {
    	CompWindowPtr	cw = GetCompWindow (pWin);
    	if (cw->pOldPixmap)
    	{
    	    (*pScreen->DestroyPixmap) (cw->pOldPixmap);
    	    cw->pOldPixmap = NullPixmap;
    	}
        }
        compCheckTree (pWin->drawable.pScreen);
    }
    
    void
    compChangeBorderWidth (WindowPtr pWin, unsigned int bw)
    {
        ScreenPtr		pScreen = pWin->drawable.pScreen;
        CompScreenPtr	cs = GetCompScreen (pScreen);
    
        compCheckTree (pScreen);
        if (pWin->redirectDraw != RedirectDrawNone)
        {
    	WindowPtr		pParent;
    	int			draw_x, draw_y;
    	unsigned int		w, h;
    	
    	/* if this is a root window, can't be moved */
    	if (!(pParent = pWin->parent))
    	   return;
    	
    	draw_x = pWin->drawable.x;
    	draw_y = pWin->drawable.y;
    	w = pWin->drawable.width;
    	h = pWin->drawable.height;
    	compReallocPixmap (pWin, draw_x, draw_y, w, h, bw);
        }
        compCheckTree (pScreen);
    
        pScreen->ChangeBorderWidth = cs->ChangeBorderWidth;
        (*pScreen->ChangeBorderWidth) (pWin, bw);
        cs->ChangeBorderWidth = pScreen->ChangeBorderWidth;
        pScreen->ChangeBorderWidth = compChangeBorderWidth;
        if (pWin->redirectDraw != RedirectDrawNone)
        {
    	CompWindowPtr	cw = GetCompWindow (pWin);
    	if (cw->pOldPixmap)
    	{
    	    (*pScreen->DestroyPixmap) (cw->pOldPixmap);
    	    cw->pOldPixmap = NullPixmap;
    	}
        }
        compCheckTree (pWin->drawable.pScreen);
    }
    
    void
    compReparentWindow (WindowPtr pWin, WindowPtr pPriorParent)
    {
        ScreenPtr		pScreen = pWin->drawable.pScreen;
        CompScreenPtr	cs = GetCompScreen (pScreen);
    
        pScreen->ReparentWindow = cs->ReparentWindow;
        /*
         * Remove any implicit redirect due to synthesized visual
         */
        if (compImplicitRedirect (pWin, pPriorParent))
    	compUnredirectWindow (serverClient, pWin, CompositeRedirectAutomatic);
        /*
         * Handle subwindows redirection
         */
        compUnredirectOneSubwindow (pPriorParent, pWin);
        compRedirectOneSubwindow (pWin->parent, pWin);
        /*
         * Add any implict redirect due to synthesized visual
         */
        if (compImplicitRedirect (pWin, pWin->parent))
    	compRedirectWindow (serverClient, pWin, CompositeRedirectAutomatic);
        
        /*
         * Allocate any necessary redirect pixmap
         * (this actually should never be true; pWin is always unmapped)
         */
        compCheckRedirect (pWin);
        
        /*
         * Reset pixmap pointers as appropriate
         */
        if (pWin->parent && pWin->redirectDraw == RedirectDrawNone)
    	compSetPixmap (pWin, (*pScreen->GetWindowPixmap) (pWin->parent));
        /*
         * Call down to next function
         */
        if (pScreen->ReparentWindow)
    	(*pScreen->ReparentWindow) (pWin, pPriorParent);
        cs->ReparentWindow = pScreen->ReparentWindow;
        pScreen->ReparentWindow = compReparentWindow;
        compCheckTree (pWin->drawable.pScreen);
    }
    
    void
    compCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
    {
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        CompScreenPtr   cs = GetCompScreen (pScreen);
        int		    dx = 0, dy = 0;
    
        if (pWin->redirectDraw != RedirectDrawNone)
        {
    	PixmapPtr	pPixmap = (*pScreen->GetWindowPixmap) (pWin);
    	CompWindowPtr	cw = GetCompWindow (pWin);
    	
    	assert (cw->oldx != COMP_ORIGIN_INVALID);
    	assert (cw->oldy != COMP_ORIGIN_INVALID);
    	if (cw->pOldPixmap)
    	{
    	    /*
    	     * Ok, the old bits are available in pOldPixmap and
    	     * need to be copied to pNewPixmap.
    	     */
    	    RegionRec	rgnDst;
    	    PixmapPtr	pPixmap = (*pScreen->GetWindowPixmap) (pWin);
    	    GCPtr	pGC;
    	    
    	    dx = ptOldOrg.x - pWin->drawable.x;
    	    dy = ptOldOrg.y - pWin->drawable.y;
    	    REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
    
    	    REGION_NULL (pWin->drawable.pScreen, &rgnDst);
    
    	    REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst,
    			     &pWin->borderClip, prgnSrc);
    	    
    	    REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, 
    			      -pPixmap->screen_x, -pPixmap->screen_y);
    	    
    	    dx = dx + pPixmap->screen_x - cw->oldx;
    	    dy = dy + pPixmap->screen_y - cw->oldy;
    	    pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
    	    if (pGC)
    	    {
    		BoxPtr	pBox = REGION_RECTS (&rgnDst);
    		int	nBox = REGION_NUM_RECTS (&rgnDst);
    		
    		ValidateGC(&pPixmap->drawable, pGC);
    		while (nBox--)
    		{
    		    (void) (*pGC->ops->CopyArea) (&cw->pOldPixmap->drawable,
    						  &pPixmap->drawable,
    						  pGC,
    						  pBox->x1 + dx, pBox->y1 + dy,
    						  pBox->x2 - pBox->x1,
    						  pBox->y2 - pBox->y1,
    						  pBox->x1, pBox->y1);
    		    pBox++;
    		}
    		FreeScratchGC (pGC);
    	    }
    	    return;
    	}
    	dx = pPixmap->screen_x - cw->oldx;
    	dy = pPixmap->screen_y - cw->oldy;
    	ptOldOrg.x += dx;
    	ptOldOrg.y += dy;
        }
        
        pScreen->CopyWindow = cs->CopyWindow;
        if (ptOldOrg.x != pWin->drawable.x || ptOldOrg.y != pWin->drawable.y)
        {
    	if (dx || dy)
    	    REGION_TRANSLATE (pScreen, prgnSrc, dx, dy);
    	(*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc);
    	if (dx || dy)
    	    REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy);
        }
        else
        {
    	ptOldOrg.x -= dx;
    	ptOldOrg.y -= dy;
    	REGION_TRANSLATE (prgnSrc, prgnSrc,
    			  pWin->drawable.x - ptOldOrg.x,
    			  pWin->drawable.y - ptOldOrg.y);
    	DamageDamageRegion (&pWin->drawable, prgnSrc);
        }
        cs->CopyWindow = pScreen->CopyWindow;
        pScreen->CopyWindow = compCopyWindow;
        compCheckTree (pWin->drawable.pScreen);
    }
    
    Bool
    compCreateWindow (WindowPtr pWin)
    {
        ScreenPtr		pScreen = pWin->drawable.pScreen;
        CompScreenPtr	cs = GetCompScreen (pScreen);
        Bool		ret;
    
        pScreen->CreateWindow = cs->CreateWindow;
        ret = (*pScreen->CreateWindow) (pWin);
        if (pWin->parent && ret)
        {
    	CompSubwindowsPtr	csw = GetCompSubwindows (pWin->parent);
            CompClientWindowPtr	ccw;
    
    	(*pScreen->SetWindowPixmap) (pWin, (*pScreen->GetWindowPixmap) (pWin->parent));
    	if (csw)
    	    for (ccw = csw->clients; ccw; ccw = ccw->next)
    		compRedirectWindow (clients[CLIENT_ID(ccw->id)],
    				    pWin, ccw->update);
    	if (compImplicitRedirect (pWin, pWin->parent))
    	    compRedirectWindow (serverClient, pWin, CompositeRedirectAutomatic);
        }
        cs->CreateWindow = pScreen->CreateWindow;
        pScreen->CreateWindow = compCreateWindow;
        compCheckTree (pWin->drawable.pScreen);
        return ret;
    }
    
    Bool
    compDestroyWindow (WindowPtr pWin)
    {
        ScreenPtr		pScreen = pWin->drawable.pScreen;
        CompScreenPtr	cs = GetCompScreen (pScreen);
        CompWindowPtr	cw;
        CompSubwindowsPtr	csw;
        Bool		ret;
    
        pScreen->DestroyWindow = cs->DestroyWindow;
        while ((cw = GetCompWindow (pWin)))
    	FreeResource (cw->clients->id, RT_NONE);
        while ((csw = GetCompSubwindows (pWin)))
    	FreeResource (csw->clients->id, RT_NONE);
        
        if (pWin->redirectDraw != RedirectDrawNone)
    	compFreePixmap (pWin);
        ret = (*pScreen->DestroyWindow) (pWin);
        cs->DestroyWindow = pScreen->DestroyWindow;
        pScreen->DestroyWindow = compDestroyWindow;
    /*    compCheckTree (pWin->drawable.pScreen); can't check -- tree isn't good*/
        return ret;
    }
    
    void
    compSetRedirectBorderClip (WindowPtr pWin, RegionPtr pRegion)
    {
        CompWindowPtr   cw = GetCompWindow (pWin);
        RegionRec	    damage;
    
        REGION_NULL (pScreen, &damage);
        /*
         * Align old border clip with new border clip
         */
        REGION_TRANSLATE (pScreen, &cw->borderClip,
    		      pWin->drawable.x - cw->borderClipX,
    		      pWin->drawable.y - cw->borderClipY);
        /*
         * Compute newly visible portion of window for repaint
         */
        REGION_SUBTRACT (pScreen, &damage, pRegion, &cw->borderClip);
        /*
         * Report that as damaged so it will be redrawn
         */
        DamageDamageRegion (&pWin->drawable, &damage);
        REGION_UNINIT (pScreen, &damage);
        /*
         * Save the new border clip region
         */
        REGION_COPY (pScreen, &cw->borderClip, pRegion);
        cw->borderClipX = pWin->drawable.x;
        cw->borderClipY = pWin->drawable.y;
    }
    
    RegionPtr
    compGetRedirectBorderClip (WindowPtr pWin)
    {
        CompWindowPtr   cw = GetCompWindow (pWin);
    
        return &cw->borderClip;
    }
    
    static VisualPtr
    compGetWindowVisual (WindowPtr pWin)
    {
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        VisualID	    vid = wVisual (pWin);
        int		    i;
    
        for (i = 0; i < pScreen->numVisuals; i++)
    	if (pScreen->visuals[i].vid == vid)
    	    return &pScreen->visuals[i];
        return 0;
    }
    
    PictFormatPtr
    compWindowFormat (WindowPtr pWin)
    {
        ScreenPtr	pScreen = pWin->drawable.pScreen;
        
        return PictureMatchVisual (pScreen, pWin->drawable.depth,
    			       compGetWindowVisual (pWin));
    }
    
    static void
    compWindowUpdateAutomatic (WindowPtr pWin)
    {
        CompWindowPtr   cw = GetCompWindow (pWin);
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        WindowPtr	    pParent = pWin->parent;
        PixmapPtr	    pSrcPixmap = (*pScreen->GetWindowPixmap) (pWin);
        PictFormatPtr   pSrcFormat = compWindowFormat (pWin);
        PictFormatPtr   pDstFormat = compWindowFormat (pWin->parent);
        int		    error;
        RegionPtr	    pRegion = DamageRegion (cw->damage);
        PicturePtr	    pSrcPicture = CreatePicture (0, &pSrcPixmap->drawable,
    						 pSrcFormat, 
    						 0, 0,
    						 serverClient,
    						 &error);
        XID		    subwindowMode = IncludeInferiors;
        PicturePtr	    pDstPicture = CreatePicture (0, &pParent->drawable,
    						 pDstFormat,
    						 CPSubwindowMode, 
    						 &subwindowMode,
    						 serverClient,
    						 &error);
        
        /*
         * First move the region from window to screen coordinates
         */
        REGION_TRANSLATE (pScreen, pRegion, 
    		      pWin->drawable.x, pWin->drawable.y);
        
        /*
         * Clip against the "real" border clip
         */
        REGION_INTERSECT (pScreen, pRegion, pRegion, &cw->borderClip);
    
        /*
         * Now translate from screen to dest coordinates
         */
        REGION_TRANSLATE (pScreen, pRegion, 
    		      -pParent->drawable.x, -pParent->drawable.y);
        
        /*
         * Clip the picture
         */
        SetPictureClipRegion (pDstPicture, 0, 0, pRegion);
        
        /*
         * And paint
         */
        CompositePicture (PictOpSrc,
    		      pSrcPicture,
    		      0,
    		      pDstPicture,
    		      0, 0, /* src_x, src_y */
    		      0, 0, /* msk_x, msk_y */
    		      pSrcPixmap->screen_x - pParent->drawable.x,
    		      pSrcPixmap->screen_y - pParent->drawable.y,
    		      pSrcPixmap->drawable.width,
    		      pSrcPixmap->drawable.height);
        FreePicture (pSrcPicture, 0);
        FreePicture (pDstPicture, 0);
        /*
         * Empty the damage region.  This has the nice effect of
         * rendering the translations above harmless
         */
        DamageEmpty (cw->damage);
    }
    
    void
    compWindowUpdate (WindowPtr pWin)
    {
        WindowPtr	pChild;
    
        for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
    	compWindowUpdate (pChild);
        if (pWin->redirectDraw != RedirectDrawNone)
        {
    	CompWindowPtr	cw = GetCompWindow(pWin);
    
    	if (cw->damaged)
    	{
    	    compWindowUpdateAutomatic (pWin);
    	    cw->damaged = FALSE;
    	}
        }
    }
    
    WindowPtr
    CompositeRealChildHead (WindowPtr pWin)
    {
        WindowPtr pChild, pChildBefore;
        CompScreenPtr cs;
    
        if (!pWin->parent &&
    	(screenIsSaved == SCREEN_SAVER_ON) &&
    	(HasSaverWindow (pWin->drawable.pScreen->myNum))) {
    
    	/* First child is the screen saver; see if next child is the overlay */
    	pChildBefore = pWin->firstChild;
    	pChild = pChildBefore->nextSib;
    
        } else {
    	pChildBefore = NullWindow;
    	pChild = pWin->firstChild;
        }
    
        if (!pChild) {
    	return NullWindow;
        }
        
        cs = GetCompScreen(pWin->drawable.pScreen);
        if (pChild == cs->pOverlayWin) {
    	return pChild;
        } else {
    	return pChildBefore;
        }
    }