/* $Header: /cec/src/nestor/servers/R3/shXlib/resources.c,v 1.3 90/06/19 10:23:15 altenhof Exp $ */

#define NEED_RESOURCES    /* we need the resource type defs here */

#include "XmuXlibint.h"

#include "map.h"

#define ALLOC_AT_ONCE 5

#ifndef XmuXMask 
#define XmuXCreate 1  /* -- same as in resources.h -- */
#define XmuXUpdate 2

#define XmuXMask ( PropertyChangeMask )
#endif

#define XMUXGCFLAGS ( GCTile | GCStipple | GCClipMask |\
		      GCFont | GCForeground | GCBackground ) 

#define RIGHTTYPE( ptr ) \
	   ( ptr->type &  ( RT_WINDOW ) )

static
MUXResourceInfoPtr _FreeInfos = NullResourceInfoPtr ;

static 
void
PrintWindowInfo( ) ,
PrintGCInfo( ) ,
PrintPixmapInfo( ) ,
PrintCursorInfo( ) ,
PrintFontInfo( ) ;


static
long
ResourceType( dpy , rID )

Display *dpy ;
XID      rID ;

{   register MUXResourceInfoPtr entry ;

    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
         entry != NullResourceInfoPtr ;
        entry = entry->next )
	if( entry->id == rID )
	    return( entry->type ) ;
    return( RT_INVALID ) ;
}

/*
 * -- CompareDepth :  compare resource info's depth with the depth passed
 * --                 as second argument
 *
 * -- Need this if drawable that was used to create a GC has gone and we have
 * -- to find another drawable with the same depth 
 */
static
int
CompareDepth( info , depth )

MUXResourceInfoPtr info ;
int                depth ;

{
    /* -- code assumes that info->type RT_WINDOW or RT_PIXMAP -- */

    if( info->type & RT_WINDOW )
	return( info->u.win_info->depth == depth ) ;
    else
	return( info->u.pmap_info->depth == depth ) ;
}

/*
 * -- GetDepth : find depth of resource rID
 *
 * -- Need this in InsertWindowInfo/InsertGCInfo: must retrieve depth from
 * -- parent/drawable resource info
 */
static
int
GetDepth( dpy , rID , depth ) 

Display *dpy ;
XID      rID ;
int     *depth ;

{   MUXResourceInfoPtr entry ;

    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
	 entry != NullResourceInfoPtr ;
	 entry = entry->next )

	if( entry->id == rID )
	{
	    if( !entry->used )
		return( False ) ;
	    if( entry->type & RT_WINDOW )
	    {
		*depth  = entry->u.win_info->depth ;
		return( True ) ;
	    }
	    else
		if( entry->type & RT_PIXMAP )
		{
		    *depth  = entry->u.pmap_info->depth ;
		    return( True ) ;
		}
		else
		{
		    /*-- wrong type -- */
		    XmuXErrorF( "GetDepth: Wrong type %d!\n" ,
			        entry->type ) ;
		    return( False ) ;
		}
	}

    return( False ) ;
}

/*
 * -- GetVisualID : determine the visual ID that was used to create this
 * --               resource (window)
 * 
 * -- Need this in InsertWindowInfo if window was created the simple way 
 * -- (visual == CopyFromParent)
 */
int
GetVisualID( dpy , rID , vid ) 

Display *dpy ;
XID      rID ,
        *vid ;

{   MUXResourceInfoPtr entry ;

    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
	 entry != NullResourceInfoPtr ;
	 entry = entry->next )

	if( entry->id == rID )
	{
	    if( !entry->used )
		return( False ) ;
	    if( entry->type & RT_WINDOW )
	    {
		*vid  = entry->u.win_info->visualid ;
		return( True ) ;
	    }
	    else
	    {
		/*-- wrong type -- */
		XmuXErrorF( "GetVisualID: Wrong type %d!\n" ,
			     entry->type ) ;
		return( False ) ;
	    }
	}

    return( False ) ;
}

/*
 * -- RemoveDrawableReference : Reset drawable attribute in GC/Colormap/
 * --                           Pixmap infos whose value is equal to drawable
 * --                           (second argument)
 */
static
RemoveDrawableReference( dpy , drawable )

Display  *dpy ;
Drawable  drawable ;

{   MUXResourceInfoPtr entry ;

#ifdef DEBUG
    CheckDisplay( dpy , "GetClientResource" ) ;
#endif
    XmuXdebug( debug_resources ,"\nreference 0x%lx in ", drawable ) ;
    /* 
     * -- remove all references (i.e. info->drawabale == drawable) from the  
     * -- list in gc_infos, cmap_infos, pmap_infos
     */
    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
	 entry != NullResourceInfoPtr ;
	 entry = entry->next )
	
	switch( entry->type )
	{
	    
	case RT_GC :
	    if( entry->u.gc_info->drawable == drawable )
	    {
		XmuXdebug( debug_resources , " GC 0x%lx" , 
			   entry->id ) ;
		entry->u.gc_info->drawable = None ;
	    }
	    break ;
	    
	case RT_PIXMAP :
	    if( entry->u.pmap_info->drawable == drawable )
	    {
                XmuXdebug( debug_resources , " Pixmap 0x%lx" ,
                           entry->id ) ;
		entry->u.pmap_info->drawable = None ;
	    }
	    break ;
	    
	case RT_COLORMAP :
	    if( entry->u.cmap_info->window == drawable )
	    {
                XmuXdebug( debug_resources , " Colormap 0x%lx" ,
                           entry->id ) ;
		entry->u.cmap_info->window = None ;
	    }
	    break ;
	    
	default :
	    break ;
	}
    XmuXdebug( debug_resources , "removed\n" ) ;
}

/* 
 * -- NewResource :  local resource allocation routine
 */
static
MUXResourceInfoPtr
NewResource( )

{   register MUXResourceInfoPtr new ;

    if( _FreeInfos == NullResourceInfoPtr )
    {
	if( ( new = ( MUXResourceInfoPtr ) 
	      Xmalloc( sizeof( MUXResourceInfo ) ) ) == NullResourceInfoPtr )
	    XmuXFatalError( "NewResource: Out of memory!\n" ) ;
    }
    else
    {
	new        = _FreeInfos ;
	_FreeInfos = _FreeInfos->next ;
	new->next  = NullResourceInfoPtr ;
    }
    return( new ) ;
}

/*
 * -- FreeResourceInfo : local deallocation routine
 */
static
void
FreeResourceInfo( info )

MUXResourceInfoPtr info ;

{
    XmuXdebug( debug_resources , "resource 0x%lx (type RT_" , info->id ) ;
    switch( info->type )
    {
    case RT_WINDOW :
	XmuXdebug( debug_resources , "WINDOW) removed\n" ) ;
	Xfree( ( char * ) info->u.win_info ) ;
	break ;

    case RT_GC :
        XmuXdebug( debug_resources , "GC) removed\n" ) ;

	/* -- free the gc here ( is hasn't been freed in XFreeGC !! ) -- */
	Xfree( ( char * ) info->u.gc_info->gc ) ;
	Xfree( ( char * ) info->u.gc_info ) ;
	break ;

    case RT_PIXMAP :
        XmuXdebug( debug_resources , "PIXMAP) removed\n" ) ;
	Xfree( ( char * ) info->u.pmap_info ) ;
	break ;

    case RT_CURSOR :
        XmuXdebug( debug_resources , "CURSOR) removed\n" ) ;
	Xfree( ( char * ) info->u.curs_info ) ;
	break ;

    case RT_FONT :
	XmuXdebug( debug_resources , "FONT) removed\n" ) ;
	Xfree( ( char * ) info->u.font_info->name ) ;
	Xfree( ( char * ) info->u.font_info ) ;
	break ;

    case RT_COLORMAP :
        XmuXdebug( debug_resources , "COLORMAP) removed\n" ) ;
	Xfree( ( char * ) info->u.cmap_info->sh_cells ) ;
	while( info->u.cmap_info->pr_cells )
	{    register MUXPrivateColorCells *pnext = 
		                            info->u.cmap_info->pr_cells->next ;
	     Xfree( ( char * ) info->u.cmap_info->pr_cells->pixels ) ;
	     if( info->u.cmap_info->pr_cells->planes ) 
		 Xfree( ( char * ) info->u.cmap_info->pr_cells->planes ) ;
	     Xfree( ( char * ) info->u.cmap_info->pr_cells ) ;
	     info->u.cmap_info->pr_cells = pnext ;
	}
	Xfree( ( char * ) info->u.cmap_info ) ;
	break ;
    case RT_GCPIXELS :
	XmuXdebug( debug_resources , "GCPIXELS) removed\n" ) ;
	Xfree( ( char * ) info->u.gcpix_info ) ;
	break ;
    }
    
    info->used = False ;
    info->next = _FreeInfos ;
    _FreeInfos = info ;
}

/*
 * -- A kind of "generic" allocation routine :
 * -- it allocates a new MUXResourceInfo structure and the type specific data
 * -- (the resource type is passed as an argument). Initializes the new 
 * -- resource info with valid values
 */
static 
MUXResourceInfoPtr
AllocAndInitResource( type , id ) 

int type ;   /* the resource type */
XID id ;

