/* 
 * --$Header: /cec/src/nestor/servers/R3/shXlib/map.c,v 1.2 90/06/07 11:24:31 altenhof Exp $ 
 * -- $Log:	map.c,v $
 * Revision 1.2  90/06/07  11:24:31  altenhof
 * Changed code in GetServerMask
 * 
 * Revision 1.1.1.1  90/04/23  10:13:12  spanachi
 * First version of 'shared X' library (X11R3). 
 * 
 * Revision 1.1  90/04/23  10:13:07  spanachi
 * Initial revision
 * 
 * Revision 1.2  90/04/04  20:31:10  altenhof
 * FIXED bug : hashing on negative numbers
 * 
 * Revision 1.1  90/04/04  09:40:53  altenhof
 * Initial revision
 * 
 * Revision 1.1  90/03/21  15:24:34  altenhof
 * Initial revision
 * 
 * Revision 1.1  89/11/03  14:45:28  neideck
 * Original send to X consortium
 * 
 * Revision 2.3  89/09/27  19:25:42  michael
 * New routine added to handle FreeColors request ( map pixels and planes )
 * FIXED BUGS : InsertID was wrong (overwriting values of unused entries)
 *              RemoveID was wrong (return with an error instead of removing
 * 	        the alias)
 * Bugs were not detected until now, since ID removal has not been used !
 * 
 * Revision 2.2  89/09/07  19:06:42  michael
 * Code to manage private cells from XAllocColorPlanes added ( but not tested !)
 * FIXED BUGS : Pixel mapping for private cells was wrong ( too many planes !)
 *              XmuXMapPixelsAndPlane now has in and out parameters ( overriding
 * 	        was bad !)
 * 
 * Revision 2.1  89/09/05  17:23:35  michael
 * FIXED BUG : Plane generation was wrong .
 * 
 */

#include "XmuXlibint.h"
#include "macros.h"

#ifndef IsPixmap 
#define IsWindow  0
#define IsPixmap  1
#define DontKnow  2
#endif

/* -- local definitions for hashing -- */

#define ID_HASHSIZE 127  /* -- fits in one page -- */

/* -- the hash function : ( resource ID ) modulo ID_HASHSIZE 
 */
#define HashID( id )   ( int ) ( ( (id) >= 0 ) ? ( id ) % ID_HASHSIZE : \
				 ( -(id)) % ID_HASHSIZE )

#define NullTable    ( IDMapPtr * ) ( 0 )
#define NullIDMapPtr ( IDMapPtr ) ( 0 )

/*
 * -- typedef's and declarations for ID mapping 
 */
typedef struct _IDMapRec {      /* one entry in our ID map */
     int whose ;                /* where does this ID come from (FromServer or
				   FromClient) */
     Bool used ;                /* is this entry currently used */
     XID id ,                   /* the id ... */
         alias ;                /* ... and it's equivalence */
     struct _IDMapRec *next ;   /* we use hashing with collision resolution by 
				   linking */
} IDMapRec , *IDMapPtr ;

static IDMapPtr *MUXIDMaps[ MAXSOCKS ] ;   /* one hash table per 
						     connection */

static IDMapPtr *FreeMaps[ 10 ] ;             /* list of allocated but unused 
						 hash tables */
					         
static int free_index = -1 ;

static IDMapPtr FreeEntries = NullIDMapPtr ;  /* list of allocated but unused 
						 hash entries */
/*
 * -- typedef's and declarations for Colormap Hashing 
 */

#define W_HASHSIZE 7

#define HashW( w )   ( int ) ( ( (w) >= 0 ) ? ( w ) % W_HASHSIZE : \
			       ( -(w) ) %W_HASHSIZE ) 

#define NullWindowCmapTable  ( WindowCmapPtr * ) ( 0 )
#define NullWindowCmapPtr    ( WindowCmapPtr ) ( 0 )

typedef struct _WindowCmapEntry {

    XID                      window ,  /* the window ... */
                             cmap ;    /* ... and it's color map */
    struct _WindowCmapEntry *next ;    /* collision resolution */

} WindowCmapEntry , *WindowCmapPtr ;

static WindowCmapPtr *MUXWindowCmapTable[ MAXSOCKS ] ;


/* 
 * -- typedef's and declarations for PIXEL mapping 
 */

typedef struct _PixelMapValues { /* one entry in a pixel map array */
 
    unsigned long  client_value ,     /* the client's pixel/plane value */
                   server_value ;     /* the server's pixel/plane value */

} PixelMapValues ;

/*
 * -- Next decalrations need some explanations :
 * -- The most time-consuming job is pixel mapping, because
 * --    You have three different ways to allocate colors :
 * --      -> You may use read-only color cells 
 * --      -> You may allocate private color cells via XAllocColorCells
 * --      -> You may allocate private color cells via XAllocColorPlanes
 * 
 * -- Read-only cells are easy : 
 * --   They are uniquely determined by a pixel value.
 *
 * -- Private color cells from XAllocColorCells are hard :
 * --   They are uniquely determined by a so-called "base-pixel" value (one of
 * --   the pixel values XAllocColorCells returns to you) and an OR-ed 
 * --   combination of plane masks returned by XAllocColorCells. 
 * --   What you get from XAllocColorCells is an array of plane masks, where
 * --   every mask has exactly one bit set (if yu are using a PseudoColor
 * --   Visual) or exactly three bits set ( if you are using a DirectColor
 * --   Visual) and no mask value having any bit in common with any other.
 * --   To map such a private cell, you'll have to reconstruct the base-pixel
 * --   value by stripping off the plane masks, map this pixel and OR it with
 * --   the mapped plane masks.
 *
 * -- Private color cells from XAllocColorPlanes are even harder :
 * --   XAllocColorPlanes is intended to be used on DirectColor workstations
 * --   (although it works on PseudoColor workstations), since the three plane
 * --   sets returned can be used as primary subfields (red,green,blue)
 * --   in DirectColor colormaps. What XAllocColorCells returns as an array is
 * --   merged into single masks here; e.g. if you need 4 planes in the red
 * --   subfield, the "red_mask" will have 4 bits set.
 * --   To map such a private color cells, you'll have to use a different 
 * --   technique to generate and map the used plane masks.
 *
 * -- To deal with all three color cell types we use an array of five 
 * -- different lists (called maps) :
 * --  One storing the read-only cells (indexed by SharedPixels)
 * --  One storing the base-pixel values returned by XAllocColorCells
 * --  (indexed by PseudoPixels)
 * --  One storing the plane mask values returned by XAllocColorCells
 * --  (indexed by PseudoPlanes)
 * --  One storing the base-pixel values returned by XAllocColorPlanes
 * --  (indexed by DirectPixels)
 * --  One storing the plane mask values returned by XAllocColorPlanes
 * --  (indexed by DirectPlanes)
 * 
 * --  The index array is used to determine the base-pixels/ plane masks 
 * --  from one call to XAllocColorCells/Planes. You must use a "per-call"
 * --  mapping algorithm, since plane masks are only unique in one call !
 */

typedef struct _PixelMap { /* describes a pixel map for one connection */

    Colormap          cmap ;                  /* identifies this pixel map */
    Bool              sorted ;                /* can we use binary search ? */
    int               length[ 5 ] ,           /* length of the arrays */
                      allocated[ 5 ] ,        /* number of allocated values 
						 in the arrays */
                      pr_calls[ 2 ] ,         /* num of calls to 
						 XAllocColorCells/Planes */
                      *index[ 3 ] ;
    PixelMapValues    *maps[ 5 ] ;             /* the map arrays */

    struct _PixelMap *next ;                /* hook to the next map */
} PixelMap , *PixelMapPtr ;

static PixelMapPtr MUXPixelMaps[ MAXSOCKS ] ; /* one pixel map list per
						 connection */

/* -- local definitions for pixel mapping -- */

#define ALLOC_AT_ONCE 5
#define PLANES_RGB     3

#define NullPixelMapValues ( PixelMapValues * ) ( 0 )
#define NullPixelMapPtr ( PixelMapPtr ) ( 0 )

/* -- indices to maps -- */
#define SharedPixels 0
#define PseudoPixels 1
#define PseudoPlanes 2
#define DirectPixels 3
#define DirectPlanes 4

