Edit

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

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2010-12-21 20:10:44
    Hash : dd56fb17
    Message : Update to xorg-server 1.9.3. Tested by japser@, landry@ and ajacoutot@ in various configurations.

  • xserver/composite/compalloc.c
  • /*
     * Copyright © 2006 Sun Microsystems, 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 (including the next
     * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
     *
     * 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"
    
    static void
    compReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure)
    {
        WindowPtr	    pWin = (WindowPtr) closure;
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        CompScreenPtr   cs = GetCompScreen (pScreen);
        CompWindowPtr   cw = GetCompWindow (pWin);
    
        cs->damaged = TRUE;
        cw->damaged = TRUE;
    }
    
    static void
    compDestroyDamage (DamagePtr pDamage, void *closure)
    {
        WindowPtr	    pWin = (WindowPtr) closure;
        CompWindowPtr   cw = GetCompWindow (pWin);
    
        cw->damage = 0;
    }
    
    /*
     * Redirect one window for one client
     */
    int
    compRedirectWindow (ClientPtr pClient, WindowPtr pWin, int update)
    {
        CompWindowPtr	cw = GetCompWindow (pWin);
        CompClientWindowPtr	ccw;
        Bool		wasMapped = pWin->mapped;
        CompScreenPtr       cs = GetCompScreen(pWin->drawable.pScreen);
        
        if (pWin == cs->pOverlayWin) {
    	return Success;
        }
    
        if (!pWin->parent)
    	return BadMatch;
    
        /*
         * Only one Manual update is allowed
         */
        if (cw && update == CompositeRedirectManual)
    	for (ccw = cw->clients; ccw; ccw = ccw->next)
    	    if (ccw->update == CompositeRedirectManual)
    		return BadAccess;
        
        /*
         * Allocate per-client per-window structure 
         * The client *could* allocate multiple, but while supported,
         * it is not expected to be common
         */
        ccw = malloc(sizeof (CompClientWindowRec));
        if (!ccw)
    	return BadAlloc;
        ccw->id = FakeClientID (pClient->index);
        ccw->update = update;
        /*
         * Now make sure there's a per-window structure to hang this from
         */
        if (!cw)
        {
    	cw = malloc(sizeof (CompWindowRec));
    	if (!cw)
    	{
    	    free(ccw);
    	    return BadAlloc;
    	}
    	cw->damage = DamageCreate (compReportDamage,
    				   compDestroyDamage,
    				   DamageReportNonEmpty,
    				   FALSE,
    				   pWin->drawable.pScreen,
    				   pWin);
    	if (!cw->damage)
    	{
    	    free(ccw);
    	    free(cw);
    	    return BadAlloc;
    	}
    	if (wasMapped)
    	{
    	    DisableMapUnmapEvents (pWin);
    	    UnmapWindow (pWin, FALSE);
    	    EnableMapUnmapEvents (pWin);
    	}
    
    	RegionNull(&cw->borderClip);
    	cw->borderClipX = 0;
    	cw->borderClipY = 0;
    	cw->update = CompositeRedirectAutomatic;
    	cw->clients = 0;
    	cw->oldx = COMP_ORIGIN_INVALID;
    	cw->oldy = COMP_ORIGIN_INVALID;
    	cw->damageRegistered = FALSE;
    	cw->damaged = FALSE;
    	cw->pOldPixmap = NullPixmap;
    	dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw);
        }
        ccw->next = cw->clients;
        cw->clients = ccw;
        if (!AddResource (ccw->id, CompositeClientWindowType, pWin))
    	return BadAlloc;
        if (ccw->update == CompositeRedirectManual)
        {
    	/* If the window was CompositeRedirectAutomatic, then
    	 * unmap the window so that the parent clip list will
    	 * be correctly recomputed.
    	 */
    	if (pWin->mapped) 
    	{
    	    DisableMapUnmapEvents (pWin);
    	    UnmapWindow (pWin, FALSE);
    	    EnableMapUnmapEvents (pWin);
    	}
    	if (cw->damageRegistered)
    	{
    	    DamageUnregister (&pWin->drawable, cw->damage);
    	    cw->damageRegistered = FALSE;
    	}
    	cw->update = CompositeRedirectManual;
        }
    
        if (!compCheckRedirect (pWin))
        {
    	FreeResource (ccw->id, RT_NONE);
    	return BadAlloc;
        }
        if (wasMapped && !pWin->mapped)
        {
    	Bool	overrideRedirect = pWin->overrideRedirect;
    	pWin->overrideRedirect = TRUE;
    	DisableMapUnmapEvents (pWin);
    	MapWindow (pWin, pClient);
    	EnableMapUnmapEvents (pWin);
    	pWin->overrideRedirect = overrideRedirect;
        }
        
        return Success;
    }
    
    /*
     * Free one of the per-client per-window resources, clearing
     * redirect and the per-window pointer as appropriate
     */
    void
    compFreeClientWindow (WindowPtr pWin, XID id)
    {
        CompWindowPtr	cw = GetCompWindow (pWin);
        CompClientWindowPtr	ccw, *prev;
        Bool		wasMapped = pWin->mapped;
    
        if (!cw)
    	return;
        for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next)
        {
    	if (ccw->id == id)
    	{
    	    *prev = ccw->next;
    	    if (ccw->update == CompositeRedirectManual)
    		cw->update = CompositeRedirectAutomatic;
    	    free(ccw);
    	    break;
    	}
        }
        if (!cw->clients)
        {
    	if (wasMapped)
    	{
    	    DisableMapUnmapEvents (pWin);
    	    UnmapWindow (pWin, FALSE);
    	    EnableMapUnmapEvents (pWin);
    	}
        
    	if (pWin->redirectDraw != RedirectDrawNone)
    	    compFreePixmap (pWin);
    
    	if (cw->damage)
    	    DamageDestroy (cw->damage);
    	
    	RegionUninit(&cw->borderClip);
        
    	dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL);
    	free(cw);
        }
        else if (cw->update == CompositeRedirectAutomatic &&
    	     !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone)
        {
    	DamageRegister (&pWin->drawable, cw->damage);
    	cw->damageRegistered = TRUE;
    	pWin->redirectDraw = RedirectDrawAutomatic;
    	DamageDamageRegion(&pWin->drawable, &pWin->borderSize);
        }
        if (wasMapped && !pWin->mapped)
        {
    	Bool	overrideRedirect = pWin->overrideRedirect;
    	pWin->overrideRedirect = TRUE;
    	DisableMapUnmapEvents (pWin);
    	MapWindow (pWin, clients[CLIENT_ID(id)]);
    	EnableMapUnmapEvents (pWin);
    	pWin->overrideRedirect = overrideRedirect;
        }
    }
    
    /*
     * This is easy, just free the appropriate resource.
     */
    
    int
    compUnredirectWindow (ClientPtr pClient, WindowPtr pWin, int update)
    {
        CompWindowPtr	cw = GetCompWindow (pWin);
        CompClientWindowPtr	ccw;
    
        if (!cw)
    	return BadValue;
    
        for (ccw = cw->clients; ccw; ccw = ccw->next)
    	if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index)
    	{
    	    FreeResource (ccw->id, RT_NONE);
    	    return Success;
    	}
        return BadValue;
    }
    	
    /*
     * Redirect all subwindows for one client
     */
    
    int
    compRedirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update)
    {
        CompSubwindowsPtr	csw = GetCompSubwindows (pWin);
        CompClientWindowPtr	ccw;
        WindowPtr		pChild;
    
        /*
         * Only one Manual update is allowed
         */
        if (csw && update == CompositeRedirectManual)
    	for (ccw = csw->clients; ccw; ccw = ccw->next)
    	    if (ccw->update == CompositeRedirectManual)
    		return BadAccess;
        /*
         * Allocate per-client per-window structure 
         * The client *could* allocate multiple, but while supported,
         * it is not expected to be common
         */
        ccw = malloc(sizeof (CompClientWindowRec));
        if (!ccw)
    	return BadAlloc;
        ccw->id = FakeClientID (pClient->index);
        ccw->update = update;
        /*
         * Now make sure there's a per-window structure to hang this from
         */
        if (!csw)
        {
    	csw = malloc(sizeof (CompSubwindowsRec));
    	if (!csw)
    	{
    	    free(ccw);
    	    return BadAlloc;
    	}
    	csw->update = CompositeRedirectAutomatic;
    	csw->clients = 0;
    	dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw);
        }
        /*
         * Redirect all existing windows
         */
        for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
        {
    	int ret = compRedirectWindow (pClient, pChild, update);
    	if (ret != Success)
    	{
    	    for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib)
    		(void) compUnredirectWindow (pClient, pChild, update);
    	    if (!csw->clients)
    	    {
    		free(csw);
    		dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0);
    	    }
    	    free(ccw);
    	    return ret;
    	}
        }
        /*
         * Hook into subwindows list
         */
        ccw->next = csw->clients;
        csw->clients = ccw;
        if (!AddResource (ccw->id, CompositeClientSubwindowsType, pWin))
    	return BadAlloc;
        if (ccw->update == CompositeRedirectManual)
        {
    	csw->update = CompositeRedirectManual;
    	/* 
    	 * tell damage extension that damage events for this client are
    	 * critical output
    	 */
    	DamageExtSetCritical (pClient, TRUE);
        }
        return Success;
    }
    
    /*
     * Free one of the per-client per-subwindows resources,
     * which frees one redirect per subwindow
     */
    void
    compFreeClientSubwindows (WindowPtr pWin, XID id)
    {
        CompSubwindowsPtr	csw = GetCompSubwindows (pWin);
        CompClientWindowPtr	ccw, *prev;
        WindowPtr		pChild;
    
        if (!csw)
    	return;
        for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next)
        {
    	if (ccw->id == id)
    	{
    	    ClientPtr	pClient = clients[CLIENT_ID(id)];
    	    
    	    *prev = ccw->next;
    	    if (ccw->update == CompositeRedirectManual)
    	    {
    		/* 
    		 * tell damage extension that damage events for this client are
    		 * critical output
    		 */
    		DamageExtSetCritical (pClient, FALSE);
    		csw->update = CompositeRedirectAutomatic;
    		if (pWin->mapped)
    		    (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, TRUE);
    	    }
    
    	    /*
    	     * Unredirect all existing subwindows
    	     */
    	    for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
    		(void) compUnredirectWindow (pClient, pChild, ccw->update);
    
    	    free(ccw);
    	    break;
    	}
        }
    
        /*
         * Check if all of the per-client records are gone
         */
        if (!csw->clients)
        {
    	dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL);
    	free(csw);
        }
    }
    
    /*
     * This is easy, just free the appropriate resource.
     */
    
    int
    compUnredirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update)
    {
        CompSubwindowsPtr	csw = GetCompSubwindows (pWin);
        CompClientWindowPtr	ccw;
        
        if (!csw)
    	return BadValue;
        for (ccw = csw->clients; ccw; ccw = ccw->next)
    	if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index)
    	{
    	    FreeResource (ccw->id, RT_NONE);
    	    return Success;
    	}
        return BadValue;
    }
    
    /*
     * Add redirection information for one subwindow (during reparent)
     */
    
    int
    compRedirectOneSubwindow (WindowPtr pParent, WindowPtr pWin)
    {
        CompSubwindowsPtr	csw = GetCompSubwindows (pParent);
        CompClientWindowPtr	ccw;
    
        if (!csw)
    	return Success;
        for (ccw = csw->clients; ccw; ccw = ccw->next)
        {
    	int ret = compRedirectWindow (clients[CLIENT_ID(ccw->id)],
    				      pWin, ccw->update);
    	if (ret != Success)
    	    return ret;
        }
        return Success;
    }
    
    /*
     * Remove redirection information for one subwindow (during reparent)
     */
    
    int
    compUnredirectOneSubwindow (WindowPtr pParent, WindowPtr pWin)
    {
        CompSubwindowsPtr	csw = GetCompSubwindows (pParent);
        CompClientWindowPtr	ccw;
    
        if (!csw)
    	return Success;
        for (ccw = csw->clients; ccw; ccw = ccw->next)
        {
    	int ret = compUnredirectWindow (clients[CLIENT_ID(ccw->id)],
    					pWin, ccw->update);
    	if (ret != Success)
    	    return ret;
        }
        return Success;
    }
    
    static PixmapPtr
    compNewPixmap (WindowPtr pWin, int x, int y, int w, int h)
    {
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        WindowPtr	    pParent = pWin->parent;
        PixmapPtr	    pPixmap;
    
        pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth,
    					CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
    
        if (!pPixmap)
    	return 0;
        
        pPixmap->screen_x = x;
        pPixmap->screen_y = y;
        
        if (pParent->drawable.depth == pWin->drawable.depth)
        {
    	GCPtr	pGC = GetScratchGC (pWin->drawable.depth, pScreen);
    	
    	/*
    	 * Copy bits from the parent into the new pixmap so that it will
    	 * have "reasonable" contents in case for background None areas.
    	 */
    	if (pGC)
    	{
    	    ChangeGCVal val;
    	    val.val = IncludeInferiors;
    	    
    	    ValidateGC(&pPixmap->drawable, pGC);
    	    ChangeGC (serverClient, pGC, GCSubwindowMode, &val);
    	    (*pGC->ops->CopyArea) (&pParent->drawable,
    				   &pPixmap->drawable,
    				   pGC,
    				   x - pParent->drawable.x,
    				   y - pParent->drawable.y,
    				   w, h, 0, 0);
    	    FreeScratchGC (pGC);
    	}
        }
        else
        {
    	PictFormatPtr	pSrcFormat = compWindowFormat (pParent);
    	PictFormatPtr	pDstFormat = compWindowFormat (pWin);
    	XID		inferiors = IncludeInferiors;
    	int		error;
    
    	PicturePtr	pSrcPicture = CreatePicture (None,
    						     &pParent->drawable,
    						     pSrcFormat,
    						     CPSubwindowMode,
    						     &inferiors,
    						     serverClient, &error);
    						    
    	PicturePtr	pDstPicture = CreatePicture (None,
    						     &pPixmap->drawable,
    						     pDstFormat,
    						     0, 0,
    						     serverClient, &error);
    
    	if (pSrcPicture && pDstPicture)
    	{
    	    CompositePicture (PictOpSrc,
    			      pSrcPicture,
    			      NULL,
    			      pDstPicture,
    			      x - pParent->drawable.x,
    			      y - pParent->drawable.y,
    			      0, 0, 0, 0, w, h);
    	}
    	if (pSrcPicture)
    	    FreePicture (pSrcPicture, 0);
    	if (pDstPicture)
    	    FreePicture (pDstPicture, 0);
        }
        return pPixmap;
    }
    
    Bool
    compAllocPixmap (WindowPtr pWin)
    {
        int		    bw = (int) pWin->borderWidth;
        int		    x = pWin->drawable.x - bw;
        int		    y = pWin->drawable.y - bw;
        int		    w = pWin->drawable.width + (bw << 1);
        int		    h = pWin->drawable.height + (bw << 1);
        PixmapPtr	    pPixmap = compNewPixmap (pWin, x, y, w, h);
        CompWindowPtr   cw = GetCompWindow (pWin);
    
        if (!pPixmap)
    	return FALSE;
        if (cw->update == CompositeRedirectAutomatic)
    	pWin->redirectDraw = RedirectDrawAutomatic;
        else
    	pWin->redirectDraw = RedirectDrawManual;
    
        compSetPixmap (pWin, pPixmap);
        cw->oldx = COMP_ORIGIN_INVALID;
        cw->oldy = COMP_ORIGIN_INVALID;
        cw->damageRegistered = FALSE;
        if (cw->update == CompositeRedirectAutomatic)
        {
    	DamageRegister (&pWin->drawable, cw->damage);
    	cw->damageRegistered = TRUE;
        }
        return TRUE;
    }
    
    void
    compFreePixmap (WindowPtr pWin)
    {
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        PixmapPtr	    pRedirectPixmap, pParentPixmap;
        CompWindowPtr   cw = GetCompWindow (pWin);
    
        if (cw->damageRegistered)
        {
    	DamageUnregister (&pWin->drawable, cw->damage);
    	cw->damageRegistered = FALSE;
    	DamageEmpty (cw->damage);
        }
        /*
         * Move the parent-constrained border clip region back into
         * the window so that ValidateTree will handle the unmap
         * case correctly.  Unmap adds the window borderClip to the
         * parent exposed area; regions beyond the parent cause crashes
         */
        RegionCopy(&pWin->borderClip, &cw->borderClip);
        pRedirectPixmap = (*pScreen->GetWindowPixmap) (pWin);
        pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent);
        pWin->redirectDraw = RedirectDrawNone;
        compSetPixmap (pWin, pParentPixmap);
        (*pScreen->DestroyPixmap) (pRedirectPixmap);
    }
    
    /*
     * Make sure the pixmap is the right size and offset.  Allocate a new
     * pixmap to change size, adjust origin to change offset, leaving the
     * old pixmap in cw->pOldPixmap so bits can be recovered
     */
    Bool
    compReallocPixmap (WindowPtr pWin, int draw_x, int draw_y,
    		   unsigned int w, unsigned int h, int bw)
    {
        ScreenPtr	    pScreen = pWin->drawable.pScreen;
        PixmapPtr	    pOld = (*pScreen->GetWindowPixmap) (pWin);
        PixmapPtr	    pNew;
        CompWindowPtr   cw = GetCompWindow (pWin);
        int		    pix_x, pix_y;
        int		    pix_w, pix_h;
    
        assert (cw && pWin->redirectDraw != RedirectDrawNone);
        cw->oldx = pOld->screen_x;
        cw->oldy = pOld->screen_y;
        pix_x = draw_x - bw;
        pix_y = draw_y - bw;
        pix_w = w + (bw << 1);
        pix_h = h + (bw << 1);
        if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height)
        {
    	pNew = compNewPixmap (pWin, pix_x, pix_y, pix_w, pix_h);
    	if (!pNew)
    	    return FALSE;
    	cw->pOldPixmap = pOld;
    	compSetPixmap (pWin, pNew);
        }
        else
        {
    	pNew = pOld;
    	cw->pOldPixmap = 0;
        }
        pNew->screen_x = pix_x;
        pNew->screen_y = pix_y;
        return TRUE;
    }