{   MUXResourceInfoPtr new ;

    if( ( new = NewResource( ) ) == NullResourceInfoPtr )
	XmuXFatalError( "Out of memory! Can't allocate new resource!\n" ) ;

    new->next       = NullResourceInfoPtr ;
    new->used       = True ;
    new->id         = id ;

    /* -- allocate space for type specific data -- */
    switch( type )
    {
    case RT_WINDOW :
	if( ( new->u.win_info = ( MUXWindowInfoPtr ) 
	                        Xmalloc( sizeof( MUXWindowInfo ) ) ) == 
	    NullWindowInfoPtr )
	XmuXFatalError( "Out of memory! Can't allocate new resource!\n" ) ;
	new->type       = RT_WINDOW ;
	new->u.win_info->window        = id ;
	new->u.win_info->bg_pixel      = 1L ;
	new->u.win_info->border_pixel  = 0L ;
	new->u.win_info->bg_pmap       = None ;
	new->u.win_info->border_pmap   = CopyFromParent ;
	new->u.win_info->cursor        = None ;
	new->u.win_info->flags         = 0L ;
	new->u.win_info->grabs         = 0L ;
	new->u.win_info->button_grabs  = NULL ;
	new->u.win_info->key_grabs     = NULL ;
	break ;

    case RT_GC :
	if( ( new->u.gc_info = ( MUXGCInfoPtr ) 
	                        Xmalloc( sizeof( MUXGCInfo ) ) ) == 
	    NullGCInfoPtr )
	XmuXFatalError( "Out of memory! Can't allocate new resource!\n" ) ;
	new->type             = RT_GC ;
	new->u.gc_info->gid   = id ;
	new->u.gc_info->flags = 0L ;
	break ;

    case RT_PIXMAP :
	if( ( new->u.pmap_info = ( MUXPixmapInfoPtr ) 
	                        Xmalloc( sizeof( MUXPixmapInfo ) ) ) == 
	    NullPixmapInfoPtr )
	XmuXFatalError( "Out of memory! Can't allocate new resource!\n" ) ;
	new->type                = RT_PIXMAP ;
	new->u.pmap_info->pixmap = id ;
	break ;

    case RT_CURSOR :
	if( ( new->u.curs_info = ( MUXCursorInfoPtr ) 
	                        Xmalloc( sizeof( MUXCursorInfo ) ) ) == 
	    NullCursorInfoPtr )
	XmuXFatalError( "Out of memory! Can't allocate new resource!\n" ) ;
	new->type                = RT_CURSOR ;
	new->u.curs_info->cursor = id ;
	break ;

    case RT_FONT :
	if( ( new->u.font_info = ( MUXFontInfoPtr ) 
	                        Xmalloc( sizeof( MUXFontInfo ) ) ) == 
	    NullFontInfoPtr )
	XmuXFatalError( "Out of memory! Can't allocate new resource!\n" ) ;
	new->type              = RT_FONT ;
	new->u.font_info->font = id ;
	break ;

    case RT_COLORMAP :
	if( ( new->u.cmap_info = ( MUXColormapInfoPtr ) 
	                        Xmalloc( sizeof( MUXColormapInfo ) ) ) == 
	    NullColormapInfoPtr )
	XmuXFatalError( "Out of memory! Can't allocate new resource!\n" ) ;
	new->type                  = RT_COLORMAP ;
	new->u.cmap_info->colormap = id ;
	new->u.cmap_info->sh_allocated = 0 ;
	new->u.cmap_info->sh_cells = NULL ;
	new->u.cmap_info->pr_cells = NULL ;
	break ;

    case RT_GCPIXELS :
	if( ( new->u.gcpix_info = ( MUXGCPixelsInfoPtr )
	                         Xmalloc( sizeof( MUXGCPixelsInfo ) ) ) ==
	    NullGCPixelsInfoPtr )
        XmuXFatalError( "Out of memory! Can't allocate new resource!\n" ) ;
	new->type               = RT_GCPIXELS ;
	new->u.gcpix_info->gid  = id ;
        break ;
    default :
	XmuXFatalError( "No resource allocation (wrong resource type)!\n" ) ;
	break ;
    }
    return( new ) ;
}
/*
 * -- we use three "generic" routines :
 * -- InsertClientResource - to insert a new resource information
 * -- GetClientResource    - to retrieve an existing resource information
 * -- RemoveClientResource - to remove an existing resource information
 * -- 
 * -- for every resource type , we use "specific" routines that 
 * -- call the corresponding "generic" with the appropriate type argument
 */

static
void
InsertClientResource( dpy , info_ptr ) 

Display            *dpy ;
MUXResourceInfoPtr  info_ptr ;

{ 

#ifdef DEBUG
    CheckDisplay( dpy , "InsertClientResource" ) ;
#endif

    if( MUXClientResources[ ConnectionNumber( dpy ) ].tail == 
        NullResourceInfoPtr )
	MUXClientResources[ ConnectionNumber( dpy ) ].head =
	MUXClientResources[ ConnectionNumber( dpy ) ].tail = info_ptr ;
    else
    {
	MUXClientResources[ ConnectionNumber( dpy ) ].tail->next = 
	    info_ptr ;
	MUXClientResources[ ConnectionNumber( dpy ) ].tail       = 
	    MUXClientResources[ ConnectionNumber( dpy ) ].tail->next ;
    }
}

static
MUXResourceInfoPtr
GetClientResource( dpy , rID , type )

Display *dpy ;
XID      rID ;
long     type ;

{   MUXResourceInfoPtr entry ;

#ifdef DEBUG
    CheckDisplay( dpy , "GetClientResource" ) ;
#endif

    /*
     * -- use resource ID and resource type to find the right entry
     * -- special case : resource type == RT_SUBWINDOW 
     * --                --> use parent ID to find the right entry
     * --                --> only return entries that are still used
     */
    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
	 entry != NullResourceInfoPtr ;
	 entry = entry->next )

	if( type & RT_SUBWINDOW )
	{
	    if( ( entry->type &  RT_WINDOW ) && 
	        entry->u.win_info->parent == rID && entry->used )
		return( entry ) ;
	}
	else
	    if( entry->id == rID && ( entry->type & type ) && entry->used ) 
	    /* -- found it -- */
	    return( entry ) ;

    /* -- we've failed -- */
    return( NullResourceInfoPtr ) ;
}

static
MUXResourceInfoPtr
RemoveClientResource( dpy , rID , type )

Display *dpy ;
XID      rID ;
long     type ;

{   MUXResourceInfoPtr curr , pred ;

#ifdef DEBUG
    CheckDisplay( dpy , "RemoveClientResource" ) ;
#endif

    curr =
    pred = MUXClientResources[ ConnectionNumber( dpy ) ].head ;

    /*
     * -- use resource ID and resource type to find the right entry
     * -- special case : resource type == RT_SUBWINDOW --> use parent ID
     * --                to find the right entry
     */
    if( curr == NullResourceInfoPtr )
    {
	XmuXErrorF( "Resource 0x%lx not removed (list %d empty)!\n" ,
	        rID , ConnectionNumber( dpy ) ) ;
	return( NullResourceInfoPtr ) ;
    }

    /* special case : remove the head of the list -- */
    if( ( ( type & RT_SUBWINDOW ) && ( curr->type &  RT_WINDOW ) &&
	  curr->u.win_info->parent == rID ) ||
        ( curr->id == rID && ( curr->type &  type ) ) )
    {
	/* -- is there only one entry in the list ? -- */
	if( MUXClientResources[ ConnectionNumber( dpy ) ].head == 
	    MUXClientResources[ ConnectionNumber( dpy ) ].tail )

	    MUXClientResources[ ConnectionNumber( dpy ) ].head = 
	    MUXClientResources[ ConnectionNumber( dpy ) ].tail = NullResourceInfoPtr ;

	else
	    MUXClientResources[ ConnectionNumber( dpy ) ].head = curr->next ;

	curr->next = NullResourceInfoPtr ;
    }
    /* -- search through the list -- */
    else
	for( 
	     curr = curr->next ;
	     curr != NullResourceInfoPtr ;
	     pred = curr , curr = curr->next 
	   )
	    /* 
	     * -- we've found it ? 
	     * -- Note special case for removing subwindows 
	     */
	    if( ( (  type & RT_SUBWINDOW ) && ( curr->type & RT_WINDOW ) && 
		  curr->u.win_info->parent == rID ) || 
	        ( curr->id == rID && ( curr->type & type ) ) )
	    {
		pred->next = curr->next ;
		curr->next = NullResourceInfoPtr ;
		/* -- do we remove the tail ? -- */
		if( curr == MUXClientResources[ ConnectionNumber( dpy ) ].tail )
		    MUXClientResources[ ConnectionNumber( dpy ) ].tail = pred ;
		/* -- exit the loop -- */
		break ;
	    }

    /* -- if we haven't found it , curr == NullResourceInfoPtr -- */
    return( curr ) ;
}

#define FREEANDADVANCE( ptr )  \
            {   register MUXResourceInfoPtr tmp = ptr ;\
		ptr = ptr->next ;\
		tmp->next = NullResourceInfoPtr ;\
		FreeResourceInfo( tmp ) ;\
	    }

/*
 * -- XmuXCleanupResources : remove all unused infos from the resource list 
 */
void
XmuXCleanupResources( dpy )

Display *dpy ;

{   MUXResourceInfoPtr curr , pred ;

    if( !MUXClientResources[ ConnectionNumber( dpy ) ].update )
	/* -- no previously freed resource info in list -- */
	return ;


    XmuXdebug( debug_resources , "Cleanup resource list %d\n" , 
	       ConnectionNumber( dpy ) ) ;

    curr = MUXClientResources[ ConnectionNumber( dpy ) ].head ;

    if( curr == NullResourceInfoPtr )
	/* -- list is empty , nothing to do -- */
	return ;
    /* -- imaginary list element BEFORE head of list -- */
    pred = NullResourceInfoPtr ;
    
    while( curr != NullResourceInfoPtr )
    {
	/* -- next candidate ? -- */
	if( ! curr->used )
	{
	    /* -- head of list ? -- */
	    if( pred == NullResourceInfoPtr )
	    {
		/* -- only one list element ? -- */
		if( MUXClientResources[ ConnectionNumber( dpy ) ].head ==
		    MUXClientResources[ ConnectionNumber( dpy ) ].tail )

		    MUXClientResources[ ConnectionNumber( dpy ) ].head =
		    MUXClientResources[ ConnectionNumber( dpy ) ].tail =
			NullResourceInfoPtr ;
		else
		    MUXClientResources[ ConnectionNumber( dpy ) ].head = 
			curr->next ;
		/* -- free the entry -- */
		FREEANDADVANCE( curr ) ;
	    }
	    else
	    {
		pred->next = curr->next ;
		/* -- remove the tail ? -- */
		if(curr == MUXClientResources[ ConnectionNumber( dpy ) ].tail)
		    MUXClientResources[ ConnectionNumber( dpy ) ].tail = 
			pred ;
		FREEANDADVANCE( curr ) ;
	    }
	}
	else
	{
	    /* -- advance in list -- */
	    pred = curr ;
	    curr = curr->next ;
	}
    }
    MUXClientResources[ ConnectionNumber( dpy ) ].update = False ;
}