/* -- indices to index -- */
#define ACCPixels    0    /* ACC means (X)A_lloc_C_olor_C_ells */
#define ACCPlanes    1
#define ACPPixels    2    /* ACP means (X)A_lloc_C_olor_P_lanes */

/* -- indices to pr_calls -- */
#define ACCCalls     0
#define ACPCalls     1

#define INDEX( ptr , i , which ) ptr->index[ which ][ i ]

#define ALLOCATED( ptr , which ) ptr->allocated[ which ]

#define MUST_REALLOC( ptr , n , which ) \
           ( ( ptr->allocated[ which ] + n ) >= ptr->length[ which ] )

#define CLIENT_VALUE( ptr , i , which ) \
         ptr->maps[ which ][ i ].client_value

#define SERVER_VALUE( ptr , i , which ) \
         ptr->maps[ which ][ i ].server_value 

#define SERVER_RGBS( ptr , k ) \
         ( ( ptr->maps[ DirectPlanes ][ k * PLANES_RGB ].server_value ) |\
	   ( ptr->maps[ DirectPlanes ][ k * PLANES_RGB + 1 ].server_value ) |\
	   ( ptr->maps[ DirectPlanes ][ k * PLANES_RGB + 2 ].server_value ) )

#define CLIENT_RGBS( ptr , k ) \
         ( ( ptr->maps[ DirectPlanes ][ k * PLANES_RGB ].client_value ) |\
	   ( ptr->maps[ DirectPlanes ][ k * PLANES_RGB + 1 ].client_value ) |\
	   ( ptr->maps[ DirectPlanes ][ k * PLANES_RGB + 2 ].client_value ) )

#define SetPseudoPixelIndex( ptr , idx ) \
           SetIndex( ptr , idx , ACCPixels , ACCCalls )

#define SetDirectPixelIndex( ptr , idx ) \
           SetIndex( ptr , idx , ACPPixels , ACPCalls ) 

#define SetPseudoPlaneIndex( ptr , idx ) \
           SetIndex( ptr , idx , ACCPlanes , ACCCalls )

void
FreeIDMap( map )

IDMapPtr *map ;

{   IDMapPtr entry ;
    register int i ;

    if( map == NullTable )
	XmuXFatalError( "FreeIDMap: Try to free an empty map!\n" ) ;
    for( i = 0 ; i < ID_HASHSIZE ; i++ )
    {
	if( ( entry = map[ i ] ) != NullIDMapPtr )
	{
	    while( entry->next != NullIDMapPtr )
		entry = entry->next ;
	    entry->next = FreeEntries ;
	    FreeEntries = map[ i ] ;
	    map[ i ] = NullIDMapPtr ;
	}

    }
    if( ++free_index > 9 )
    {
	free_index = 9 ;
	Xfree( ( char * ) map ) ;
    }
    else
	FreeMaps[ free_index ] = map ;
}

IDMapPtr *
AllocIDMap( )

{   IDMapPtr * map ;
    register int i ;

    if ( free_index < 0 )
    {
	free_index = -1 ;
	map = ( IDMapPtr * ) Xmalloc( ID_HASHSIZE * sizeof( IDMapPtr ) ) ;
				      
    }
    else
	map = FreeMaps[ free_index-- ] ;

    for( i = 0 ; i < ID_HASHSIZE ; i++ )
	map[ i ] = NullIDMapPtr ;

    return( map ) ;
}   

IDMapPtr 
AllocEntry( )

{   IDMapPtr newentry ;

    if( FreeEntries == NullIDMapPtr )
	return ( ( IDMapPtr ) Xmalloc( sizeof( IDMapRec ) ) ) ;
    else
    {
	newentry = FreeEntries ;
        newentry->next = NullIDMapPtr ;
	FreeEntries = FreeEntries->next ;
        return( newentry ) ;
    }
}

void
InitIDMaps( )

{   register int i ;
        
    for( i = 0 ; i < MAXSOCKS ; i++ )
	MUXIDMaps[ i ] = NullTable ;
}

void 
InstallIDMap( dpy )

Display *dpy ;

{   register int i ;

#ifdef DEBUG
    CheckDisplay( dpy ) ;
#endif

    if( ( MUXIDMaps[ ConnectionNumber( dpy ) ] = AllocIDMap( ) ) == 
        NullTable )
	XmuXFatalError( "InstallIDMap: Out of memory (conn %d)!\n" ,
		    ConnectionNumber( dpy ) ) ;
    
    for( i = 0 ; i < ID_HASHSIZE ; i++ )
	MUXIDMaps[ ConnectionNumber( dpy ) ][ i ] = NullIDMapPtr ;
}

void 
XmuXInsertID( dpy , id , alias , whose )

Display *dpy ;
XID      id ,
         alias ;
int      whose ;  /* -- FromServer or FromClient -- */

{   IDMapPtr *bucket ,    /* pointer to hash table bucket */
	      newentry ;  /* pointer to new map entry */

    /* -- don't want to point to nowhere -- */

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

    /* -- the "primary" server need no hash table at all -- */
    if( IsClientDisplay( dpy ) )
	return ;
    /* 
     * -- Multiplex servers must use a hash table
     */

    if( MUXIDMaps[ ConnectionNumber( dpy ) ] == NullTable )
	/* -- create it -- */
	InstallIDMap( dpy ) ;

    /* -- find the right place -- */
    bucket = MUXIDMaps[ ConnectionNumber( dpy ) ] + HashID( id ) ;

    for( newentry = *bucket ; newentry != NullIDMapPtr ; 
         newentry = newentry->next )
        /* 
	 * -- it has been inserted before or entry is unused , 
	 * --  overwrite old values
	 */
	if( ! newentry->used || 
	    ( newentry->id  == id && newentry->whose == whose ) )
	   break ;

    if( newentry == NullIDMapPtr )
    {
	/* -- create , fill and insert a new entry -- */
	if( ( newentry = AllocEntry( ) ) == NullIDMapPtr )
	    XmuXFatalError( "XmuXInsertID: Out of memory (conn %d)!\n" ,
			    ConnectionNumber( dpy ) ) ;
	newentry->next   = *bucket ;
	*bucket = newentry ;
    }
    
    newentry->id     = id ;
    newentry->alias  = alias ;
    newentry->whose  = whose ;
    newentry->used   = True ;
    
}

/*
 * -- We do not really remove here, because its to complicated (Hint : 
 * -- XDestroyWindow destroys all subwindows too. We would only be able
 * -- to remove these IDs when removing the resource info; but that's 
 * -- the wrong place, since the request XDetroyWindow for multiplex'ed
 * -- connections comes later. Which IDs should we use then ? ).
 * -- Instead, we mark the entry as "not used".
 */

void
XmuXRemoveID( dpy , id , whose )

Display *dpy ;
XID      id ;
int      whose ; /* -- FromClient or FromServer -- */

{    IDMapPtr  curr ;      /* pointer to the entry that has to be "deleted" */
     register int i ;

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

    /* -- the "primary" server does not store any id at all -- */
    if( IsClientDisplay( dpy ) )
	return ;

    /* -- VAX can "handle" NULL pointers !!! -- */
    if( MUXIDMaps[ ConnectionNumber( dpy ) ] == NullTable )
    {
	XmuXErrorF( "XmuXRemoveID: Empty map %d!\n" , ConnectionNumber( dpy ) ) ;
	return ;
    }
    /* 
     * -- we remove the ID and it's alias !!!
     */
    for( i = 0 ; i < 2 ; i++ )
    {
	/* -- find the right place in the table -- */
	curr = MUXIDMaps[ ConnectionNumber( dpy ) ][ HashID( id ) ] ;
	
	if( curr == NullIDMapPtr )
	{
	    XmuXErrorF( "XmuXRemoveID: No entry (0x%lx ID map %d)!\n" , 
		        id , ConnectionNumber( dpy ) ) ;
	    return ;
	}
	
	/* -- search through the list -- */
	for( ; curr != NullIDMapPtr ; curr = curr->next )
	    if( curr->id == id && curr->whose == whose )
	    {   /* -- we've found it --> update the list -- */
		/* -- set values for second round -- */
		id = curr->alias ;
		whose = ( whose == FromClient ) ? FromServer : FromClient ;
		/* -- mark entry as unused -- */
		curr->used = False ;
		break ;
	    }
	if( curr == NullIDMapPtr )
	{
	    /* -- we failed ! -- */
	    XmuXErrorF( "XmuXRemoveID: ID 0x%lx not found (ID map %d)!\n" , 
		        id , ConnectionNumber( dpy ) ) ;
	    return ;
	}
    }
}

