324 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			6.6 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);
 | |
| }
 |