#undef FREEANDADVANCE

/* 
 * -- two additional routines used to handle top-level windows in 
 * -- XCreateWindow , XCreateSimpleWindows and XmuXReplicate
 */

/*
 * -- XmuXIsRootWindow : find out if window is a root window
 *
 * -- If window is a root window, return the screen number, else return -1
 */
int
XmuXIsRootWindow( dpy , window )

Display *dpy ;
Window   window ;

{   register int i ;

#ifdef DEBUG
    CheckDisplay( dpy , "XmuXIsRootWindow" ) ;
#endif

    for( i = 0 ; i < ScreenCount(dpy ) ; i++ )
	if( window == RootWindow( dpy , i ) )
	    /* -- return the screen number -- */
	    return( i ) ;

    return( -1 ) ;
}

/*
 * -- XmuXMustAddEvents : find out if we must add events for this window
 */
Bool
XmuXMustAddEvents( dpy , wid , mode )

Display *dpy ;
Window   wid ;
int      mode ;  /* -- if mode == XmuXCreate, wid is the parent ID
		       else it's a top-level ID -- */

{ 

    if( mode == XmuXCreate )
	return( XmuXStoreResources( dpy ) &&
	        ( XmuXIsRootWindow( dpy , wid ) != -1 ) ) ;
    else
	return( XmuXStoreResources( dpy ) &&
	        XmuXIsToplevel( dpy , wid ) ) ;
}

/*
 * -- the eight(!) "window routines"
 * -- one additional routine to update resource attributes
 * -- four routines to maintain grab specific information
 */

void
XmuXInsertWindowInfo( dpy , window , parent , visualid , depth ) 

Display        *dpy ;  /* index to the resource table */
XID             window ,
                parent ,
                visualid ;
int             depth ;

{   MUXResourceInfoPtr new_entry ;
    int                screen ,
                       pdepth ,
                       XmuXIsRootWindow( ) ;

    /* -- don't check for errors here , it's done by AllocAndInitResource -- */
    new_entry             = AllocAndInitResource( RT_WINDOW , window ) ;

    /* -- space has been allocated by AllocAndInitResource -- */
    new_entry->u.win_info->parent        = parent ;
   
    /*
     * -- must determine the depth and the visual ID
     */
    if( ( screen = XmuXIsRootWindow( dpy , parent ) ) != -1 )
    {
	/* -- a top level window  -- */
	new_entry->u.win_info->depth    = DefaultDepth( dpy , screen ) ;
	if( visualid == CopyFromParent )
	    new_entry->u.win_info->visualid = 
		DefaultVisual( dpy ,screen )->visualid ;
	else
	    new_entry->u.win_info->visualid = visualid ;
    }
    else
    {
	if( visualid == CopyFromParent )
	{   XID vid ;
	    
	    /*
	     * -- determine parent's visual id
	     */
	    if( GetVisualID( dpy , parent , &vid ) )
		new_entry->u.win_info->visualid = vid ;
	    else
		XmuXFatalError(
		   "XmuXInsertWindowInfo: Can't find parent's 0x%lx info!\n" ,
		    parent ) ;
	}
	else
	    new_entry->u.win_info->visualid = visualid ;

	/*
	 * -- depth == 0 has two possible meanings :
	 * -- either it's from XCreateSimpleWindow where depth is 
	 * -- "CopyFromParent" or it's an InputOnly window. An exact solution
	 * -- would need the class attribute here, but it's CopyFromParent
	 * -- too in XCreateSimpleWindow. So, we treat depth == 0 as 
	 * --  "CopyFromParent". We fix this "bug" in XmuXReplicate where
	 * -- we know the window's class; otherwise we may use an InputOnly 
	 * -- window in XmuXMatchDrawable
	 */
	if( depth == 0 ) 
	    if( GetDepth( dpy , parent , &pdepth ) )
		new_entry->u.win_info->depth   = pdepth ;
	    else
		XmuXFatalError( 
		       "InsertWindowInfo: Can't find parent's 0x%lx info!\n" ,
		       parent ) ;
	else
	    new_entry->u.win_info->depth = depth ;
    }
    /* -- insert it in client's list -- */
    InsertClientResource( dpy , new_entry ) ;
    XmuXdebug( debug_resources , 
	       "new resource 0x%lx info (type RT_WINDOW) inserted\n" ,
	       window ) ;
    PrintWindowInfo( dpy , new_entry->u.win_info ) ;
}

MUXWindowInfoPtr
GetWindowInfo( dpy , window )

Display *dpy ;  /* index to the resource table */
XID      window ;

{   MUXResourceInfoPtr resource_info ;

    resource_info = GetClientResource( dpy , window , RT_WINDOW ) ;
    
    return( ( resource_info != NullResourceInfoPtr )
	    ? resource_info->u.win_info 
	    : NullWindowInfoPtr ) ;
}

void
XmuXUpdateWindowInfo( dpy , window , flags , attributes ) 

Display              *dpy ;
XID                   window ;
unsigned long         flags ;
XSetWindowAttributes *attributes ;

{   MUXWindowInfoPtr win_info ;

    if( ( win_info = GetWindowInfo( dpy , window ) ) !=
        NullWindowInfoPtr ) 
    {
	XmuXdebug( debug_resources , "Window 0x%lx updated:\n" , window ) ;
	/*
	 * -- What the docu says : 
	 * -- "If you specify a background_pixel ,
	 * -- it overrrides either the default background_pixmap or any value
	 * -- you may have set in the background_pixmap member...If you set 
	 * -- the backgrpound_pixmap, it overrides the default 
	 * -- background_pixmap." 
	 * -- The same applies to the border_pixel and border_pixmap values.
	 * -- That's why we use this order 
	 */
	if( flags & CWBackPixmap )
	{
	    win_info->flags |= CWBackPixmap ;
	    /* -- reset background pixel bit -- */
	    win_info->flags &= ~CWBackPixel ;
	    win_info->bg_pmap = attributes->background_pixmap ;
	    XmuXdebug( debug_resources , "bg pixmap 0x%lx\n" , 
		       win_info->bg_pmap ) ;
	}
	if( flags & CWBackPixel )
	{
	    win_info->flags   |= CWBackPixel ;
	    /* -- background pixel overrides background pixmap -- */
	    win_info->flags   &= ~CWBackPixmap ;
	    win_info->bg_pixel = attributes->background_pixel ;
            XmuXdebug( debug_resources , "bg pixel 0x%lx\n" ,
                       win_info->bg_pixel ) ;
        }
	if( flags & CWBorderPixmap )
	{
	    win_info->flags |= CWBorderPixmap ;
            /* -- reset border pixel bit -- */
            win_info->flags &= ~CWBorderPixel ;
	    win_info->border_pmap = attributes->border_pixmap ;
            XmuXdebug( debug_resources , "border pixmap 0x%lx\n" ,
                       win_info->border_pmap ) ;
        }
	if( flags & CWBorderPixel )
	{
	    win_info->flags   |= CWBorderPixel ;
            /* -- background pixel overrides background pixmap -- */
            win_info->flags   &= ~CWBorderPixmap ;
	    win_info->border_pixel = attributes->border_pixel ;
            XmuXdebug( debug_resources , "border pixel 0x%lx\n" ,
                       win_info->border_pixel ) ;
        }
	if( flags & CWCursor )
	{
	    win_info->flags |= CWCursor ;
	    win_info->cursor = attributes->cursor ;
            XmuXdebug( debug_resources , "cursor 0x%lx\n" ,
                       win_info->cursor ) ;
	}
	if( flags & CWColormap )
	{
	    win_info->flags   |= CWColormap ;
	    win_info->colormap = attributes->colormap ;
	    XmuXdebug( debug_resources , "colormap 0x%lx\n" ,
		       win_info->colormap ) ;
	}
    }
}

void
XmuXRemoveWindowInfo( dpy , window )

Display *dpy ;  /* index to the resource table */
XID      window ;

{   MUXResourceInfoPtr resource_info ;
    void               XmuXRemoveSubwindowInfos( ) ;

    resource_info = GetClientResource( dpy , window , RT_WINDOW ) ;

    if( resource_info != NullResourceInfoPtr )
    {
	MUXClientResources[ ConnectionNumber( dpy ) ].update = True ;
	/* -- if this is a toplevel window, remove the toplevel info -- */
	XmuXRemoveToplevelInfo( dpy , window ) ;
	/* -- remove all subwindow infos -- */
	XmuXRemoveSubwindowInfos( dpy , window ) ;
	resource_info->used = False ;
	/* -- remove all references of this window -- */
	RemoveDrawableReference( dpy , resource_info->id ) ;
    }
    else
	XmuXErrorF( debug_resources , "window info 0x%lx not found!\n" , 
		    window ) ;
}

void
XmuXRemoveSubwindowInfos( dpy , window )

Display *dpy ;  /* index to the resource table */
XID window ;

{   MUXResourceInfoPtr resource_info ;

    while( ( resource_info = 
	       GetClientResource( dpy , window , RT_SUBWINDOW ) ) != 
	     NullResourceInfoPtr )
    {
	/*
	 * -- that's the only place where we can remove the ID's
	 */
	XmuXRemoveWindowID( dpy , resource_info->id ) ;
	/* -- we recursive descent down the window tree -- */
	XmuXRemoveSubwindowInfos( dpy ,
				  resource_info->id ) ;
	resource_info->used = False ;
	/* -- remove all references of this window -- */
	RemoveDrawableReference( dpy , resource_info->id ) ;
    }
}

static
void
PrintWindowInfo( dpy , win_info  )

Display          *dpy ;  /* index to the resource table */
MUXWindowInfoPtr  win_info ;

{
    XmuXdebug( debug_resources , "resource 0x%lx type RT_WINDOW values :\n" ,
	   win_info->window ) ;
    XmuXdebug( debug_resources , "parent = 0x%lx\n" , win_info->parent ) ;
}