void
XmuXRemoveWindowID( dpy , window ) 

Display *dpy ;
Window   window ;

{   register Display *curr_dpy ;
    register int      i ;

    for( i = 1 ; ( curr_dpy = XmuXGetDisplay( dpy , i ) ) != NULL ; i++ )
	XmuXRemoveID( curr_dpy , window , FromClient ) ;

}

static
void
DeleteIDMap( dpy )

Display *dpy ;

{

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

    if( MUXIDMaps[ ConnectionNumber( dpy ) ] != NullTable )
	FreeIDMap( MUXIDMaps[ ConnectionNumber( dpy ) ] ) ;
    MUXIDMaps[ ConnectionNumber( dpy ) ] = NullTable ;
}

int
XmuXIsRegistered( dpy , id , whose )

Display *dpy ;
XID      id ;
int      whose ;
{   IDMapPtr entry ;

    /* -- Check the connection number (Don't want to point to nowhere) -- */
#ifdef DEBUG
    CheckDisplay( dpy , "XmuXMapID" ) ;
#endif

    /* -- id None is not registered -- */
    if( id == None )
	return( False ) ;

    /* -- the "primary" server doesn't use a hash table -- */
    if( IsClientDisplay( dpy ) )
	return( False ) ;
    /*
     * -- All other ID "pairs" are stored in a hash table 
     */

    if ( MUXIDMaps[ ConnectionNumber( dpy ) ] == NullTable )
	XmuXFatalError( "XmuXMapID: ID map %d empty!\n" , 
		        ConnectionNumber( dpy ) ) ;

    /* -- find the right place -- */
    entry = MUXIDMaps[ ConnectionNumber( dpy ) ][ HashID( id ) ] ;

    /* -- scan the list -- */
    for( ; entry != NullIDMapPtr ; entry = entry->next )
	if( entry->id == id && entry->whose == whose )
	    /* -- we've found it -- */
	    return( True ) ;

    /* -- not found -- */
    return( False ) ;
}

XID
XmuXMapID( dpy , id , whose )

Display *dpy ;
XID      id ;
int      whose ;

{   IDMapPtr entry ;

    /* -- Check the connection number (Don't want to point to nowhere) -- */
#ifdef DEBUG
    CheckDisplay( dpy , "XmuXMapID" ) ;
#endif

    /* -- don't do anything if id == None -- */
    if( id == None )
	return( None ) ;

    /* -- the "primary" server need no hash table at all -- */
    if( IsClientDisplay( dpy ) )
	return( id ) ;
    /*
     * -- All other ID "pairs" are stored in a hash table 
     */

    if ( MUXIDMaps[ ConnectionNumber( dpy ) ] == NullTable )
	XmuXFatalError( "XmuXMapID: ID map %d empty!\n" , 
		        ConnectionNumber( dpy ) ) ;

    /* -- find the right place -- */
    entry = MUXIDMaps[ ConnectionNumber( dpy ) ][ HashID( id ) ] ;

    /* -- scan the list -- */
    for( ; entry != NullIDMapPtr ; entry = entry->next )
	if( entry->id == id && entry->whose == whose )
	    /* -- we've found it -- */
	    return( entry->alias ) ;

    /* 
     * -- We've failed ! Maybe it's an id from the wm or another
     * -- client. Pass it back without changing.
     */
    return( id );
}

static 
Colormap 
FindWindowCmap( dpy , window )

Display *dpy ;
Window   window ;

{   register Colormap cmap ;
    register WindowCmapPtr entry ;

    /* --we know that the display is valid here -- */
    /* -- this is the default if we fail -- */
    cmap = DefaultColormap( dpy , DefaultScreen( dpy ) ) ;
    /* -- window == None means, use the default -- */
    if( window == None )
	return( cmap ) ;
    if( MUXWindowCmapTable[ ConnectionNumber( dpy ) ] != NullWindowCmapTable )
    {
	entry = MUXWindowCmapTable[ ConnectionNumber( dpy ) ][ HashW( window ) ] ;
    
	for( ; entry != NullWindowCmapPtr ; entry = entry->next )
	    if( entry->window == window )
	    {
		cmap = entry->cmap ;
		break ;
	    }
    }
    
    return( cmap ) ;
}

static
PixelMapPtr 
FindPixelMapPtr( dpy , window ) 

Display  *dpy ;
Window    window ;

{   register Colormap cmap ;
    register PixelMapPtr ptr ;

    cmap = FindWindowCmap( dpy , window ) ;
    ptr = MUXPixelMaps[ ConnectionNumber( dpy ) ] ;
    while( ptr != NullPixelMapPtr && cmap != ptr->cmap )
	ptr = ptr->next ;

    return( ptr ) ;
}

void
InitWindowCmapTables( )

{   register int i ;

    for( i = 0 ; i < MAXSOCKS ; i++ )
	MUXWindowCmapTable[ i ] = NullWindowCmapTable ;
}

void
InstallWindowCmapTable( dpy )

Display *dpy ;

{   register WindowCmapPtr *new_map ;
    register int i ;

    new_map = ( WindowCmapPtr * ) 
	Xmalloc( W_HASHSIZE * sizeof( WindowCmapPtr ) ) ;

    if( new_map == NullWindowCmapTable )
	XmuXFatalError( "InstallWindowCmapTable: Out of memory (conn %d)!\n",
		        ConnectionNumber( dpy ) ) ;
    for( i = 0 ; i < W_HASHSIZE ; i++ )
	new_map[ i ] = NullWindowCmapPtr ;

    MUXWindowCmapTable[ ConnectionNumber( dpy ) ] = new_map ;
}

static 
void
DeleteCmapTable( dpy )

Display *dpy ;

{   register WindowCmapPtr  entry ;
    register int            i ;

    if( MUXWindowCmapTable[ ConnectionNumber( dpy ) ] == NullWindowCmapTable )
	return ;

    for( i = 0 ; i < W_HASHSIZE ; i++ )
	if( ( entry = MUXWindowCmapTable[ ConnectionNumber( dpy ) ][ i ] ) )
	    while( entry )
	    {   register WindowCmapPtr pnext = entry->next ;
		Xfree( ( char * ) entry ) ;
		entry = pnext ;
	    }
    MUXWindowCmapTable[ ConnectionNumber( dpy ) ] = NullWindowCmapTable ;
}

void
XmuXSetWindowCmap( dpy , window , cmap , parent )

Display *dpy ;
XID      window ,
         cmap ,
         parent ;   /* -- in case we have cmap == CopyFromParent -- */

{   register WindowCmapPtr newentry , *bucket ;

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

    
    /* -- no hash table for the default display -- */
    if( IsClientDisplay( dpy ) )
	return ;
    /*
     * -- if cmap == CopyFromParent we must find out the cmap ID that
     * -- is used by the parent
     */
    if( cmap == CopyFromParent )
	cmap = FindWindowCmap( dpy , parent ) ;
    /*
     * -- Multiplex servers must use a hash table
     */
    if( MUXWindowCmapTable[ ConnectionNumber( dpy ) ] == NullWindowCmapTable )
	/* -- create it -- */
	InstallWindowCmapTable( dpy ) ;

    /* -- find the right place -- */
    bucket = MUXWindowCmapTable[ ConnectionNumber( dpy ) ] + HashW( window ) ;

    for( newentry = *bucket ; newentry != NullWindowCmapPtr ; 
	 newentry = newentry->next )
	/* -- entry exists , override old value -- */
	if( newentry->window == window )
	    break ;
    
    if( newentry == NullWindowCmapPtr )
    {
	if( ( newentry = ( WindowCmapPtr ) 
	      Xmalloc( sizeof( WindowCmapEntry ) ) ) == NullWindowCmapPtr )
	    XmuXFatalError( "XmuXSetWindowCmap: Out of memory (conn %d)!\n" ,
			    ConnectionNumber( dpy ) ) ;
	newentry->window = window ;
	newentry->cmap   = cmap ;
	newentry->next   = *bucket ;
	*bucket          = newentry ;
    }
    else
	newentry->cmap = cmap ;
}

