324 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Copyright © 2005 Novell, Inc.
 | 
						|
 *
 | 
						|
 * 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
 | 
						|
 * Novell, Inc. not be used in advertising or publicity pertaining to
 | 
						|
 * distribution of the software without specific, written prior permission.
 | 
						|
 * Novell, Inc. makes no representations about the suitability of this
 | 
						|
 * software for any purpose. It is provided "as is" without express or
 | 
						|
 * implied warranty.
 | 
						|
 *
 | 
						|
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
						|
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 | 
						|
 * NO EVENT SHALL NOVELL, INC. 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.
 | 
						|
 *
 | 
						|
 * Author: David Reveman <davidr@novell.com>
 | 
						|
 */
 | 
						|
 | 
						|
#include "xgl.h"
 | 
						|
 | 
						|
static Bool
 | 
						|
xglAreaMoveIn (xglAreaPtr pArea,
 | 
						|
	       pointer	  closure)
 | 
						|
{
 | 
						|
    pArea->closure = closure;
 | 
						|
    pArea->state   = xglAreaOccupied;
 | 
						|
 | 
						|
    return (*pArea->pRoot->funcs->MoveIn) (pArea, closure);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
xglAreaMoveOut (xglAreaPtr pArea)
 | 
						|
{
 | 
						|
    (*pArea->pRoot->funcs->MoveOut) (pArea, pArea->closure);
 | 
						|
 | 
						|
    pArea->closure = (pointer) 0;
 | 
						|
    pArea->state   = xglAreaAvailable;
 | 
						|
}
 | 
						|
 | 
						|
static xglAreaPtr
 | 
						|
xglAreaCreate (xglRootAreaPtr pRoot,
 | 
						|
	       int	      level,
 | 
						|
	       int	      x,
 | 
						|
	       int	      y,
 | 
						|
	       int	      width,
 | 
						|
	       int	      height)
 | 
						|
{
 | 
						|
    xglAreaPtr pArea;
 | 
						|
    int	       n = 4;
 | 
						|
 | 
						|
    pArea = xalloc (sizeof (xglAreaRec) + pRoot->devPrivateSize);
 | 
						|
    if (!pArea)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    pArea->level   = level;
 | 
						|
    pArea->x	   = x;
 | 
						|
    pArea->y	   = y;
 | 
						|
    pArea->width   = width;
 | 
						|
    pArea->height  = height;
 | 
						|
    pArea->pRoot   = pRoot;
 | 
						|
    pArea->closure = (pointer) 0;
 | 
						|
    pArea->state   = xglAreaAvailable;
 | 
						|
 | 
						|
    while (n--)
 | 
						|
	pArea->pArea[n] = NULL;
 | 
						|
 | 
						|
    if (pRoot->devPrivateSize)
 | 
						|
	pArea->devPrivate.ptr = pArea + 1;
 | 
						|
    else
 | 
						|
	pArea->devPrivate.ptr = (pointer) 0;
 | 
						|
 | 
						|
    if (!(*pArea->pRoot->funcs->Create) (pArea))
 | 
						|
    {
 | 
						|
	free (pArea);
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return pArea;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
xglAreaDestroy (xglAreaPtr pArea)
 | 
						|
{
 | 
						|
    if (!pArea)
 | 
						|
	return;
 | 
						|
 | 
						|
    if (pArea->state == xglAreaOccupied)
 | 
						|
    {
 | 
						|
	xglAreaMoveOut (pArea);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	int n = 4;
 | 
						|
 | 
						|
	while (n--)
 | 
						|
	    xglAreaDestroy (pArea->pArea[n]);
 | 
						|
    }
 | 
						|
 | 
						|
    xfree (pArea);
 | 
						|
}
 | 
						|
 | 
						|
static xglAreaPtr
 | 
						|
xglAreaGetTopScoredSubArea (xglAreaPtr pArea)
 | 
						|
{
 | 
						|
    if (!pArea)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    switch (pArea->state) {
 | 
						|
    case xglAreaOccupied:
 | 
						|
	return pArea;
 | 
						|
    case xglAreaAvailable:
 | 
						|
	break;
 | 
						|
    case xglAreaDivided: {
 | 
						|
	xglAreaPtr tmp, top = NULL;
 | 
						|
	int	   i;
 | 
						|
 | 
						|
	for (i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
	    tmp = xglAreaGetTopScoredSubArea (pArea->pArea[i]);
 | 
						|
	    if (tmp && top)
 | 
						|
	    {
 | 
						|
		if ((*pArea->pRoot->funcs->CompareScore) (tmp,
 | 
						|
							  tmp->closure,
 | 
						|
							  top->closure) > 0)
 | 
						|
		    top = tmp;
 | 
						|
	    }
 | 
						|
	    else if (tmp)
 | 
						|
	    {
 | 
						|
		top = tmp;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	return top;
 | 
						|
    }
 | 
						|
    }
 | 
						|
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
xglAreaFind (xglAreaPtr pArea,
 | 
						|
	     int	width,
 | 
						|
	     int	height,
 | 
						|
	     Bool	kickOut,
 | 
						|
	     pointer	closure)
 | 
						|
{
 | 
						|
    if (pArea->width < width || pArea->height < height)
 | 
						|
	return FALSE;
 | 
						|
 | 
						|
    switch (pArea->state) {
 | 
						|
    case xglAreaOccupied:
 | 
						|
	if (kickOut)
 | 
						|
	{
 | 
						|
	    if ((*pArea->pRoot->funcs->CompareScore) (pArea,
 | 
						|
						      pArea->closure,
 | 
						|
						      closure) >= 0)
 | 
						|
		return FALSE;
 | 
						|
 | 
						|
	    xglAreaMoveOut (pArea);
 | 
						|
	} else
 | 
						|
	    return FALSE;
 | 
						|
 | 
						|
    /* fall-through */
 | 
						|
    case xglAreaAvailable:
 | 
						|
    {
 | 
						|
	if (pArea->level == pArea->pRoot->maxLevel ||
 | 
						|
	    (pArea->width == width && pArea->height == height))
 | 
						|
	{
 | 
						|
	    if (xglAreaMoveIn (pArea, closure))
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
	    int dx[4], dy[4], w[4], h[4], i;
 | 
						|
 | 
						|
	    dx[0] = dx[2] = dy[0] = dy[1] = 0;
 | 
						|
 | 
						|
	    w[0] = w[2] = dx[1] = dx[3] = width;
 | 
						|
	    h[0] = h[1] = dy[2] = dy[3] = height;
 | 
						|
 | 
						|
	    w[1] = w[3] = pArea->width - width;
 | 
						|
	    h[2] = h[3] = pArea->height - height;
 | 
						|
 | 
						|
	    for (i = 0; i < 2; i++)
 | 
						|
	    {
 | 
						|
		if (w[i])
 | 
						|
		    pArea->pArea[i] =
 | 
						|
			xglAreaCreate (pArea->pRoot,
 | 
						|
				       pArea->level + 1,
 | 
						|
				       pArea->x + dx[i],
 | 
						|
				       pArea->y + dy[i],
 | 
						|
				       w[i], h[i]);
 | 
						|
	    }
 | 
						|
 | 
						|
	    for (; i < 4; i++)
 | 
						|
	    {
 | 
						|
		if (w[i] && h[i])
 | 
						|
		    pArea->pArea[i] =
 | 
						|
			xglAreaCreate (pArea->pRoot,
 | 
						|
				       pArea->level + 1,
 | 
						|
				       pArea->x + dx[i],
 | 
						|
				       pArea->y + dy[i],
 | 
						|
				       w[i], h[i]);
 | 
						|
	    }
 | 
						|
 | 
						|
	    pArea->state = xglAreaDivided;
 | 
						|
 | 
						|
	    if (xglAreaFind (pArea->pArea[0], width, height, kickOut, closure))
 | 
						|
		return TRUE;
 | 
						|
	}
 | 
						|
    } break;
 | 
						|
    case xglAreaDivided:
 | 
						|
    {
 | 
						|
	xglAreaPtr topArea;
 | 
						|
	int	   i, rejected = FALSE;
 | 
						|
 | 
						|
	for (i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
	    if (pArea->pArea[i])
 | 
						|
	    {
 | 
						|
		if (pArea->pArea[i]->width >= width &&
 | 
						|
		    pArea->pArea[i]->height >= height)
 | 
						|
		{
 | 
						|
		    if (xglFindArea (pArea->pArea[i], width, height, kickOut,
 | 
						|
				     closure))
 | 
						|
			return TRUE;
 | 
						|
 | 
						|
		    rejected = TRUE;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
	if (rejected)
 | 
						|
	    return FALSE;
 | 
						|
 | 
						|
	topArea = xglAreaGetTopScoredSubArea (pArea);
 | 
						|
	if (topArea)
 | 
						|
	{
 | 
						|
	    if (kickOut)
 | 
						|
	    {
 | 
						|
		if ((*pArea->pRoot->funcs->CompareScore) (topArea,
 | 
						|
							  topArea->closure,
 | 
						|
							  closure) >= 0)
 | 
						|
		    return FALSE;
 | 
						|
	    } else
 | 
						|
		return FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
	    xglAreaDestroy (pArea->pArea[i]);
 | 
						|
	    pArea->pArea[i] = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	pArea->closure = (pointer) 0;
 | 
						|
	pArea->state   = xglAreaAvailable;
 | 
						|
	if (xglFindArea (pArea, width, height, TRUE, closure))
 | 
						|
	    return TRUE;
 | 
						|
 | 
						|
    } break;
 | 
						|
    }
 | 
						|
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xglRootAreaInit (xglRootAreaPtr	    pRoot,
 | 
						|
		 int		    maxLevel,
 | 
						|
		 int		    width,
 | 
						|
		 int		    height,
 | 
						|
		 int		    devPrivateSize,
 | 
						|
		 xglAreaFuncsPtr    funcs,
 | 
						|
		 pointer	    closure)
 | 
						|
{
 | 
						|
    pRoot->maxLevel	  = maxLevel;
 | 
						|
    pRoot->funcs	  = funcs;
 | 
						|
    pRoot->devPrivateSize = devPrivateSize;
 | 
						|
    pRoot->closure	  = closure;
 | 
						|
 | 
						|
    pRoot->pArea = xglAreaCreate (pRoot, 0, 0, 0, width, height);
 | 
						|
    if (!pRoot->pArea)
 | 
						|
	return FALSE;
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xglRootAreaFini (xglRootAreaPtr pRoot)
 | 
						|
{
 | 
						|
    xglAreaDestroy (pRoot->pArea);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xglLeaveArea (xglAreaPtr pArea)
 | 
						|
{
 | 
						|
    xglAreaMoveOut (pArea);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
xglWithdrawArea (xglAreaPtr pArea)
 | 
						|
{
 | 
						|
    pArea->closure = NULL;
 | 
						|
    pArea->state   = xglAreaAvailable;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
xglFindArea (xglAreaPtr pArea,
 | 
						|
	     int	width,
 | 
						|
	     int	height,
 | 
						|
	     Bool	kickOut,
 | 
						|
	     pointer	closure)
 | 
						|
{
 | 
						|
    if (width < 1 || height < 0)
 | 
						|
	return FALSE;
 | 
						|
 | 
						|
    return xglAreaFind (pArea, width, height, kickOut, closure);
 | 
						|
}
 |