void
XmuXSetWindowButtonGrab( dpy , grab_window , button , modifiers ,
			 owner_events , event_mask , pointer_mode ,
			 keyboard_mode , confine_to , curs )
Display      *dpy ;
XID           grab_window ;
unsigned int  modifiers; /* CARD16 */
unsigned int  button; /* CARD8 */
Bool          owner_events;
unsigned int  event_mask; /* CARD16 */
int           pointer_mode, 
              keyboard_mode;
Window        confine_to;
Cursor        curs;

{   register MUXWindowInfoPtr win_info ;

    if( ( win_info = GetWindowInfo( dpy , grab_window ) ) != 
        NullWindowInfoPtr ) 
    {   register GrabButtonParams *bgrab ;

	if( ( bgrab = 
	      ( GrabButtonParams * ) Xmalloc( sizeof( GrabButtonParams ) ) ) ==
	     NULL )
	    XmuXFatalError( "XmuXSetWindowButtonGrab: Out of memory!\n" ) ;

	bgrab->modifiers     = modifiers ;
	bgrab->button        = button ;
	bgrab->owner_events  = owner_events ;
	bgrab->event_mask    = event_mask ;
	bgrab->pointer_mode  = pointer_mode ;
	bgrab->keyboard_mode = keyboard_mode ;
	bgrab->confine_to    = confine_to ;
	bgrab->cursor        = curs ;

	/* -- insert it in the button grab list -- */
	bgrab->next             = win_info->button_grabs ;
	win_info->button_grabs  = bgrab ;
	win_info->grabs        |= ButtonGrabbed ;
	XmuXdebug( debug_resources , "Add button grab %d for window 0x%lx\n" ,
		   button , grab_window ) ;
	
    }
    else
	XmuXErrorF( "XmuXSetWindowButtonGrab: window 0x%lx not found!\n" , 
		    grab_window ) ;
}

void
XmuXRemoveWindowButtonGrab( dpy , grab_window , button , modifiers )

Display      *dpy;
Window        grab_window;
unsigned int  button ;
unsigned int  modifiers ;

{   register MUXWindowInfoPtr win_info ;

    if( ( win_info = GetWindowInfo( dpy , grab_window ) ) != 
        NullWindowInfoPtr ) 
    {   register GrabButtonParams *pred , *curr ;
	
	pred = curr = win_info->button_grabs ;
	if( curr == NULL )
	{
	    XmuXErrorF( "XmuXRemoveWindowButtonGrab: list 0x%lx empty!\n" ,
		        grab_window ) ;
	    return ;
	}
	/* -- remove the head ? -- */
	if( curr->button == button && curr->modifiers == modifiers )
	{
	    win_info->button_grabs = win_info->button_grabs->next ;
	    if( win_info->button_grabs == NULL ) 
		/* -- no more button grabs -- */
		win_info->grabs &= ~ButtonGrabbed ;
	    Xfree( ( char * ) curr ) ;
	    return ;
	}
	/* -- search through the list -- */
	for( curr = curr->next ; curr != NULL ;
	     pred = curr , curr = curr->next )
	    if( curr->button == button && curr->modifiers == modifiers ) 
	    {
		pred->next = curr->next ;
		Xfree( ( char * ) curr ) ;
		return ;
	    }
	XmuXErrorF( "XmuXRemoveWindowButtonGrab: list 0x%lx entry not found!\n" ,
                        grab_window ) ;
    }
    else
	XmuXErrorF( "XmuXRemoveWindowButtonGrab: window 0x%lx not found!\n" ,
		    grab_window ) ;
}

void
XmuXSetWindowKeyGrab( dpy , grab_window , key , modifiers ,
		      owner_events , pointer_mode ,
		      keyboard_mode )
Display      *dpy;
Window        grab_window;
int           key;
unsigned int  modifiers;
Bool          owner_events;
int           pointer_mode, 
              keyboard_mode;

{   register MUXWindowInfoPtr win_info ;

    if( ( win_info = GetWindowInfo( dpy , grab_window ) ) != 
        NullWindowInfoPtr ) 
    {   register GrabKeyParams *kgrab ;

	if( ( kgrab = 
	      ( GrabKeyParams * ) Xmalloc( sizeof( GrabKeyParams ) ) ) ==
	     NULL )
	    XmuXFatalError( "XmuXSetWindowKeyGrab: Out of memory!\n" ) ;

	kgrab->modifiers     = modifiers ;
	kgrab->key           = key ;
	kgrab->owner_events  = owner_events ;
	kgrab->pointer_mode  = pointer_mode ;
	kgrab->keyboard_mode = keyboard_mode ;

	/* -- insert it in the key grab list -- */
	kgrab->next          = win_info->key_grabs ;
	win_info->key_grabs  = kgrab ;
	win_info->grabs     |= KeyGrabbed ;
	XmuXdebug( debug_resources , "Add key grab %d for window 0x%lx\n" ,
		   key , grab_window ) ;
    }
    else
	XmuXErrorF( "XmuXSetWindowKeyGrab: window 0x%lx not found!\n" , 
		    grab_window ) ;
}

void
XmuXRemoveWindowKeyGrab( dpy , grab_window , key , modifiers )

Display      *dpy;
Window        grab_window;
int           key;
unsigned int  modifiers;

{   register MUXWindowInfoPtr win_info ;

    if( ( win_info = GetWindowInfo( dpy , grab_window ) ) != 
        NullWindowInfoPtr ) 
    {   register GrabKeyParams *pred , *curr ;
	
	pred = curr = win_info->key_grabs ;
	if( curr == NULL )
	{
	    XmuXErrorF( "XmuXRemoveWindowKeyGrab: list 0x%lx empty!\n" ,
		        grab_window ) ;
	    return ;
	}
	/* -- remove the head ? -- */
	if( curr->key == key && curr->modifiers == modifiers )
	{
	    win_info->key_grabs = win_info->key_grabs->next ;
	    if( win_info->key_grabs == NULL ) 
		/* -- no more button grabs -- */
		win_info->grabs &= ~KeyGrabbed ;
	    Xfree( ( char * ) curr ) ;
	    return ;
	}
	/* -- search through the list -- */
	for( curr = curr->next ; curr != NULL ;
	     pred = curr , curr = curr->next )
	    if( curr->key == key && curr->modifiers == modifiers ) 
	    {
		pred->next = curr->next ;
		Xfree( ( char * ) curr ) ;
		return ;
	    }
	XmuXErrorF( "XmuXRemoveWindowKeyGrab: list 0x%lx entry not found!\n" ,
                        grab_window ) ;
    }
    else
	XmuXErrorF( "XmuXRemoveWindowKeyGrab: window 0x%lx not found!\n" ,
		    grab_window ) ;
}

/*
 * -- our four "gc routines"
 * -- one additional routine to update the flags 
 */

void
XmuXInsertGCInfo( dpy , gc , drawable )

Display *dpy ;
GC       gc ;
XID      drawable ;

{   MUXResourceInfoPtr new_entry ;
    int                screen , depth ;

    /* -- don't check for errors here , it's done by AllocAndInitResource -- */
    new_entry             = AllocAndInitResource( RT_GC , gc->gid ) ;

    new_entry->u.gc_info->gc       = gc ;
    new_entry->u.gc_info->drawable = drawable ;

    if( ( screen = XmuXIsRootWindow( dpy , drawable ) ) != -1 )
	new_entry->u.gc_info->depth   = DefaultDepth( dpy , screen ) ;
    else
	if( GetDepth( dpy , drawable , &depth ) )
	    new_entry->u.gc_info->depth   = depth ;
	else
	    XmuXFatalError( 
		"XmuXInsertGCInfo: Can't find drawable's 0x%lx info!\n" ,
		drawable ) ;

    /* -- insert it in client's list -- */
    InsertClientResource( dpy , new_entry ) ;
    XmuXdebug( debug_resources , 
	       "new resource 0x%lx info (type RT_GC) inserted\n" ,
	       gc->gid ) ;
    PrintGCInfo( new_entry->u.gc_info ) ;
}

MUXGCInfoPtr 
GetGCInfo( dpy , gid )

Display *dpy ;
XID      gid ;

{   MUXResourceInfoPtr resource_info ;

    resource_info = GetClientResource( dpy , gid , RT_GC ) ;

    return( ( resource_info != NullResourceInfoPtr )
	    ? resource_info->u.gc_info
	    : NullGCInfoPtr ) ;
}

void
XmuXUpdateGCFlags( dpy , gid , flags )

Display *dpy ;
XID      gid ;
long     flags ;

{   MUXGCInfoPtr gc_info ;

    if( ( gc_info = GetGCInfo( dpy , gid ) ) != NullGCInfoPtr )
    {
	gc_info->flags |= ( flags & XMUXGCFLAGS ) ;
	XmuXdebug( debug_resources , "GC 0x%lx updated\n" , gid ) ;
    }
}
   
/*
 * -- This is the only remove routine that returns a result !!
 * -- this result is needed in XFreeGC (to find out if we can free the
 * -- GC struct there)!!! 
 */
int
XmuXRemoveGCInfo( dpy , gid )

Display *dpy ;
XID      gid ;

{   MUXResourceInfoPtr resource_info ;

    resource_info = GetClientResource( dpy , gid , RT_GC ) ;

    if( resource_info != NullResourceInfoPtr )
    {
	MUXClientResources[ ConnectionNumber( dpy ) ].update = True ;
	resource_info->used = False ;
	return( 1 ) ;
    }
    else
	return( 0 ) ;
}

/* 
 * -- local routine to print current GC values
 */

static
void
PrintGCInfo( gc_info )

MUXGCInfoPtr gc_info ;

{
    XmuXdebug( debug_resources , "resource 0x%lx type : RT_GC values :\n" , 
	   gc_info->gid ) ;
    XmuXdebug( debug_resources , "drawable = 0x%lx\n" , gc_info->drawable ) ;
    XmuXdebug( debug_resources , "GC function   = %d\n" , 
	   gc_info->gc->values.function ) ;
    XmuXdebug( debug_resources , "GC foreground = %x\n" , 
	   gc_info->gc->values.foreground ) ;
    XmuXdebug( debug_resources , "GC background = %x\n" ,
	   gc_info->gc->values.background ) ;
    /* ... */
}