static 
PixelMapPtr
AllocPixelMap( dpy , cmap )

Display  *dpy ;
Colormap  cmap ;

{   register PixelMapPtr new_map , 
                         ptr ;
    register int         i ;

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

    /* -- alloc a new entry -- */
    new_map = ( PixelMapPtr ) Xmalloc( sizeof( PixelMap ) ) ;

    if( new_map == NullPixelMapPtr )
	XmuXFatalError( "AllocPixelMap: Out of memory (conn %d)!\n" ,
		         ConnectionNumber( dpy ) ) ;
    /* -- fill in the values -- */
    new_map->cmap               = cmap ;
    new_map->sorted             = False ;
    new_map->next               = NullPixelMapPtr ;

    new_map->pr_calls[ ACCCalls ]  = 
    new_map->pr_calls[ ACPCalls ]  = 0 ;
    new_map->index[ ACCPixels ]    =
    new_map->index[ ACCPlanes ]    = 
    new_map->index[ ACPPixels ]    = NULL ;
    for( i = SharedPixels ; i <= DirectPlanes ; i++ )
    {
	new_map->length[ i ]    = 
	new_map->allocated[ i ] = 0 ;
	new_map->maps[ i ]       = NULL ;
    }
    /* -- append it to the list -- */
    if( ( ptr = MUXPixelMaps[ ConnectionNumber( dpy ) ] ) == NullPixelMapPtr )
	MUXPixelMaps[ ConnectionNumber( dpy ) ] = new_map ;
    else
    {
	while( ptr->next != NullPixelMapPtr )
	    ptr = ptr->next ;
	ptr->next = new_map ;
    }
    return( new_map ) ;
}

static
void
ReallocPixelValues( dpy , pmap_ptr , n , which )

Display      *dpy ;
PixelMapPtr   pmap_ptr ;
int           n ,
              which ;

{   register int size ;

#ifdef DEBUG
    CheckDisplay( dpy , "ReallocPixelMap" ) ;
#endif
    
    if( which == DirectPlanes )
	/* -- always three plane masks -- */
	size = pmap_ptr->length[ which ] + PLANES_RGB ;
    else
	size = ( ( pmap_ptr->length[ which ] + n ) / ALLOC_AT_ONCE + 1 ) * 
	           ALLOC_AT_ONCE ;
    
    pmap_ptr->maps[ which ] = ( PixelMapValues * )
       Xrealloc( pmap_ptr->maps[ which ] , size * sizeof( PixelMapValues ) ) ;
    
    if( pmap_ptr->maps[ which ] == NullPixelMapValues )
	XmuXFatalError( "ReallocPixelMap: Out of memory (conn %d)!\n" , 
		         ConnectionNumber( dpy ) ) ;
    pmap_ptr->length[ which ] = size ;
}

static
void
DeletePixelMaps( dpy )

Display *dpy ;

{   register PixelMapPtr ptr ;

    ptr = MUXPixelMaps[ ConnectionNumber( dpy ) ] ;

    while( ptr != NullPixelMapPtr )
    {   register PixelMapPtr pnext = ptr->next ;
	register int         i ;

	for( i = SharedPixels ; i <= DirectPlanes ; i++ )
	    if( ptr->length[ i ] )
		Xfree( ( char * ) ptr->maps[ i ] ) ;
	for( i = ACCPixels ; i <= ACPPixels ; i++ )
	    if( ptr->index[ i ] )
		Xfree( ( char * ) ptr->index[ i ] ) ;
	Xfree( ( char * ) ptr ) ;
	ptr = pnext ;
    }
    MUXPixelMaps[ ConnectionNumber( dpy ) ] = NullPixelMapPtr ;
}

static
void
SetIndex( pmap_ptr , index , which , call )

PixelMapPtr pmap_ptr ;
int         index ,
            which ,
            call ;

{
    pmap_ptr->index[ which ] = ( int * ) 
	Xrealloc( ( char * ) pmap_ptr->index[ which ] , 
		  pmap_ptr->pr_calls[ call ] * sizeof( int ) ) ;
    if( !pmap_ptr->index[ which ] )
	XmuXFatalError( "SetIndex: Can't realloc!\n" ) ;
    pmap_ptr->index[ which ][ pmap_ptr->pr_calls[ call ] - 1 ] = index ;
}

static
int 
SharedCell( dpy , window , pixel ) 

Display       *dpy ;
Window         window ;
unsigned long  pixel ;

{   register int i ;
    register PixelMapPtr ptr ;

    /* -- don't do any mapping on the primary connection -- */
    if( IsClientDisplay( dpy ) )
	return( False ) ;
    /*
     * -- find the right pixel map 
     */
    if( ( ptr = FindPixelMapPtr( dpy , window ) ) == NullPixelMapPtr )
	XmuXFatalError( "SharedCell: no map (win 0x%lx , conn %d)!\n " ,
		        window , ConnectionNumber( dpy ) ) ;

    for( i = 0 ; i < ptr->allocated[ SharedPixels ] ; i++ )
	if( pixel == CLIENT_VALUE( ptr , i , SharedPixels ) )
	    return( True ) ;

    return( False ) ;
}
static
int
GetServerMask( ptr , old_mask , new_mask )

PixelMapPtr    ptr ;
unsigned long  old_mask ,
              *new_mask ;

{   register  int i ,
                  k ,
                  bits_set ,
                  matches ;

    
    if( !ptr->pr_calls[ ACCCalls ] && !ptr->pr_calls[ ACPCalls ] )
    {
       *new_mask = 0L ;
	return( False ) ;
    }
    else
    {  register int  start_planes ,
	             end_planes ;
       bits_set = 0 ;
       for( i = 0 ; i < sizeof( unsigned long ) ; i++ )
	 if( ( 1 << i ) & old_mask )
	   bits_set++ ;

	/*
	 * -- Is it a private cell allocated by XAllocColorCells ?
	 */
	/* -- generate plane values for every call -- */
	for( k = 0 ; k < ptr->pr_calls[ ACCCalls ] ; k++ )
	{   
	    *new_mask = 0L ;
	    matches = 0 ;
	    start_planes = INDEX( ptr , k , ACCPlanes ) ;
	    if( k < ptr->pr_calls[ ACCCalls ] - 1 )
		end_planes   = INDEX( ptr , k + 1 , ACCPlanes ) ;
	    else
		end_planes   = ALLOCATED( ptr , PseudoPlanes ) ;
	    for( i = start_planes ; i < end_planes ; i++ )
	       if( CLIENT_VALUE( ptr , i , PseudoPlanes ) & old_mask )
	       {
		   matches++ ;
		   *new_mask |= SERVER_VALUE( ptr , i , PseudoPlanes ) ;
	       }
	    if ( matches == bits_set )
	      return( True ) ;
	}
	/*
	 * -- last chance : 
	 * -- Is it a private cell allocated by XAllocColorPlanes ?
	 */
	for( k = 0 ; k < ptr->pr_calls[ ACPCalls ] ; k++ )
	{   register unsigned long cl_base ,
		                   cl_bits ,
		                   cl_mask ,
		                   sv_base ,
		                   sv_bits ,
		                   sv_mask ;

		 
	    cl_bits = 
	    sv_bits = 0L ;
	    cl_mask = CLIENT_RGBS( ptr , k ) ;
	    sv_mask = SERVER_RGBS( ptr , k ) ;
	    cl_base = lowbit( cl_mask ) ;
	    sv_base = lowbit( sv_mask ) ;
	   
	    *new_mask = 0L ;
	    matches = 0 ;
	    /* -- try all bit combinations -- */
	    while( 1 )
	    {
		if( old_mask & cl_bits )
		{
		    matches++ ;
		    *new_mask |= sv_bits ;
		}
		GetNextBitsOrBreak( sv_bits , sv_mask , sv_base ) ;
		GetNextBitsOrBreak( cl_bits , cl_mask , cl_base ) ;
	    }
	    if( matches == bits_set )
	      return( True ) ;
       }
       /* -- we fall through all loops, so we didn't find a match -- */
       *new_mask = 0L ;
       return( False ) ;
     }
}
/*
 * -- GetServerPixel : Tries to map a pixel passed by the client to the 
 *                     corresponding pixel value on the (multiplex'ed)
 *                     server side.
 *
 * -- Since we're allowing private color cell allocation, we have to use a 
 * -- try-and-error algorithm (best case first, worst case last):
 * -- First try to map the pixel using the shared cells. On failure, try
 * -- to map the pixel to a private cell allocated via XAllocColorCells.
 * -- If even that step fails, look at the private cells allocated via
 * -- XAllocColorPlanes.
 * -- The second and third case indicate, that we may have to map planes too.
 * -- To make this plane mapping faster, we return in index and call the
 * -- place we have to look for.
 */

static
unsigned long
GetServerPixel( ptr , pixel )

PixelMapPtr    ptr ;
unsigned long  pixel ;

{   register int i ;

    /* 
     * -- Is it a shared color cell ? 
     */
    if( ptr->sorted )
    {   int l , m  , r ;

	/* -- use binary search -- */
	l = 0 ; 
	r = ptr->allocated[ SharedPixels ] - 1 ;
	m = ( l + r ) >> 1 ;

	while( l <= r )
	    {
		if( CLIENT_VALUE( ptr , m , SharedPixels ) == pixel )
		    return( SERVER_VALUE( ptr , m , SharedPixels ) ) ;
		else 
		    if( CLIENT_VALUE( ptr , m , SharedPixels ) < pixel )
			l = m + 1 ;
		    else
			r = m - 1 ; 
		m = ( r + l ) >> 1 ;
	    }
    }
    else
    {   
	/* -- use linear search -- */
	for( i = 0 ; 
	     i < ptr->allocated[ SharedPixels ] ; i++ )
	    
	    if( CLIENT_VALUE( ptr , i , SharedPixels ) == pixel )
		return( SERVER_VALUE( ptr , i , SharedPixels ) ) ;
    }

    /* 
     * -- nothing found ; if client hasn't allocated private cells 
     * -- return the original value
     */
    if( !ptr->pr_calls[ ACCCalls ] && !ptr->pr_calls[ ACPCalls ] )
	return( pixel ) ;
    else
    {   unsigned long used_planes ,
                      base_pixel ;
	register int  start_planes ,
	              end_planes ,
	              start_pixels ,
                      end_pixels ,
	              j , 
	              k ,
	              found ;
	/* 
	 * -- This is how we map a private color cell (pixel value):
	 * -- 1. Strip off the used plane masks to get the base pixel
	 * -- 2. Map the base pixel 
	 * -- 3. OR the mapped base pixel with the mapped plane masks 
	 * -- PROBLEM :
	 * -- The only thing that's unique is the base pixel value (you can't
	 * -- get the same base pixel values from different calls to 
	 * -- XAllocColorCells) , whereas one plane_mask may occur several
	 * -- times. So, we must use a try-and-error tecnique here :
	 * -- Do the three steps above for every "private call" until you 
	 * -- find the recalculated base pixel value in that part of
	 * -- the private pixel array.
	 */

	/*
	 * -- Is it a private cell allocated by XAllocColorCells ?
	 */
	/* -- generate pixel values for every call -- */
	for( k = 0 ; k < ptr->pr_calls[ ACCCalls ] ; k++ )
	{   

	    start_pixels = INDEX( ptr , k , ACCPixels ) ;
	    start_planes = INDEX( ptr , k , ACCPlanes ) ;
	    
	    if( k < ptr->pr_calls[ ACCCalls ] - 1 )
	    {
		end_planes   = INDEX( ptr , k + 1 , ACCPlanes ) ;
		end_pixels   = INDEX( ptr , k + 1 , ACCPixels ) ; 
	    }
	    else
	    {
		end_planes   = ALLOCATED( ptr , PseudoPlanes ) ;
		end_pixels   = ALLOCATED( ptr , PseudoPixels ) ;
	    }
	    used_planes = 0L ;
	    base_pixel  = pixel ;
	
	    for( i = start_planes ; i < end_planes ; i++ )
	    {   
		/* 
		 * -- 1. Strip off the planes ( and implicitly "map" them )
		 */
		if( base_pixel & CLIENT_VALUE( ptr , i , PseudoPlanes ) )
		{
		    base_pixel &= ~CLIENT_VALUE( ptr , i , PseudoPlanes ) ;
		    used_planes |= SERVER_VALUE( ptr , i , PseudoPlanes ) ;
		}
	    }
	    /*
	     * -- Try to find the base pixel
	     */
	    for( j = start_pixels ; j < end_pixels ; j++ )
		if( CLIENT_VALUE( ptr , j , PseudoPixels ) == base_pixel )
		{
		    /* -- that's it ! -- */
		    base_pixel = SERVER_VALUE( ptr , j , PseudoPixels ) ;
		    return( base_pixel | used_planes ) ;
		}
	}
	/*
	 * -- last chance : 
	 * -- Is it a private cell allocated by XAllocColorPlanes ?
	 */
	for( k = 0 ; k < ptr->pr_calls[ ACPCalls ] ; k++ )
	{   register unsigned long cl_bit , 
		                   cl_planes ,
		                   sv_bit ,
		                   sv_planes ;

	    start_pixels = INDEX( ptr , k , ACCPixels ) ;
	    
	    if( k < ptr->pr_calls[ ACPCalls ] - 1 )
		end_pixels   = INDEX( ptr , k + 1 , ACPPixels ) ; 
	    else
		end_pixels   = ALLOCATED( ptr , DirectPixels ) ;
	    
	    base_pixel   = pixel ;
	    used_planes  = 0L ;

	    /* -- always three masks (red,green,blue) -- */
	    for( i = 0 ; i < PLANES_RGB ; i++ )
	    {
		/* -- 1. Strip off the planes ( and implicitly "map" them )
		 * -- here , plane is really a set of planes
		 * -- must try all "single-bit-set" combinations for
		 * -- red_mask , green_mask , blue_mask 
		 */
		cl_bit    = 
		sv_bit    = 0L ;
		cl_planes = CLIENT_VALUE( ptr , k * PLANES_RGB + i , 
					  DirectPlanes ) ;
		sv_planes = SERVER_VALUE( ptr , k * PLANES_RGB + i ,
					  DirectPlanes ) ;
		while( cl_planes )
		{
		    if( base_pixel & cl_bit )
		    {
			base_pixel  &= ~cl_bit ;
			used_planes |= ~sv_bit ;
		    }
		    /*
		     * -- NOTE : sv_planes and cl_planes
		     * -- have the same number of bis set !
		     */
		    cl_bit     = lowbit( cl_planes ) ;
		    cl_planes &= ~cl_bit ;
		    sv_bit     = lowbit( sv_planes ) ;
		    sv_planes &= ~sv_bit ;
		}
	    }

	    /* 
	     * -- all planes are stripped off; 
	     * -- try to find the base pixel 
	     */
	    
	    for( j = start_pixels ; j < end_pixels ; j++ )
		if( CLIENT_VALUE( ptr , j , DirectPixels ) == base_pixel )
		{
		    /* -- that's it ! -- */
		    base_pixel = SERVER_VALUE( ptr , j , DirectPixels ) ;
		    return( base_pixel | used_planes ) ;
		}
	}
	    
	/* -- we're out of luck, return the unchanged value -- */
	return( pixel ) ;
    }
}

static
MapPlanes( i , ptr , offset , cl_mask , sv_mask )

int             i ;
PixelMapPtr     ptr ;
int             offset ;
unsigned long  *cl_mask ,
               *sv_mask ;

{   register int j ;

    *cl_mask = 
    *sv_mask = 0L ;

    for( j = 0 ; ( 1L << j ) <= i ; j++ )
	if( ( 1L << j ) & i )
	{
	  *cl_mask |= CLIENT_VALUE( ptr , offset + j , 
				    PseudoPlanes ) ;
	  *sv_mask |= SERVER_VALUE( ptr , offset + j , 
				    PseudoPlanes ) ;
	}
}

/*
 * -- pixel caches are restricted to 8 plane machines 
 */