/*
 * -- the four "pixmap routines"
 */

void
XmuXInsertPixmapInfo( dpy , pixmap , drawable , depth )

Display *dpy ;
XID      pixmap ,
         drawable ;
int      depth ;

{   MUXResourceInfoPtr new_entry ;
    int                screen , junk_depth ;

    /* -- don't check for errors here , it's done by AllocAndInitResource -- */
    new_entry             = AllocAndInitResource( RT_PIXMAP , pixmap ) ;
    /* -- space has been allocated by AllocAndInitResource -- */
    new_entry->u.pmap_info->drawable   = drawable ;
    new_entry->u.pmap_info->depth      = depth ;
    
    /* -- Insert it in client's list -- */
    InsertClientResource( dpy , new_entry ) ;
    XmuXdebug( debug_resources ,
	   "new resource 0x%lx info (type RT_PIXMAP) inserted\n" , 
	   pixmap ) ;
}

MUXPixmapInfoPtr
GetPixmapInfo( dpy , pixmap )

Display *dpy ;
XID      pixmap ;

{   MUXResourceInfoPtr resource_info ;

    resource_info = GetClientResource( dpy , pixmap , RT_PIXMAP ) ;
    
    return( ( resource_info != NullResourceInfoPtr )
	    ? resource_info->u.pmap_info 
	    : NullPixmapInfoPtr ) ;
}

XID
XmuXGetPixmapDrawable( dpy , pixmap )

Display *dpy ;
XID      pixmap ;

{   MUXResourceInfoPtr resource_info ;

    resource_info = GetClientResource( dpy , pixmap , RT_PIXMAP ) ;

    return( ( resource_info != NullResourceInfoPtr )
            ? resource_info->u.pmap_info->drawable 
	    : None ) ;
}

void
XmuXRemovePixmapInfo( dpy , pixmap )

Display *dpy ;
XID      pixmap ;

{   MUXResourceInfoPtr resource_info ;
    MUXPixmapInfoPtr pmap_info ;

    resource_info = GetClientResource( dpy , pixmap , RT_PIXMAP ) ;
    
    if( resource_info != NullResourceInfoPtr )
    {
	MUXClientResources[ ConnectionNumber( dpy ) ].update = True ;
	resource_info->used = False ;
	RemoveDrawableReference( dpy , pixmap ) ;
    }
    else
	XmuXErrorF( debug_resources , "pixmap info 0x%lx not found!\n" , 
		    pixmap ) ;

}

/*
 * -- local routine to print parts of pixmap values 
 */

static
void
PrintPixmapInfo( dpy , pmap_info )

Display          *dpy ;
MUXPixmapInfoPtr  pmap_info ;

{

    XmuXdebug( debug_resources , "resource 0x%lx type = RT_PIXMAP values :\n" ,
	       pmap_info->pixmap ) ;
    XmuXdebug( debug_resources , "drawable: 0x%lx\n" , pmap_info->drawable ) ;

}

/*
 * -- the five(!) "cursor routines"
 * -- the two different cursor types are handled in two different routines
 * -- one additional routine to handle XRecolorCursor
 */

void
XmuXInsertGlyphCursorInfo( dpy , cursor , fg_color , bg_color ,
	                   src_font , mask_font , src_char , mask_char )

Display      *dpy ;
XID           cursor ;
XColor       *fg_color ,
             *bg_color ;
XID           src_font ,
              mask_font ;
unsigned int  src_char ,
              mask_char ;

{   MUXResourceInfoPtr new_entry ;

    /* -- don't check for errors here , it's done by AllocAndInitResource -- */
    new_entry             = AllocAndInitResource( RT_CURSOR , cursor ) ;

    /* -- space has been allocated by AllocAndInitResource -- */
    new_entry->u.curs_info->cursor_type  = GLYPH_CURSOR ;

    new_entry->u.curs_info->fg.red     = fg_color->red ;
    new_entry->u.curs_info->fg.green   = fg_color->green ;
    new_entry->u.curs_info->fg.blue    = fg_color->blue ;

    new_entry->u.curs_info->bg.red     = bg_color->red ;
    new_entry->u.curs_info->bg.green   = bg_color->green ;
    new_entry->u.curs_info->bg.blue    = bg_color->blue ;

    new_entry->u.curs_info->u.glyph_cursor.source_font = src_font ;
    new_entry->u.curs_info->u.glyph_cursor.mask_font   = mask_font ;
    new_entry->u.curs_info->u.glyph_cursor.source_char = src_char ;
    new_entry->u.curs_info->u.glyph_cursor.mask_char   = mask_char ;

    /* -- insert it in client's list -- */
    InsertClientResource( dpy , new_entry ) ;
    XmuXdebug( debug_resources ,
	   "new resource 0x%lx info (type RT_CURSOR) inserted\n" ,
	    cursor ) ;
    PrintCursorInfo( new_entry->u.curs_info ) ;
}

void
XmuXInsertPixmapCursorInfo( dpy , cursor , fg_color , bg_color ,
			    src_pmap , mask_pmap , hot_x , hot_y ) 

Display *dpy ;
XID      cursor ;
XColor  *fg_color ,
        *bg_color ;
XID      src_pmap ,
         mask_pmap ;
int      hot_x ,
         hot_y ;

{   MUXResourceInfoPtr new_entry ;

    /* -- don't check for errors here , it's done by AllocAndInitResource -- */
    new_entry             = AllocAndInitResource( RT_CURSOR , cursor ) ;

    /* -- space has been allocated by AllocAndInitResource -- */
    new_entry->u.curs_info->cursor_type  = PIXMAP_CURSOR ;

    new_entry->u.curs_info->fg.red     = fg_color->red ;
    new_entry->u.curs_info->fg.green   = fg_color->green ;
    new_entry->u.curs_info->fg.blue    = fg_color->blue ;

    new_entry->u.curs_info->bg.red     = bg_color->red ;
    new_entry->u.curs_info->bg.green   = bg_color->green ;
    new_entry->u.curs_info->bg.blue    = bg_color->blue ;

    new_entry->u.curs_info->u.pixmap_cursor.source_pmap = src_pmap ;
    new_entry->u.curs_info->u.pixmap_cursor.mask_pmap   = mask_pmap ;
    new_entry->u.curs_info->u.pixmap_cursor.hot_x       = hot_x ;
    new_entry->u.curs_info->u.pixmap_cursor.hot_y       = hot_y ;

    /* -- insert it in client's list -- */
    InsertClientResource( dpy , new_entry ) ;
    XmuXdebug( debug_resources ,
	   "new resource 0x%lx info (type RT_CURSOR) inserted\n" ,
	   cursor ) ;
    PrintCursorInfo( new_entry->u.curs_info ) ;
}

MUXCursorInfoPtr
GetCursorInfo( dpy , cursor )

Display *dpy ;
XID      cursor ;

{   MUXResourceInfoPtr resource_info ;

    resource_info = GetClientResource( dpy , cursor , RT_CURSOR ) ;
    
    return( ( resource_info != NullResourceInfoPtr )
	    ? resource_info->u.curs_info 
	    : NullCursorInfoPtr ) ;
}

void
XmuXChangeCursorColors( dpy , cursor , fg_color , bg_color )

Display   *dpy ;
XID        cursor ;
XColor    *fg_color ,
          *bg_color ;

{    MUXCursorInfoPtr curs_info ;

     if( ( curs_info = GetCursorInfo( dpy , cursor ) ) ==
	 NullCursorInfoPtr )
     {
	 XmuXErrorF( "Can't update cursor colors (cursor 0x%lx not found)!\n" ,
		 cursor ) ;
	 return ;
     }
     curs_info->fg.red   = fg_color->red ;
     curs_info->fg.green = fg_color->green ;
     curs_info->fg.blue  = fg_color->blue ;

     curs_info->bg.red   = bg_color->red ;
     curs_info->bg.green = bg_color->green ;
     curs_info->bg.blue  = bg_color->blue ;
     XmuXdebug( debug_resources , "cursor 0x%lx colors changed\n" , cursor ) ;
}

void
XmuXRemoveCursorInfo( dpy , cursor )

Display *dpy ;
XID      cursor ;

{   MUXResourceInfoPtr resource_info ;
    MUXCursorInfoPtr curs_info ;

    resource_info = GetClientResource( dpy , cursor , RT_CURSOR ) ;
    
    if ( resource_info != NullResourceInfoPtr )
    {
	MUXClientResources[ ConnectionNumber( dpy ) ].update = True ;
	resource_info->used = False ;
    }
    else
	XmuXErrorF( debug_resources , "cursor info 0x%lx not found!\n" , 
		    cursor ) ;

}

/*
 * -- local routine to print current cursor info 
 */

static 
void
PrintCursorInfo( curs_info )

MUXCursorInfoPtr curs_info ;

{

    XmuXdebug( debug_resources , "resource 0x%lx type = RT_CURSOR " ,
	   curs_info->cursor ) ;
    if( curs_info->cursor_type == PIXMAP_CURSOR )
    {
	XmuXdebug( debug_resources , "(type PIXMAP_CURSOR) values:\n" ) ;
	XmuXdebug( debug_resources , "foreground color (rgb) = %u %u %u\n" ,
	       curs_info->fg.red , curs_info->fg.green , curs_info->fg.blue ) ;
	XmuXdebug( debug_resources , "background color (rgb) = %u %u %u\n" ,
	       curs_info->bg.red , curs_info->bg.green , curs_info->bg.blue ) ;
	XmuXdebug( debug_resources , "pixmaps : src = 0x%lx mask = 0x%lx\n" ,
	       curs_info->u.pixmap_cursor.source_pmap ,
	       curs_info->u.pixmap_cursor.mask_pmap ) ;
	XmuXdebug( debug_resources , "hot spot : x = %d y = %d\n" ,
	       curs_info->u.pixmap_cursor.hot_x ,
	       curs_info->u.pixmap_cursor.hot_y ) ;
    }
    else
    {
	XmuXdebug( debug_resources , "(type = GLYPH_CURSOR) values :\n" ) ;
	XmuXdebug( debug_resources , "foreground color (rgb) = %u %u %u\n" ,
	       curs_info->fg.red , curs_info->fg.green , curs_info->fg.blue ) ;
	XmuXdebug( debug_resources , "background color (rgb) = %u %u %u\n" ,
	       curs_info->bg.red , curs_info->bg.green , curs_info->bg.blue ) ;
	XmuXdebug( debug_resources , "fonts : src = 0x%lx mask = 0x%lx\n" ,
	       curs_info->u.glyph_cursor.source_font ,
	       curs_info->u.glyph_cursor.mask_font ) ;
	XmuXdebug( debug_resources , "glyphs : src = %u mask = %u\n" ,
	       curs_info->u.glyph_cursor.source_char ,
	       curs_info->u.glyph_cursor.mask_char ) ;
    }
}