#define CACHE_SIZE 256 
unsigned long _theCache[ CACHE_SIZE ] ;

static
unsigned long 
*PixelMapCache( ptr , length )

PixelMapPtr  ptr ;
int         *length ;

{   register int i ,
                 k ,
                 start_pixels ,
                 end_pixels ;

    unsigned long cl_pixel , 
                  sv_pixel ,
                  cl_mask ,
                  sv_mask ;

    for( i = 0 ; i < CACHE_SIZE  ; i++ )
	/* -- garbage in , garbage out -- */
	_theCache[ i ] = i ;

    /* -- the shared cells -- */
    for( i = 0 ; i < ptr->allocated[ SharedPixels ] ; i++ )
	  _theCache[ CLIENT_VALUE( ptr , i , SharedPixels ) ] = 
	      SERVER_VALUE( ptr , i , SharedPixels ) ;

    /* 
     * -- the private cells from XAllocColorCells : 
     * -- generate pixel values for every call 
     */
    for( k = 0 ; k < ptr->pr_calls[ ACCCalls ] ; k++ )
    {   register int num_planes ;
	
	start_pixels = INDEX( ptr , k , ACCPixels ) ;
	if( k < ptr->pr_calls[ ACCCalls ] - 1 )
	{
	    num_planes = ( int )( 1L << ( INDEX( ptr , k + 1 , ACCPlanes ) - 
				      INDEX( ptr , k , ACCPlanes ) ) ) ;
	    end_pixels   = INDEX( ptr , k + 1 , ACCPixels ) ; 
	}
	else
	{
	    num_planes = ( int )( 1L << ( ALLOCATED( ptr , PseudoPlanes ) -
					  INDEX( ptr , k , ACCPlanes ) ) ) ;
	    end_pixels   = ALLOCATED( ptr , PseudoPixels ) ;
	}

	for( i = 0 ; i < num_planes ; i++ )
	{   register int j ;

	    MapPlanes( i , ptr , INDEX( ptr , k , ACCPlanes ) ,
		       &cl_mask , &sv_mask ) ;
	  
	    for( j = start_pixels ; j < end_pixels ; j++ )
	    {
		cl_pixel = CLIENT_VALUE( ptr , j , PseudoPixels ) | cl_mask ;
		sv_pixel = SERVER_VALUE( ptr , j , PseudoPixels ) | sv_mask ;
		if( cl_pixel > CACHE_SIZE ) 
		    return( ( unsigned long * ) NULL ) ;
		else
		    _theCache[ cl_pixel ] = sv_pixel ;
	    }
	}
    }
    /*
     * -- generate all pixels allocated by XAlocColorPlanes ;
     * -- REMEMBER : the red/green/blue plane masks  are sets of planes
     * --  Must generate all pixels * 2^( red + blue + green ) combinations
     */
    for( k = 0 ; k < ptr->pr_calls[ ACPCalls ] ; k++ )
    {   register unsigned long cl_bits ,
	                       sv_bits ,
	                       cl_base ,
	                       sv_base ;
	cl_bits = 
	sv_bits = 0L ;
	cl_mask = CLIENT_RGBS( ptr , k ) ;
	sv_mask = SERVER_RGBS( ptr , k ) ;
	cl_base = lowbit( cl_mask ) ;
	sv_base = lowbit( sv_mask ) ;

	start_pixels = INDEX( ptr , k , ACCPixels ) ;
	if( k < ptr->pr_calls[ ACPCalls ] - 1 )
	    end_pixels   = INDEX( ptr , k + 1 , ACCPixels ) ; 
	else
	    end_pixels   = ALLOCATED( ptr , DirectPixels ) ;

	while( 1 )
	{   register int j ;
	    
	    for( j = start_pixels ; j < end_pixels ; j++ )
	    {
		cl_pixel = CLIENT_VALUE( ptr , j , DirectPixels ) | cl_bits ;
		sv_bits  = SERVER_VALUE( ptr , j , DirectPixels ) | sv_bits ;
		if( cl_pixel > CACHE_SIZE ) 
		    return( ( unsigned long * ) NULL ) ;
		else
		    _theCache[ cl_pixel ] = sv_pixel ;
	    }
	    /* macro from X server sources */
	    GetNextBitsOrBreak( sv_bits , sv_mask , sv_base ) ;
	    GetNextBitsOrBreak( cl_bits , cl_mask , cl_base ) ;
	}
    }
		
    *length = CACHE_SIZE ;
    return( &_theCache[ 0 ] ) ;
}
    
void
InitPixelMaps( ) 

{   register int i ;

    for( i = 0 ; i < MAXSOCKS ; i++ )
	MUXPixelMaps[ i ] = NullPixelMapPtr ;
}

void
XmuXInsertSharedCell( dpy , cmap , client_pixel , server_pixel )

Display       *dpy ;
Colormap       cmap ;
unsigned long  client_pixel ,
               server_pixel ;

{   register PixelMapPtr ptr ;

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

    ptr = MUXPixelMaps[ ConnectionNumber( dpy ) ] ;
    while( ptr != NullPixelMapPtr && ptr->cmap != cmap )
	    ptr = ptr->next ;
    if( ptr == NullPixelMapPtr )
	ptr = AllocPixelMap( dpy , cmap ) ;

    if( MUST_REALLOC( ptr , 1 , SharedPixels ) )
	ReallocPixelValues( dpy , ptr , 1 , SharedPixels ) ;

    CLIENT_VALUE( ptr , ALLOCATED( ptr , SharedPixels ) , SharedPixels ) = 
	client_pixel ;
    SERVER_VALUE( ptr , ALLOCATED( ptr , SharedPixels ) , SharedPixels ) = 
	server_pixel ;
    ptr->allocated[ SharedPixels ]++ ;

}

void
XmuXInsertPrivateCells( dpy , cmap , client_pixels , server_pixels , 
			 n_pixels , client_planes , server_planes , n_planes ,
		         AllocColorCells )
			 

Display       *dpy ;
Colormap       cmap ;
unsigned long *client_pixels ,
              *server_pixels ,
              *client_planes ,
              *server_planes ;
int            n_pixels ,
               n_planes ,
               AllocColorCells ;  /* cells from XAllocColorCells ? */

{   register PixelMapPtr ptr ;
    register int         which_pixels ,
                         which_planes ;

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

    ptr = MUXPixelMaps[ ConnectionNumber( dpy ) ] ;
    while( ptr != NullPixelMapPtr && ptr->cmap != cmap )
	    ptr = ptr->next ;

    if( ptr == NullPixelMapPtr )
	ptr = AllocPixelMap( dpy , cmap ) ;
    
    if( AllocColorCells )
    {
	if( MUST_REALLOC( ptr , n_pixels , PseudoPixels ) )
	    ReallocPixelValues( dpy , ptr , n_pixels , PseudoPixels ) ;
	if( MUST_REALLOC( ptr , n_planes , PseudoPlanes ) )
	    ReallocPixelValues( dpy , ptr , n_planes , PseudoPlanes ) ;

	ptr->pr_calls[ ACCCalls ]++ ;

	SetPseudoPixelIndex( ptr , ALLOCATED( ptr , PseudoPixels ) ) ;
	SetPseudoPlaneIndex( ptr , ALLOCATED( ptr , PseudoPlanes ) ) ;
	which_pixels = PseudoPixels ;
	which_planes = PseudoPlanes ;
    }
    else
    {
	if( MUST_REALLOC( ptr , n_pixels , DirectPixels ) )
	    ReallocPixelValues( dpy , ptr , n_pixels , DirectPixels ) ;
	if( MUST_REALLOC( ptr , n_planes , DirectPlanes ) )
	    ReallocPixelValues( dpy , ptr , n_planes , DirectPlanes ) ;
	
	ptr->pr_calls[ ACPCalls ]++ ;
	
	SetDirectPixelIndex( ptr, ALLOCATED( ptr , DirectPixels ) ) ;
	which_pixels = DirectPixels ;
	which_planes = DirectPlanes ;
    }

	while( --n_pixels >= 0 )
	{

	    CLIENT_VALUE( ptr , 
			  ALLOCATED( ptr , which_pixels ) , which_pixels ) = 
			       client_pixels[ n_pixels ] ;
	    SERVER_VALUE( ptr , 
			  ALLOCATED( ptr , which_pixels ) , which_pixels ) = 
			       server_pixels[ n_pixels ] ;
	ptr->allocated[ which_pixels ]++ ;
    }
 

    while( --n_planes >= 0 )
    {

	CLIENT_VALUE( ptr , 
		      ALLOCATED( ptr , which_planes ) , which_planes ) = 
			  client_planes[ n_planes ] ;
	SERVER_VALUE( ptr , 
		      ALLOCATED( ptr , which_planes ) , which_planes  ) = 
			  server_planes[ n_planes ] ;
	ptr->allocated[ which_planes ]++ ;
    }
}
    
unsigned long
XmuXMapPixel( dpy , window , pixel )

Display       *dpy ;
Window         window ;
unsigned long  pixel ;

{   register PixelMapPtr ptr ;

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

    /* -- don't do any mapping on the primary connection -- */
    if( IsClientDisplay( dpy ) )
	return( pixel ) ;
    /*
     * -- find the right pixel map 
     */
    if( ( ptr = FindPixelMapPtr( dpy , window ) ) == NullPixelMapPtr )
	XmuXFatalError( "XmuXMapPixel: no map (win 0x%lx , conn %d)!\n " ,
		        window , ConnectionNumber( dpy ) ) ;

    return( GetServerPixel( ptr , pixel ) ) ;
}

void
XmuXMapGCValues( dpy , window , old_fg , old_bg, old_mask , 
		       new_fg , new_bg , new_mask , function )

Display        *dpy ;
Window          window ;
unsigned long  old_fg ,
               old_bg ,
               old_mask ,
              *new_fg ,
              *new_bg ,
              *new_mask ,
               function ;

{   register PixelMapPtr   ptr ;

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

    /* -- don't do any mapping on the primary connection -- */
    if( IsClientDisplay( dpy ) )
	return;
    /*
     * -- find the right pixel map 
     */
    if( ( ptr = FindPixelMapPtr( dpy , window ) ) == NullPixelMapPtr )
	XmuXFatalError( "XmuXMapGCValues: no map (win 0x%lx , conn %d)!\n " ,
		        window , ConnectionNumber( dpy ) ) ;

    switch( function )
    {

    case GXxor :
	*new_fg   = GetServerPixel( ptr , ( old_fg ^ old_bg ) ) ;
	*new_bg   = GetServerPixel( ptr , old_bg ) ;
	*new_fg  ^= *new_bg ;
	if( !GetServerMask( ptr , old_mask , new_mask ) )
	    *new_mask = old_mask ;
	break ;
    
    case GXinvert :
	*new_bg  = GetServerPixel( ptr , old_bg ) ;
	*new_fg  = GetServerPixel( ptr , old_fg ) ;
	if( !GetServerMask( ptr , old_mask , new_mask ) )
	    *new_mask = *new_fg ^ *new_bg ;
	break ;

    default :
	*new_bg = GetServerPixel( ptr , old_bg ) ;
	*new_fg = GetServerPixel( ptr, old_fg ) ;
	if( !GetServerMask( ptr , old_mask , new_mask ) )
	{
	    if( old_fg == old_mask )
		*new_fg   = old_fg ;
	    *new_mask = old_mask ;
	}
	break ;
    }
}

int
XmuXMapPixelsAndPlanes( dpy , cmap , pixels , npixels , planes )

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

{   int                    i ;
    register PixelMapPtr   ptr ;

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

    /*
     * -- find the right pixel map 
     */
    
    ptr = MUXPixelMaps[ ConnectionNumber( dpy ) ] ;
    while( ptr != NullPixelMapPtr && cmap != ptr->cmap )
	ptr = ptr->next ;
    
    if( ptr == NullPixelMapPtr )
	XmuXFatalError( "XmuXMapPixelsAndPlanes: no map !\n" ) ;

    for( i = 0 ; i < npixels ; i++ )
	pixels[ i ] = GetServerPixel( ptr , pixels[ i ] ) ;

    if( *planes != 0L )
	if( !GetServerMask( ptr , *planes , planes ) )
	    return( 0 ) ;
    return( 1 ) ;
}
    
int
CompareClPixel( a , b ) 

PixelMapValues *a , *b ;

{
    if( a->client_value < b->client_value )
	return( -1 ) ;
    else
	if( a->client_value > b->client_value ) 
	    return( 1 ) ;
	else
	    return( 0 ) ;
}

void
XmuXSortPixelMaps( dpy )

Display *dpy ;

{   register PixelMapPtr ptr ;

#ifdef DEBUG
    CheckDisplay( dpy , "XmuXSortPixelMap" ) ;
#endif
    
    for( ptr = MUXPixelMaps[ ConnectionNumber( dpy ) ] ;
	 ptr != NullPixelMapPtr ; 
	 ptr = ptr->next ) 
	if( !ptr->sorted )
    {
	XmuXdebug( debug_mux , "Sort pixel map %d..." , 
		   ConnectionNumber( dpy ) ) ;
	qsort( &(ptr->maps[ SharedPixels ][ 0 ]) ,
	       ptr->allocated[ SharedPixels ] ,
	       sizeof( PixelMapValues ) ,
	       CompareClPixel ) ;
	ptr->sorted = True ;
	XmuXdebug( debug_mux , "done\n" ) ;
    }
}

unsigned long 
*CreatePixelMapCache( dpy , window , length ) 

Display *dpy ;
Window   window ;
int     *length ;

{   register PixelMapPtr    ptr ;

    ptr = FindPixelMapPtr( dpy , window ) ;
    *length  = 0 ;
    if( ptr == NullPixelMapPtr )
	return( ( unsigned long * ) NULL ) ;
    else
	return( PixelMapCache( ptr , length ) ) ;
}

/* -- two macros from XImUtil.c : used in XmuXMapImage -- */

#define ZNORMALIZE(bp, nbytes, img) \
    if (img->byte_order == MSBFirst) \
	_normalizeimagebits((unsigned char *)(bp), (nbytes), MSBFirst, img->bits_per_pixel, \
	LSBFirst)

#define ZINDEX(x, y, img) ((y) * img->bytes_per_line) + \
    (((x) * img->bits_per_pixel) >> 3)

static unsigned char _reverse_byte[0x100] = {
	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
}; /* found in XPutImage */

/* 
 * -- from XImUtil.c 
 */
static _normalizeimagebits (bpt, nb, byteorder, unitsize, bitorder)
    unsigned char *bpt;	/* beginning pointer to image bits */
    int nb;		/* number of bytes to normalize */
    int byteorder;	/* swap bytes if byteorder == MSBFirst */
    int unitsize;	/* size of the bitmap_unit or Zpixel */
    int bitorder;	/* swap bits if bitorder == MSBFirst */
{
	if ((byteorder==MSBFirst) && (byteorder!=bitorder)) {
	    register char c;
	    register unsigned char *bp = bpt;
	    register unsigned char *ep = bpt + nb;
	    register unsigned char *sp;
	    switch (unitsize) {

		case 4:
		    do {			/* swap nibble */
			*bp = ((*bp >> 4) & 0xF) | ((*bp << 4) & ~0xF);
			bp++;
		    }
		    while (bp < ep);
		    break;

		case 16:
		    do {			/* swap short */
			c = *bp;
			*bp = *(bp + 1);
			bp++;
			*bp = c;
			bp++;
		    }
		    while (bp < ep);
		    break;

		case 24:
		    do {			/* swap three */
			c = *(bp + 2);
			*(bp + 2) = *bp;
			*bp = c;
			bp += 3;		
		    }
		    while (bp < ep);
		    break;

		case 32:
		    do {			/* swap long */
			sp = bp + 3;
			c = *sp;
			*sp = *bp;
			*bp++ = c;
			sp = bp + 1;
			c = *sp;
			*sp = *bp;
			*bp++ = c;
			bp += 2;
		    }
		    while (bp < ep);
		    break;
	    }
	}
	if (bitorder == MSBFirst) {
	    do {
		*bpt = _reverse_byte[*bpt];
		bpt++;
	    }
	    while (--nb > 0);
	}
}