/*
 * -- the three "font routines"
 */

void
XmuXInsertFontInfo( dpy , font , name ) 

Display   *dpy ;
XID        font ;
char      *name ;

{   MUXResourceInfoPtr new_entry ;
    char *font_name ;
    int str_length ;

    /* -- don't check for errors here , it's done by AllocAndInitResource -- */
    new_entry             = AllocAndInitResource( RT_FONT , font ) ;

    /* -- space has been allocated by AllocAndInitResource... -- */
    /* -- exept for this -- */
    str_length = strlen( name ) ;
    if( ( font_name = ( char * ) Xmalloc( str_length + 1 ) ) == NULL )
	XmuXFatalError( "Out of memory (can't store font name)!\n" ) ;
    strcpy( font_name , name ) ;
    font_name[ str_length ] = '\0' ;
    new_entry->u.font_info->name  = font_name ;

    /* -- insert it in client's list -- */
    InsertClientResource( dpy , new_entry ) ;
    XmuXdebug( debug_resources ,
	   "new resource 0x%lx info (type RT_FONT) inserted\n" , font ) ;
    PrintFontInfo( new_entry->u.font_info ) ;
}

MUXFontInfoPtr
GetFontInfo( dpy , font )

Display *dpy ;
XID      font ;

{   MUXResourceInfoPtr resource_info ;

    resource_info = GetClientResource( dpy , font , RT_FONT ) ;
    
    return( ( resource_info != NullResourceInfoPtr )
	    ? resource_info->u.font_info 
	    : NullFontInfoPtr ) ;
}

void
XmuXRemoveFontInfo( dpy , font )

Display *dpy ;
XID      font ;

{   MUXResourceInfoPtr resource_info ;


    resource_info = GetClientResource( dpy , font , RT_FONT ) ;

    if( resource_info != NullResourceInfoPtr )
    {
	MUXClientResources[ ConnectionNumber( dpy ) ].update = True ;
	resource_info->used = False ;
    }
    else
	XmuXErrorF( debug_resources , "font info 0x%lx not found!\n" , font ) ;

}

/* 
 * --- local routine to print font info
 */

static
void
PrintFontInfo( font_info ) 

MUXFontInfoPtr font_info ;

{

    XmuXdebug( debug_resources , "resource 0x%lx type = RT_FONT values : \n" ,
	   font_info->font ) ;
    XmuXdebug( debug_resources , "name = %s\n" , font_info->name ) ;
}

/*
 * -- the six "colormap routines"
 * -- One additional routine to handle XCopyColormapAndFree
 * -- One additional routine to update the colormap info 
 * -- One additional routine to handle XFreeColors
 */

void
XmuXCreateColormapInfo( dpy , colormap , visual , window , private , alloc )

Display *dpy ;
XID      colormap ;
Visual  *visual ;
Window   window ;
int      private ,   /* is this a private colormap */
         alloc ;     /* did the client pass AllocAll to XCreateColormap */

{   register unsigned long     *map ;
    register int                size ;
    register MUXResourceInfoPtr new_entry ;
    
#ifdef DEBUG
    CheckDisplay( dpy , "XmuXInsertColormapInfo" ) ;
#endif

    /* -- don't check for errors here , it's done by AllocAndInitResource -- */
    new_entry             = AllocAndInitResource( RT_COLORMAP , colormap ) ;

    /* -- space has been allocated by AllocAndInitResource -- */
    new_entry->u.cmap_info->visualid    = visual->visualid ;
    new_entry->u.cmap_info->window      = window ;

    size = ALLOC_AT_ONCE ;
    new_entry->u.cmap_info->sh_length    = size ;
    map = ( unsigned long * ) Xmalloc( size * sizeof( unsigned long ) ) ;
    if( map == ( unsigned long * ) NULL )
	XmuXFatalError( "XmuXCreateColormapInfo: Out of memory (conn %d )!\n",
		        ConnectionNumber( dpy ) ) ;
    new_entry->u.cmap_info->sh_cells      = map ;
    new_entry->u.cmap_info->sh_allocated  = 0 ;

    /* -- insert it in client's list -- */
    InsertClientResource( dpy , new_entry ) ;
    if( private )
    {
	MUXClientResources[ ConnectionNumber( dpy ) ].privcmaps++ ;
	new_entry->u.cmap_info->is_private = True ;
    }
    else
	new_entry->u.cmap_info->is_private = False ;

    if( alloc == AllocAll )
    {   Visual             *vis ; 
	XID                 vid ;
	MUXColormapInfoPtr  cmap_info = new_entry->u.cmap_info ;

	/* 
	 * -- client has passed AllocAll to XCreateColormap 
	 * -- I.E. :
	 * -- Client doesn't need to call XAllocColorCells to allocate 
	 * -- cells in this new colormap and we won't get informed about
	 * -- thos allocation of private cells if we don't register it here !
	 */
	if( visual == NULL )
	    /*
	     * -- we need the visual structure to determine the size 
	     * -- of the map
	     */
	    if( !GetVisualID( dpy , window , &vid ) )
		XmuXFatalError( 
		    "XmuXCreateCmap: Can't find window's 0x%lx visual!" , 
		    window ) ;
	    else
		vis = _XVIDtoVisual( dpy , vid ) ;
	else
	    vis = visual ;
	
	if( ( cmap_info->pr_cells = ( MUXPrivateColorCells * )
	      Xmalloc( sizeof( MUXPrivateColorCells ) ) ) == NULL )
	    XmuXFatalError( "XmuXCreateCmap: Out of mem (pr_cells)!\n" ) ;
	if( visual->class == PseudoColor )
	{
	    if( ( cmap_info->pr_cells->pixels = ( unsigned long * ) 
		 Xmalloc( visual->map_entries * sizeof( long ) ) ) == NULL )
		XmuXFatalError( 
			 "XmuXCreateCmap: Out of mem (priv pixels)!\n" );
	    for( size = 0 ; size < visual->map_entries ; size++ )
		cmap_info->pr_cells->pixels[ size ] = size ;
	    cmap_info->pr_cells->n_pixels = visual->map_entries ;
	    cmap_info->pr_cells->n_planes = 0 ;
	    cmap_info->pr_cells->planes   = NULL ;
	    cmap_info->pr_cells->alloc_cells = True ;
	}
	else 
	{   /* -- DirectColor -- */
	    if( ( cmap_info->pr_cells->pixels = ( unsigned long * )
                  Xmalloc( sizeof( long ) ) ) == NULL )
		XmuXFatalError(
			  "XmuXCreateCmap: Out of mem (priv pixels)!\n" );
	    cmap_info->pr_cells->pixels[ 0 ] = 0 ;
	    cmap_info->pr_cells->n_pixels    = 1 ;
	    if( ( cmap_info->pr_cells->planes = ( unsigned long * )
		  Xmalloc( 3 *  sizeof( long ) ) ) == NULL )
		XmuXFatalError(
			  "XmuXCreateCmap: Out of mem (priv planes)!\n" );
	    cmap_info->pr_cells->n_planes = 3 ;
	    cmap_info->pr_cells->planes[ 0 ] = visual->red_mask ;
	    cmap_info->pr_cells->planes[ 1 ] = visual->green_mask ;
	    cmap_info->pr_cells->planes[ 2 ] = visual->blue_mask ;
	    cmap_info->pr_cells->alloc_cells = False ;
	}
    }
    XmuXdebug( debug_resources , 
       "new resource 0x%lx info (type RT_COLORMAP) inserted\n" ,
	colormap ) ;
}

MUXColormapInfoPtr
XmuXGetColormapInfo( dpy , colormap )

Display *dpy ;
XID      colormap ;

{   MUXResourceInfoPtr resource_info ;

#ifdef DEBUG
    CheckDisplay( dpy , "XmuXUpdateColormapInfo" ) ;
#endif

    resource_info = GetClientResource( dpy , colormap , RT_COLORMAP ) ;
    
    return( ( resource_info != NullResourceInfoPtr )
	    ? resource_info->u.cmap_info 
	    : NullColormapInfoPtr ) ;
}

void
XmuXCopyColormap( dpy , src_cmap , dst_cmap )

Display  *dpy ;
Colormap  src_cmap ,
          dst_cmap ;

{   MUXResourceInfoPtr resource_info ;

#ifdef DEBUG
    CheckDisplay( dpy , "XmuXCopyColormap" ) ;
#endif

    if( ( resource_info = GetClientResource( dpy , src_cmap , RT_COLORMAP ) ) 
        != NullResourceInfoPtr )
	/*
	 * -- just change the resource ID's
	 */
	resource_info->id                    =
	resource_info->u.cmap_info->colormap = dst_cmap ;
}

void
XmuXUpdateColormapInfo( dpy , colormap , pixels , n_pixels , planes , 
		        n_planes , shared , AllocCells ) 

Display       *dpy ;
XID            colormap ;
unsigned long *pixels ,
              *planes ;
int             n_pixels ,
                n_planes ,
                shared ,
                AllocCells ;