#define MAPPIXEL( dpy , window , pcache , pixel , length ) \
    ( pcache != ( unsigned long * ) NULL ) ? \
       ( ( pixel <= length ) ? pcache[ pixel ] : pixel ) :\
    XmuXMapPixel( dpy , window , pixel )\

#define FREE_CACHE( cache ) 

void
XmuXMapImage( dpy , window , ximage )

Display *dpy ;
Window   window ;
XImage  *ximage ;

{   unsigned long pixel;
    register unsigned char *dp, *src, *dst, *tmp;
    register int x;
    int y , length ;
    long nbytes, i;
    register unsigned long *pcache ;

    /*
     * -- What shall we do if application uses a private colormap and
     * -- the specified window in really a pixmap ? (e.g. this mapping
     * -- results from a call to XCreatePixmapFromBitmapData )
     * -- We hope our application is a polite one that creates "real" pixmaps
     * -- (depth > 1) with the window where it is used with; or to put it
     * -- in a "politness rule" : "Don't use the same pixmap with (windows 
     * -- that use) different colormaps!"
     * -- We hope our application will follow this rule: if "window" is a
     * -- pixmap, we retrieve the drawable (and hope that it is a window!)
     * -- the pixmap was created with and use this as a reference to the 
     * -- "right" colormap !
     */
    if( XmuXUsesPrivateCmaps( dpy ) && XmuXIsPixmap( dpy , window ) )
    {   register Display *dflt_dpy ;
	
	/*
	 * -- XmuXMapImage is called with a multiplexed display, but the
	 * -- information we need here is stored in the default display's
	 * -- resource list 
	 */
	dflt_dpy = XmuXPrimaryDisplayFromDisplay( dpy ) ;
	/* -- unmap the window ID -- */
	window   = XmuXMapID( dpy , window , FromServer ) ;
	window = XmuXGetPixmapDrawable( dpy , window ) ;
	/* -- map the new ID -- */
	window = XmuXMapID( dpy , window , FromClient ) ;
    }
    /*
     * -- We want to avoid calling XPutPixel and XGetPixel for
     * -- every image pixel. We must confess, that we are too lazy
     * -- to develop a new algorithm here; instead, we modify 
     * -- _XAddPixel and hope that we don't fall in the else case 
     * -- ASSUMPTION : image depth is always greater than one !
     * -- When called from DuplicatePixmap image is always in ZPixmap format
     * -- We accelerate pixel mapping here by creating a pixel map cache,
     * -- where pixel mapping can be done by simple indexing instead of 
     * -- calling XmuXMapPixel (which searches for the right pixel map every
     * -- time )
     */
    length = 0 ;
    pcache = CreatePixelMapCache( dpy , window , &length ) ;

    if (ximage->format == XYPixmap) 
    {
	/* this is slow, may do better later */
	for (y = 0; y < ximage->height; y++) {
	    for (x = 0; x < ximage->width; x++) {
		pixel = XGetPixel(ximage, x, y);
		pixel = MAPPIXEL( dpy , window , pcache , pixel , length ) ;
		XPutPixel(ximage, x, y, pixel);
	    }
	}
    } 
    else 
    /* 
     * This has stupid little-endian assumptions; to fix it you
     * would need to make sure that it copies the right nbytes
     * into and out of the variable "pixel".  Later.
     */

    /* If the bits_per_pixel makes the alignment occur on even
     * byte boundaries, perform the addition by stepping thru
     * the data one pixel at a time.  Otherwise, do it the slow
     * way by calling get and put pixel.
     */
	if ((ximage->bits_per_pixel & 7) == 0) {
	    nbytes = (ximage->bits_per_pixel + 7 ) >> 3;
	    for (y = 0; y < ximage->height; y++) 
	    {
		src = (unsigned char *) &ximage->data[ZINDEX(0, y, ximage)];
		dst = src;
		for (x = 0; x < ximage->width; x++) 
		{
		    pixel = 0;
		    tmp = (unsigned char *)&pixel;
		    for (i = 0; i < nbytes; i++) *tmp++ = *src++;
		    ZNORMALIZE(&pixel, nbytes, ximage);
		    pixel = MAPPIXEL( dpy , window , pcache , 
				      pixel , length ) ;
		    ZNORMALIZE(&pixel, nbytes, ximage);
		    tmp = (unsigned char *)&pixel;
		    for (i = 0; i < nbytes; i++) *dst++ = *tmp++;
		}
	    }			    
	} 
	else 
	{
	    for (y = 0; y < ximage->height; y++) {
		for (x = 0; x < ximage->width; x++) {
		    pixel = XGetPixel(ximage, x, y);
		    pixel = XmuXMapPixel( dpy , window , pixel );
		    XPutPixel(ximage, x, y, pixel);
		}
	    }
	}

	FREE_CACHE( pcache ) ;
}

#undef MAPPIXEL

int
XmuXMapDepth( dpy , depth , drawable , type )

Display       *dpy ;
unsigned int   depth ;   
Drawable       drawable ;
int            type ;

{   unsigned int i ;
    long         sup_depths ;

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

    /*
     * -- depth 0 is always supported ( depth of input-only windows )
     */
    if( depth == 0 )
	return( 0 ) ;

    if( ( type == IsPixmap ) || 
        ( ( type == DontKnow ) &&  XmuXIsPixmap( dpy , drawable ) ) )
    {
	sup_depths = 
	    ConnectionTranslation[ ConnectionNumber( dpy ) ]->all_depths ;
	/* 
	 * -- supported depths is a bit array; check if dpy supports depths
	 * -- greater or equal than the requested
	 */
	if( sup_depths >= ( 1L << ( depth - 1 ) ) )
	{   
	    for( i = depth ; i < sizeof( long ) << 3 ; i++ )
		if( sup_depths & ( 1L << ( i - 1 ) ) )
		    return( i ) ;
	}
	else
	    for( i = depth - 1 ; i >= 0 ; i-- )
		if( sup_depths & ( 1L << ( i - 1 ) ) )
		    return( i ) ;
    }
    /* 
     * -- it's a window --> use the corresponding visual to find the right
     * -- depth 
     */
    else 
    {
	if( XmuXDepthViaVisual( dpy , drawable , &i ) ) 
	    return( i ) ;
	else
	{
	    /* 
	     * -- still possible, e.g call from FindBestVisual
	     */
	    sup_depths = 
		ConnectionTranslation[ ConnectionNumber( dpy ) ]->vis_depths ;
	    /* 
	     * -- supported depths is a bit array; check if dpy supports depths
	     * -- greater or equal than the requested
	     */
	    if( sup_depths >= ( 1L << ( depth - 1 ) ) )
	    {   
		for( i = depth ; i < sizeof( long ) << 3 ; i++ )
		    if( sup_depths & ( 1L << ( i - 1 ) ) )
			return( i ) ;
	    }
	    else
		for( i = depth - 1 ; i >= 0 ; i-- )
		    if( sup_depths & ( 1L << ( i - 1 ) ) )
			return( i ) ;
	}
    }
}

void
XmuXMapColors( dpy , cmap , colors , ncolors )

Display  *dpy ;
Colormap  cmap ;
XColor   *colors ;
int       ncolors ;

{   PixelMapPtr             ptr ;
    int                     length ;
    register unsigned long *pcache ;

    ptr = MUXPixelMaps[ ConnectionNumber( dpy ) ] ;
    while( ptr != NullPixelMapPtr && cmap != ptr->cmap )
	ptr = ptr->next ;
    
    if( ptr == NullPixelMapPtr )
	XmuXFatalError( "XmuXMapColors: no map !\n" ) ;

    length = 0 ;
    pcache = PixelMapCache( ptr , &length ) ;
    if( !length )
    {
	while( --ncolors >= 0 )
	    colors[ ncolors ].pixel = 
	      GetServerPixel( ptr , colors[ ncolors ].pixel );
						      
    }
    else
    {
	while( --ncolors >= 0 )
	    colors[ ncolors ].pixel = pcache[ colors[ ncolors ].pixel ] ;
	FREE_CACHE( pcache ) ;
    }
}

XmuXFreeMaps( dpy )

Display *dpy ;

{

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

    DeleteIDMap( dpy ) ;
    DeleteCmapTable( dpy ) ;
    DeletePixelMaps( dpy ) ;

}