{   MUXResourceInfoPtr entry ; 
    MUXColormapInfoPtr cmap_info ;
    int                allocate ;

#ifdef DEBUG
    CheckDisplay( dpy , "XmuXUpdateColormapInfo" ) ;
#endif

    if( ( entry  = GetClientResource( dpy , colormap , RT_COLORMAP ) ) !=
        NullResourceInfoPtr )
    {   
	cmap_info = entry->u.cmap_info ;
	if( shared )
	{   register int i ;

	    /* -- client allocated shared color cells -- */
	    /* 
	     * -- see if this pixel has been allocated before
	     */
	    for( i = 0 ; i < cmap_info->sh_allocated ; i++ )
		if( pixels[ 0 ] == cmap_info->sh_cells[ i ] )
		    return ;

	    if( cmap_info->sh_allocated == cmap_info->sh_length )
	    {
		/* -- must realloc array -- */
		allocate = 
		    ( ( cmap_info->sh_allocated + 1 ) / ALLOC_AT_ONCE + 1 ) * 
			ALLOC_AT_ONCE ;
		cmap_info->sh_length = allocate ;
		cmap_info->sh_cells  = ( unsigned long * ) 
		    Xrealloc( ( char * ) cmap_info->sh_cells , 
			      allocate * sizeof( unsigned long ) ) ;
		if( cmap_info->sh_cells == NULL )
		    XmuXFatalError( "XmuXUpdateColormapInfo: Realloc failed \
                                    (conn %d)!\n" , ConnectionNumber( dpy ) ) ;
	    }
	    cmap_info->sh_cells[ cmap_info->sh_allocated ] = pixels[ 0 ] ;
	    cmap_info->sh_allocated++ ;
	    XmuXdebug( debug_resources , 
		      "Colormap 0x%lx  pixel %u inserted\n" ,
		      colormap , 
		      entry->u.cmap_info->sh_cells[ entry->u.cmap_info->sh_allocated - 1 ] ) ;
	}
	else
	{   MUXPrivateColorCells *pr_cells ;

	    if ( ( pr_cells = ( MUXPrivateColorCells * )
		    Xmalloc( sizeof( MUXPrivateColorCells ) ) ) == NULL )
		XmuXFatalError( "XmuXUpdCmap: Out of mem (private info)!\n" );
	    if( n_pixels )
	    {
		if( ( pr_cells->pixels = ( unsigned long * ) 
		      Xmalloc( n_pixels * sizeof( unsigned long ) ) ) == NULL )
		    XmuXFatalError( "XmuXUpdCmap: Out of mem (private cells)!\n" );
		bcopy( ( char * ) pixels , ( char * ) pr_cells->pixels , 
		       n_pixels * sizeof( unsigned long ) ) ;
	    }
	    else
		pr_cells->pixels = NULL ;

	    if( n_planes )
	    {
		if( ( pr_cells->planes = ( unsigned long * ) 
		      Xmalloc( n_planes * sizeof( unsigned long ) ) ) == NULL )
		    XmuXFatalError( "XmuXUpdCmap: Out of mem (private cells)!\n" );
		bcopy( ( char * ) planes , ( char * ) pr_cells->planes , 
		       n_planes * sizeof( unsigned long ) ) ;
	    }
	    else
		pr_cells->planes = NULL ;
		
	    pr_cells->n_pixels    = n_pixels ;
	    pr_cells->n_planes    = n_planes ;
	    pr_cells->alloc_cells = AllocCells ;
	    pr_cells->next      = cmap_info->pr_cells ;
	    cmap_info->pr_cells = pr_cells ;
	    XmuXdebug( debug_resources , 
		      "cmap 0x%lx  %d private pixels (%d planes)inserted\n" ,
		      colormap , n_pixels , n_planes ) ;
	}
    }
}

void
XmuXRemoveColormapInfo( dpy , colormap )

Display *dpy ;
XID      colormap ;

{   MUXResourceInfoPtr resource_info ;

#ifdef DEBUG
    CheckDisplay( dpy , "XmuXRemoveColormapInfo" ) ;
#endif

    resource_info = GetClientResource( dpy , colormap , 
					  RT_COLORMAP ) ;
    
    if( resource_info != NullResourceInfoPtr )
    {
	MUXClientResources[ ConnectionNumber( dpy ) ].update = True ;
    	resource_info->used = False ;
    }
    else
	XmuXErrorF( debug_resources , "colormap 0x%lx not found!\n" , 
		    colormap ) ;
}

#define FREEANDADVANCE( ptr )  \
            {   register MUXPrivateColorCells *tmp = ptr ;\
		ptr = ptr->next ;\
		tmp->next = NULL ;\
		Xfree( ( char * ) tmp->pixels ) ;\
		if( tmp->planes ) Xfree( ( char * ) tmp->planes ) ;\
		Xfree( ( char * ) tmp ) ;\
	    }

void
XmuXFreeColors( dpy , cmap , pixels , npixels , planes )

Display       *dpy ;
Colormap       cmap ;
unsigned long *pixels ;
int            npixels ;
unsigned long  planes ;

{   MUXColormapInfoPtr cmap_info ;

    if( ( cmap_info = XmuXGetColormapInfo( dpy , cmap ) ) != NULL )
    {   register int                   i , j , zapped , matched ;
	register MUXPrivateColorCells *curr , *prev ;

	if( planes == 0L )
	{
	    /* -- must check shared color cells -- */
	    zapped = 0 ;
	    for( i = 0 ; i < npixels ; i++ )
		for( j = cmap_info->sh_allocated - 1 ; j >= 0 ; j-- )
		    if( cmap_info->sh_cells[ j ] == pixels[ i ] )
		    {
			cmap_info->sh_cells[ j ] = ~(0L) ;
			zapped++ ;
			break ;
		    }
	    if( zapped )
	    {
		cmap_info->sh_allocated -= zapped ;
		if( cmap_info->sh_allocated )
		{
		    /*
		     * -- array will shrink --> copy in place 
		     * -- and realloc array 
		     */
		    for( j = 0 , i = 0 ;
			 i < cmap_info->sh_allocated + zapped ; i++ )
			if( cmap_info->sh_cells[ i ] != ~(0L) )
			    cmap_info->sh_cells[ j++ ] = 
				cmap_info->sh_cells[ i ] ;
		    cmap_info->sh_length = 
			( cmap_info->sh_allocated / ALLOC_AT_ONCE + 1 ) *
			ALLOC_AT_ONCE ;
		    cmap_info->sh_cells = ( unsigned long * ) 
			Xrealloc( ( char * ) cmap_info->sh_cells , 
				  cmap_info->sh_length * sizeof( long ) ) ;
		}
		else
		{
		    Xfree( ( char * ) cmap_info->sh_cells ) ;
		    cmap_info->sh_cells = NULL ;
		}
		if( zapped == npixels )
		    return ;
	    }
	}
	/*
	 * -- private cells will only be freed if we find an exact match !
	 */
	for( curr = cmap_info->pr_cells ; curr != NULL ; curr = curr->next )
	{
	    matched = 0 ;
	    for( i = 0 ; i < npixels ; i++ )
		for( j = curr->n_pixels - 1 ; j >= 0 ; j-- )
		    if( pixels[ i ] == curr->pixels[ j ] )
			matched++ ;
	    if( matched == curr->n_pixels )
	    {
		matched = 0 ;
		for( j = curr->n_planes - 1 ; j >= 0 ; j-- )
		    if( planes & curr->planes[ j ] )
			matched++ ;
		if( matched == curr->n_planes )
		    curr->n_pixels = -1 ;
	    }
	}
	curr = cmap_info->pr_cells ;
	prev = NULL ;

	while( curr != NULL )
	{
	    /* -- a new candidate ? -- */
	    if( curr->n_pixels == -1 )
	    {
		/* -- head of list ? -- */
		if( prev == NULL )
		{
		    /* -- only one list element ? -- */
		    if( curr->next == NULL )
			  cmap_info->pr_cells = NULL ;
		    else
			cmap_info->pr_cells = curr->next ;
		    
		    /* -- free the entry -- */
		    FREEANDADVANCE( curr ) ;
		}
		else
		{
		    prev->next = curr->next ;
		    FREEANDADVANCE( curr ) ;
		}
	    }
	    else
	    {
		prev = curr ;
		curr = curr->next ;
	    }
	}
    }
}

#undef FREEANDADVANCE

/* 
 * -- local routine to print colormap info
 */
void
PrintColormapInfo( cmap_info )

MUXColormapInfoPtr cmap_info ;

{   register int i ;

    XmuXdebug( debug_resources , "resource 0x%lx type = RT_COLORMAP values :\n" ,
	   cmap_info->colormap ) ;
    for( i = 0 ; i < cmap_info->sh_allocated ; i++ )
    {
	XmuXdebug( debug_resources , "%dth allocated pixel : %lx\n" ,
	          i , cmap_info->sh_cells[ i ] ) ;
    }
}

/* -- GCPixelInfo routines -- */

void
XmuXUpdateGCPixels( dpy , gid , flags , values )

Display       *dpy ;
XID            gid ;
unsigned long  flags ;
XGCValues     *values ;

{   register MUXResourceInfoPtr res_info  ;

    res_info = GetClientResource( dpy , gid , RT_GCPIXELS ) ;
    
    XmuXdebug( debug_resources , "Update GC 0x%lx pixels" , gid ) ;
    if( res_info == NullResourceInfoPtr )
    {
	/* -- it's not an error here, must create a new entry -- */
	res_info             = AllocAndInitResource( RT_GCPIXELS , gid ) ;
	res_info->used       = True ;
	res_info->id         = gid ;
	res_info->type       = RT_GCPIXELS ;

	res_info->u.gcpix_info->gid    = gid ;
	res_info->u.gcpix_info->flags  = flags ;
	if( flags & GCFunction )
	{
	    XmuXdebug( debug_resources , " function %u" , 
		       values->function ) ;
	    res_info->u.gcpix_info->function = values->function ;
	}
	if( flags & GCForeground )
	{
	    XmuXdebug( debug_resources , " fg %u" , values->foreground ) ;
	    res_info->u.gcpix_info->fg = values->foreground ;
	}
	if( flags & GCBackground )
	{
	    XmuXdebug( debug_resources , " bg %u" , values->foreground ) ;
	    res_info->u.gcpix_info->bg = values->background ;
	}
	if( flags & GCPlaneMask )
	{
	    XmuXdebug( debug_resources , " plane msk %u" , 
		       values->plane_mask )  ;
	    res_info->u.gcpix_info->plane_mask = values->plane_mask ;
	}
	/* -- insert it -- */
	InsertClientResource( dpy , res_info ) ;
    }
    else
    {
	res_info->u.gcpix_info->flags  = flags ;
	if( flags & GCFunction )
	{
	    XmuXdebug( debug_resources , " function %u" , 
		       values->function ) ;
	    res_info->u.gcpix_info->function = values->function ;
	}
	if( flags & GCForeground )
	{
	    XmuXdebug( debug_resources , " fg %u" , values->foreground ) ;
	    res_info->u.gcpix_info->fg = values->foreground ;
	}
	if( flags & GCBackground )
	{
	    XmuXdebug( debug_resources , " bg %u" , values->foreground ) ;
	    res_info->u.gcpix_info->bg = values->background ;
	}
	if( flags & GCPlaneMask )
	{
	    XmuXdebug( debug_resources , " plane msk %u" , 
		       values->plane_mask )  ;
	    res_info->u.gcpix_info->plane_mask = values->plane_mask ;
	}
    }
    XmuXdebug( debug_resources , " done\n" ) ;
}

void 
PrintGCPixelsInfo( dpy , gcpix_info )

Display            *dpy ;
MUXGCPixelsInfoPtr  gcpix_info ;

{ 
}

MUXGCPixelsInfoPtr
GetGCPixelsInfo( dpy , gid )

Display *dpy ;
XID      gid ;

{   register MUXResourceInfoPtr resource_info ;

    resource_info = GetClientResource( dpy , gid , RT_GCPIXELS ) ;
    
    return( ( resource_info != NullResourceInfoPtr )
	    ? resource_info->u.gcpix_info 
	    : NullGCPixelsInfoPtr ) ;
}

void
InitClientResources( )

{   register int i ;

    for( i = 0 ; i < MAXSOCKS ; i++ )
    {
	MUXClientResources[ i ].head       =
	MUXClientResources[ i ].tail       = NullResourceInfoPtr ;
	MUXClientResources[ i ].privcmaps     = 0 ;
	MUXClientResources[ i ].update     = False ;
    }
}

/*
 * -- That's what every "good" X application should do on normal termination :
 * -- free all allocated resources 
 */

void
XmuXFreeClientResources( dpy )

Display *dpy ;    /* index in the resource info table */

{    MUXResourceInfoPtr resource_info ;
     void               ListClientResources( ) ;

#ifdef DEBUG
    CheckDisplay( dpy , "XmuXFreeClientResources" ) ;
#endif

     if( debug_resources )
	 ListClientResources( dpy ) ;

     /* -- do FIRST OUT -- */
     while( MUXClientResources[ ConnectionNumber( dpy ) ].head != 
	    NullResourceInfoPtr )
     {
	 resource_info = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
	 MUXClientResources[ ConnectionNumber( dpy ) ].head = 
	     resource_info->next ;
	 resource_info->next = NullResourceInfoPtr ;
	 FreeResourceInfo( resource_info ) ;
     }

     /* -- the list is empty ! -- */
     MUXClientResources[ ConnectionNumber( dpy ) ].tail = NullResourceInfoPtr ;

}
/*
 * -- debugging and information routine
 */
void
ListClientResources( dpy ) 

Display *dpy ;

{    MUXResourceInfoPtr entry ;

#ifdef DEBUG
    CheckDisplay( dpy , "ListClientResources" ) ;
#endif

     XmuXdebug( debug_resources , "Client %d uses the following resources:\n" ,
	        ConnectionNumber( dpy ) ) ;

     for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
	  entry != NullResourceInfoPtr ;
	  entry = entry->next ) 
     {
	 switch( entry->type )
	 {

	 case RT_WINDOW :
	     PrintWindowInfo( dpy , entry->u.win_info ) ;
	     break ;

	 case RT_GC :
	     PrintGCInfo( entry->u.gc_info ) ;
	     break ;

	 case RT_PIXMAP :
	     PrintPixmapInfo( dpy , entry->u.pmap_info ) ;
	     break ;

	 case RT_CURSOR :
	     PrintCursorInfo( entry->u.curs_info ) ;
	     break ;

	 case RT_FONT :
	     PrintFontInfo( entry->u.font_info ) ;
	     break ;

	 case RT_COLORMAP :
	     PrintColormapInfo( entry->u.cmap_info ) ;
	     break ;
	 case RT_GCPIXELS :
	     PrintGCPixelsInfo( entry->u.gcpix_info ) ;
	     break ;
	 }
     }
}

Bool
XmuXStoreResources( dpy )

Display *dpy ;

{

#ifdef DEBUG
    CheckDisplay( dpy , "XmuXStoreResources" ) ;
#endif

    return( ConnectionTranslation[ ConnectionNumber( dpy ) ]->storeResources ) ;

}

XID
XmuXMatchDrawable( dpy , depth )

Display *dpy ;
int      depth ;

{   MUXResourceInfoPtr entry ;
    int                ret_screen , 
                       ret_depth ;

#ifdef DEBUG
    CheckDisplay( dpy , "XmuXMatchDrawable" ) ;
#endif

    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
	 entry != NullResourceInfoPtr ;
	 entry = entry->next ) 

	if( ( entry->used ) && RIGHTTYPE( entry ) ) 
	    if( CompareDepth( entry , depth ) )
		return( entry->id ) ;
    
    return( None ) ;
}

int
XmuXBmapStillReferenced( dpy , bitmap )

Display *dpy ;
Pixmap   bitmap ;

{   register MUXResourceInfoPtr entry ;

    /* -- is this bitmap (or pixmap) still referenced in another 
          resource info ? -- */
    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
	 entry != NullResourceInfoPtr ;
	entry = entry->next ) 

      switch( entry->type ) {
      
      case RT_CURSOR:
	if( ( entry->u.curs_info->cursor_type == PIXMAP_CURSOR ) &&
	    ( ( entry->u.curs_info->u.pixmap_cursor.source_pmap == bitmap ) ||
	      ( entry->u.curs_info->u.pixmap_cursor.mask_pmap == bitmap ) ) )
	    return( True ) ;
	break ;
      case RT_WINDOW:
	if( ( entry->u.win_info->bg_pmap == bitmap ) ||
	    ( entry->u.win_info->border_pmap == bitmap ) )
	  return( True ) ;
	break;
      case RT_GC:
	if( ( entry->u.gc_info->gc->values.tile == bitmap ) || 
	    ( entry->u.gc_info->gc->values.stipple == bitmap ) )
	  return( True ) ;
	break;
      default:
	break;
      }

    return( False ) ;
}

int
XmuXFontStillReferenced( dpy , font )

Display *dpy ;
Font     font ;

{   register MUXResourceInfoPtr entry ;

    /* -- is font still referenced in a glyph cursor info or gc info ? -- */
    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
         entry != NullResourceInfoPtr ;
        entry = entry->next )

      switch( entry->type ) {

      case RT_CURSOR:
        if( ( entry->u.curs_info->cursor_type == GLYPH_CURSOR ) &&
	    ( ( entry->u.curs_info->u.glyph_cursor.source_font == font ) ||
	      ( entry->u.curs_info->u.glyph_cursor.mask_font == font ) ) )
	    return( True ) ;
	break;
      case RT_GC:
	if( entry->u.gc_info->gc->values.font == font)
	  return( True ) ;
	break ;
      default:
	break;
      }
    return( False ) ;
}

int
XmuXCursorStillReferenced( dpy , cursor )

Display *dpy ;
Cursor   cursor ;

{   register MUXResourceInfoPtr entry ;

    /* -- is this cursor still referenced in a window info ? -- */
    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
         entry != NullResourceInfoPtr ;
        entry = entry->next )
      if( ( entry->type == RT_WINDOW ) &&
	  ( entry->u.win_info->cursor == cursor ) )
	return( True ) ;
    return( False ) ;
}
	
int
XmuXColormapStillReferenced( dpy , colormap )

Display *dpy ;
Colormap colormap ;

{   register MUXResourceInfoPtr entry ;

    /* -- is colormap still referenced in a window info ? -- */
    for( entry = MUXClientResources[ ConnectionNumber( dpy ) ].head ;
         entry != NullResourceInfoPtr ;
        entry = entry->next )
      if( ( entry->type == RT_WINDOW ) &&
	  ( entry->u.win_info->colormap == colormap ) )
	return( True ) ;
    return( False ) ;
}

int
XmuXUsesPrivateCmaps( dpy )

Display *dpy ;

{   register Display            *dflt_dpy ;

    dflt_dpy = XmuXPrimaryDisplayFromDisplay( dpy ) ;
    return( MUXClientResources[ ConnectionNumber( dflt_dpy ) ].privcmaps > 0 ) ;
}

Bool
XmuXIsPixmap( dpy , rID )

Display *dpy ;
XID      rID ;

{   
    if( !IsClientDisplay( dpy ) )
    {
	rID = XmuXMapID( dpy , rID , FromServer ) ;
	dpy = XmuXPrimaryDisplayFromDisplay( dpy ) ;
    }
    return( ResourceType( dpy , rID ) == RT_PIXMAP ) ;
}

int
XmuXDepthViaVisual( dpy , window , depth )

Display *dpy ;
Window   window ;
int     *depth ;

{   XID visualID ;
    Display *default_dpy ;

    /*
     * -- First of all, we need the default display pointer to 
     * -- retrieve the visual ID 
     */
    if( !IsClientDisplay( dpy ) )
    {
        window = XmuXMapID( dpy , window , FromServer ) ;
        default_dpy = XmuXPrimaryDisplayFromDisplay( dpy ) ;
    }
    else
	default_dpy = dpy ;

    if( !GetVisualID( default_dpy , window , &visualID ) )
	return( False ) ;
    else
    {   
	/* 
	 * -- NOTE : Visual ID mudt be mapped !!
	 */
	if( !XmuXDepthFromVisualID( dpy , 
				    XmuXMapID( dpy , 
					       visualID , FromClient ) ,
	                            depth ) )
	    return( False ) ;
	else
	    return( True ) ;
    }
}
