/*********************************************************************
 *
 *         EZWGL, the EZ Widget and Graphics Library
 *
 *             Copyright (C) 1996, 1997  Maorong Zou
 *  
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **********************************************************************/
/*
 *  June 1996.  Beta Release.
 *  Sept 1996.  Release Version 1.0
 *  Dec 1996.  Release Version 1.1 Beta
 *  April 1997.  Release Version 1.2
 *  November 1997.  Release Version 1.3
 *  May 1997. Handling of raw rgb images added by Arno Dabekaussen.
 */
/*********************************************************************
 ***                                                               ***
 ***            Simple hash tables for widgets.                    ***
 ***             For quick loop up of a widget                     ***
 ***                  from its window id                           ***
 ***            And from its address                               ***
 ***                                                               ***
 *********************************************************************/
#define _EZ_WIDGET_HASH_C_
#include "EZ_Widget.h"

#define STANDARD_BITMAP_INCLUDE "/usr/include/X11/bitmaps/"
#define STANDARD_PIXMAP_INCLUDE "/usr/include/X11/pixmaps/"

/*********************************************************************
 * 
 *  Functions implemented in this file:
 */
EZ_Bitmap         *EZ_CreateLabelPixmapFromXpmFile MY_ANSIARGS((char *file));
EZ_Bitmap         *EZ_CreateLabelPixmapFromXpmData MY_ANSIARGS((char **data));
EZ_Bitmap         *EZ_CreateLabelPixmapFromRawRGB MY_ANSIARGS((char *data, int width, int height));
EZ_Bitmap         *EZ_CreateLabelPixmapFromXBitmapFile MY_ANSIARGS((char *file));
EZ_Bitmap         *EZ_CreateLabelPixmapFromXBitmapData MY_ANSIARGS((char *file, unsigned int w, unsigned int h));
EZ_Bitmap         *EZ_CreateLabelPixmapFromImageFile MY_ANSIARGS((char *file));
void              EZ_FreeLabelPixmap MY_ANSIARGS((EZ_Bitmap *bitmap));
void              EZ_FreeXPixmap MY_ANSIARGS((Pixmap pixmap));
int               EZ_GetLabelPixmapInfo MY_ANSIARGS((EZ_Bitmap *bitmap,
						     Pixmap *p_ret, Pixmap *s_ret, int *w, int *h));
void              EZ_SetIconPath MY_ANSIARGS((char *path));
char              *EZ_GetIconPath MY_ANSIARGS((void));
/*******************************************************************/
void              EZ_InitializeWidgetHT MY_ANSIARGS((void));
void              EZ_RemoveWidgetFromMappedHT  MY_ANSIARGS((EZ_Widget *widget));
void              EZ_RemoveWidgetFromAllHT  MY_ANSIARGS((EZ_Widget *widget));
void              EZ_InsertWidgetToMappedHT  MY_ANSIARGS((EZ_Widget *widget));
void              EZ_InsertWidgetToAllHT  MY_ANSIARGS((EZ_Widget *widget));
EZ_Widget         *EZ_LookupWidgetFromMappedHT  MY_ANSIARGS((Window win));
EZ_Widget         *EZ_LookupWidgetFromAllHT  MY_ANSIARGS((EZ_Widget *widget));
EZ_Widget         *EZ_LookupWidgetFromAllHTUL  MY_ANSIARGS((unsigned long addr));

EZ_Widget         *EZ_WindowIsWidgetWindow  MY_ANSIARGS((Window window));
EZ_Widget         *EZ_WidgetExist  MY_ANSIARGS((EZ_Widget *widget));

int               EZ_HashString  MY_ANSIARGS((char *str));
EZ_Bitmap         *EZ_GetBitmapFromFile  MY_ANSIARGS((char *file, int ref));

EZ_Bitmap         *EZ_GetBitmapFromData  MY_ANSIARGS((char *data, unsigned int w, unsigned int h));
EZ_Bitmap         *EZ_GetPixmapFromData  MY_ANSIARGS((char  **data));
EZ_Bitmap         *EZ_GetPixmapFromRawRGB  MY_ANSIARGS((char  *data, int width, int height));
EZ_Bitmap         *EZ_GetPixmapFromPixmap  MY_ANSIARGS((Pixmap pix, int x, int y, int w, int h));
EZ_Bitmap         *EZ_GetImageFromFile  MY_ANSIARGS((char *file, int ref));
EZ_Bitmap         *EZ_GetAnyPixmapFromFile  MY_ANSIARGS((char *file));
char              *EZ_GetBitmapFileName  MY_ANSIARGS((EZ_Bitmap *bitmap));
void              EZ_FreeBitmap  MY_ANSIARGS((EZ_Bitmap *bitmap));

void              EZ_DestroyAllWidgets  MY_ANSIARGS((void));

/*********************************************************************
 *
 *  local functions.
 */
static  void  EZ_InitiailzeBitmapHT  MY_ANSIARGS((void));
static  int   EZ_WidgetHashWin  MY_ANSIARGS((Window win));
static  int   EZ_WidgetHashAddress  MY_ANSIARGS((unsigned long addr));
static  EZ_Bitmap *AllocateBitmapEntry  MY_ANSIARGS((int bucket, char *fname, int type,
						    Pixmap pixmap, Pixmap shape,
						    int w, int h, int ref, int savename));
/*********************************************************************
 *
 *  This is the hash table for widget windows. All created X windows
 *  are stored here.
 */
EZ_MappedWidgetHTEntry         EZ_MappedWidgetsHashTable[EZ_WIDGET_HASH_TABLE_SIZE]; /* for mapped widgets */
EZ_AllWidgetHTEntry            EZ_AllWidgetsHashTable[EZ_WIDGET_HASH_TABLE_SIZE];

static char *ezIconPath = NULL;

/**********************************************************************/
char *EZ_TildeExpandPath(pin) char *pin;
{
  int  length = 1024;
  if(pin)
    {
      char *ret = (char *) malloc(length * sizeof(char));
      char *p = pin, *q, *tilde;
      int  tlen = 0;
      ret[0] = '\0';
      while(p)
	{
	  q = strchr(p, ':');
	  if(q) { *q = 0; q++;}
	  tilde = EZ_TildeExpand(p);
	  if(tilde)
	    {
	      tlen += strlen(tilde);
	      if(tlen >= length)
		{
		  length *= 2;
		  ret = (char *)realloc(ret, length * sizeof(char));
		}
	      strcat(ret,tilde);
	      if(q)strcat(ret, ":");
	      free(tilde);
	    }
	  p = q;
	}
      return(ret);
    }
  return(NULL);
}
/**********************************************************************/
void EZ_SetIconPath(path) char *path;
{
  if(ezIconPath != NULL) (void)my_free(ezIconPath);
  ezIconPath = NULL;
  ezIconPath = EZ_TildeExpandPath(path);
}
char *EZ_GetIconPath MY_ANSIARGS((void))
{ return(ezIconPath);}
/**********************************************************************
 *
 *  Initialization.
 */
void  EZ_InitializeWidgetHT()
{
  register int i;
  for(i = 0; i < EZ_WIDGET_HASH_TABLE_SIZE; i++)
    {
      EZ_MappedWidgetsHashTable[i].next = (EZ_MappedWidgetHTEntry *)NULL;
      EZ_MappedWidgetsHashTable[i].widget = (EZ_Widget *)NULL;
      EZ_AllWidgetsHashTable[i].next = (EZ_AllWidgetHTEntry *)NULL;
      EZ_AllWidgetsHashTable[i].widget = (EZ_Widget *)NULL;
    }
  EZ_InitiailzeBitmapHT();
  ezIconPath = NULL;
}

/*************************************************************
 *
 *  Destroy all widgets. Have to destroy one widget a time
 *  since EZ_DestroyWidget modify the global hash table.
 */
void EZ_DestroyAllWidgets()
{
  int i, notdone = 1;
  EZ_AllWidgetHTEntry  *tmp;  
  
  while(notdone)
    {
      for(i = 0; i < EZ_WIDGET_HASH_TABLE_SIZE; i++)
	{
	  tmp = EZ_AllWidgetsHashTable[i].next;
	  if(tmp)
	    {
	      EZ_DestroyWidget(tmp->widget);
	      break;
	    }
	  else if(i == EZ_WIDGET_HASH_TABLE_SIZE -1) notdone = 0;
	}
    }
}
/*************************************************************
 *
 *  Extermely simple hash functions. (ID % EZ_WIDGET_HASH_TABLE_SIZE)
 */
static int EZ_WidgetHashAddress(widget)
     unsigned long widget;
{
  return( widget % EZ_WIDGET_HASH_TABLE_SIZE);
}
static int EZ_WidgetHashWin(win)
     Window win;
{
  unsigned long tmp1;

  tmp1 = (unsigned long) win;
  return( tmp1 % EZ_WIDGET_HASH_TABLE_SIZE);
}
/*************************************************************/
/*
 * Insert a widget into the hash table.
 */
void EZ_InsertWidgetToAllHT(widget)
     EZ_Widget *widget;
{
  EZ_AllWidgetHTEntry  *tmp;
  int                  hash_value;

  if(widget)
    {
      hash_value = EZ_WidgetHashAddress((unsigned long)widget);
      tmp = (EZ_AllWidgetHTEntry *)my_malloc(sizeof(EZ_AllWidgetHTEntry), _WIDGET_ALL_HT_ENTRY_);
      if(!tmp) EZ_OutOfMemory("EZ_InsertWidgetToAllHT");
      tmp->widget = widget;
      tmp->next = EZ_AllWidgetsHashTable[hash_value].next;
      EZ_AllWidgetsHashTable[hash_value].next = tmp;
    }
}

void EZ_InsertWidgetToMappedHT(widget)
     EZ_Widget *widget;
{
  EZ_MappedWidgetHTEntry *tmp;
  int                     hash_value;

  if(EZ_WidgetWindow(widget) == (Window )NULL) return;
  hash_value = EZ_WidgetHashWin(EZ_WidgetWindow(widget));
  
  tmp = (EZ_MappedWidgetHTEntry *)my_malloc(sizeof(EZ_MappedWidgetHTEntry),_WIDGET_MAPPED_HT_ENTRY_);
  if(!tmp) EZ_OutOfMemory("EZ_InsertWidgetToMappedHT");
  tmp->widget = widget;
  tmp->next = (EZ_MappedWidgetsHashTable[hash_value].next);
  EZ_MappedWidgetsHashTable[hash_value].next = tmp;
}

/*
 *  Lookup a wisget.
 */
EZ_Widget  *EZ_LookupWidgetFromAllHT(widget)
     EZ_Widget *widget;
{
  EZ_AllWidgetHTEntry *tmp;
  int                 hash_value;

  if(widget)
    {
      hash_value = EZ_WidgetHashAddress((unsigned long)widget);
      tmp = EZ_AllWidgetsHashTable[hash_value].next;
      while(tmp)
	{
	  if(tmp->widget == widget) return(widget);
	  tmp = tmp->next;
	}
    }
  return( (EZ_Widget *)NULL);
}

/* play safe. Lookup a widget when the ptr to widget is casted to a ulong */
EZ_Widget  *EZ_LookupWidgetFromAllHTUL(widgetaddr)
     unsigned long widgetaddr;
{
  EZ_AllWidgetHTEntry *tmp;
  int                 hash_value;

  if(widgetaddr)
    {
      hash_value = EZ_WidgetHashAddress((unsigned long)widgetaddr);
      tmp = EZ_AllWidgetsHashTable[hash_value].next;
      while(tmp)
	{
	  if((unsigned long)(tmp->widget) == widgetaddr) return(tmp->widget);
	  tmp = tmp->next;
	}
    }
  return( (EZ_Widget *)NULL);
}


EZ_Widget  *EZ_LookupWidgetFromMappedHT(win)
     Window  win;
{
  EZ_MappedWidgetHTEntry *tmp;
  int               hash_value;

  hash_value = EZ_WidgetHashWin(win);
  
  tmp = (EZ_MappedWidgetsHashTable[hash_value].next);
  while(tmp)
    {
      if(EZ_WidgetWindow(tmp->widget) == win)
	return(tmp->widget);
      tmp = tmp->next;
    }
  return( (EZ_Widget *)NULL);
}
/*
 * Remove an entry form HT.
 */
void  EZ_RemoveWidgetFromAllHT(widget)
     EZ_Widget *widget;
{
  EZ_AllWidgetHTEntry *tmp, *tmpa;
  int                  hash_value;

  if(widget)
    {
      hash_value = EZ_WidgetHashAddress((unsigned long)widget);
      tmp = &(EZ_AllWidgetsHashTable[hash_value]);
      while(tmp && tmp->next)
	{
	  if(tmp->next->widget == widget)
	    {
	      tmpa = tmp->next;
	      tmp->next = tmp->next->next;
	      (void)my_free( (char *)(tmpa));
	      return;
	    }
	  tmp = tmp->next;
	}
    }
}

void  EZ_RemoveWidgetFromMappedHT(widget)
     EZ_Widget *widget;
{
  EZ_MappedWidgetHTEntry *tmp, *tmpa;
  int               hash_value;

  hash_value = EZ_WidgetHashWin(EZ_WidgetWindow(widget));
  
  tmp = &(EZ_MappedWidgetsHashTable[hash_value]);
  while(tmp && tmp->next)
    {
      if(tmp->next->widget == widget)
	{
	  tmpa = tmp->next;
	  tmp->next = tmp->next->next;
	  (void)my_free( (char *)(tmpa));
	  return;
	}
      tmp = tmp->next;
    }
}

/*******************************************************************
 ***                                                             ***
 ***  Well, we maintain also another hash table for bitmaps.     ***
 ***                                                             ***
 *******************************************************************/

#define  EZ_PRIME  EZ_WIDGET_HASH_TABLE_SIZE

EZ_BitmapHTEntry  EZ_BitmapHashTable[EZ_PRIME+4];

/******************************************************************
 *
 *  Initialize the hash table.
 */

static void  EZ_InitiailzeBitmapHT()
{
  register int i;

  for(i = 0; i < EZ_PRIME + 4; i++)
    EZ_BitmapHashTable[i].next = (EZ_BitmapHTEntry *)NULL;
  /*
   * This last one is saved for drag and drop. It will be constantly
   * modified so it is hidden.
   */
  EZ_SnapShotBitmap = AllocateBitmapEntry(EZ_PRIME + 3,  (char *)NULL,  EZ_BITMAP_IS_PIXMAP,
					  (Pixmap)NULL, (Pixmap)NULL, 0, 0, 1, 0);
}
/******************************************************************
 *
 *  Given a file name, create a bitmap from data contained in file.
 */
EZ_Bitmap *EZ_GetBitmapFromFile(file_name, ref)
     char *file_name; int ref;  /* reference type 1 for widgets, 0 for text in textwidget*/
{
  int              hash_value;
  EZ_BitmapHTEntry *tmp;
  
  /*------------------------------
   * Check the hash table first.
   *-----------------------------*/
  hash_value = EZ_HashString(file_name);
  tmp = EZ_BitmapHashTable[hash_value].next;
  while(tmp != (EZ_BitmapHTEntry *)NULL)
    {
      if((tmp->name)[0] == file_name[0])
	{
	  if(!strcmp(tmp->name,file_name))
	    {
	      /* got it */
	      if(ref) tmp->ref  += 1;
	      else    tmp->special = 1;  /* used in TextWidget */
	      return(tmp);
	    }
	}
      tmp = tmp->next;
    }

  /*-------------------------------------
   * so we don't have it already,
   * create a new HT entry if we can
   * create a bitmap from file.
   *------------------------------------*/
  {
    Pixmap pixmap = (Pixmap )NULL;
    Pixmap shape_mask = (Pixmap )NULL;
    char   *file = file_name;
    char   tmp_name[512], path[1024];
    char   filename[256];
    int    file_ok = EZ_FileReadable(file);

    if(file_ok == 0)
      {
	/*----------------------------------------
	 * file is not in the current directory.
	 * check $EZ_LIBDIR
	 *---------------------------------------*/
	char *p,*tmp = getenv("EZ_LIBDIR");
	if(ezIconPath != NULL)
	  {
	    sprintf(path, "%s:%s", ezIconPath, tmp);
	    tmp = path;
	  }
	if(tmp != (char *)NULL)
	  {
	    tmp = strcpy(tmp_name, tmp);
	    while(tmp)
	      {
		int len;
		p = strchr(tmp, ':');
		if(p) *p++ = '\0';
		strcpy(filename, tmp);
		len = strlen(filename);
		if(filename[len-1] !='/')
		  {
		    filename[len] = '/';
		    filename[len+1] = '\0';
		  }
		(void) strcat(filename, file_name);
		file_ok = EZ_FileReadable(filename);
		file = filename;
		if(file_ok) break;
		tmp = p;
	      }
	  }
      }
    /*-----------------------------------
     * Still not found,
     * check  "/usr/include/X11/bitmaps/"
     * and    "/usr/include/X11/pixmaps/"
     *----------------------------------*/
    if(file_ok == 0)
      {
	(void)strcpy(tmp_name, STANDARD_BITMAP_INCLUDE);
	(void)strcat(tmp_name, file_name);
	file_ok = EZ_FileReadable(tmp_name);
	if(file_ok == 0)
	  {
	    (void)strcpy(tmp_name, STANDARD_PIXMAP_INCLUDE);
	    (void)strcat(tmp_name, file_name);
	    file_ok = EZ_FileReadable(tmp_name);
	  }
	file = tmp_name;
      }

    if(file_ok)
      {
	unsigned int width, height;
	int      dummyx, dummyy, created = 0;
	if(XReadBitmapFile(EZ_DisplayForWidgets,
			   RootWindow(EZ_DisplayForWidgets, EZ_ScreenNumForWidgets),
			   file,
			   &width,
			   &height,
			   &pixmap,
			   &dummyx,
			   &dummyy) == BitmapSuccess)
	  created = 1;
	else
	  {
	    if(EZ_CreateXPixmapFromXpmFile(file, &width, &height, 
				       &pixmap,&shape_mask))
	      created = 2;
	  }
	if(created)
	  return(AllocateBitmapEntry(hash_value, file_name,
				     (created == 1? EZ_BITMAP_IS_BITMAP : EZ_BITMAP_IS_PIXMAP),
				     pixmap, shape_mask, width, height, ref, 1));
      }
  }
  return((EZ_Bitmap *)NULL);
}

/******************************************************************
 *
 *  Create a bitmap from pixmap data
 */
EZ_Bitmap *EZ_GetBitmapFromData(data, width, height)
     char          *data;
     unsigned int  width, height;
{
  EZ_BitmapHTEntry *tmp;
  Pixmap pixmap = (Pixmap )NULL;  

  /*----------------------------------------------------------------
   * Bitmap created from bitmap data are saved in table[EZ_PRIME+1]
   *---------------------------------------------------------------*/
  tmp = EZ_BitmapHashTable[EZ_PRIME+1].next;
  while(tmp != (EZ_BitmapHTEntry *)NULL)
    {
      if(tmp->name == data)
	{
	  tmp->ref  += 1;
	  return(tmp);
	}
      tmp = tmp->next;
    }
  /*-------------------------------------
   * so we don't have it
   *------------------------------------*/
  if((pixmap = XCreateBitmapFromData(EZ_Display,
				     RootWindow(EZ_Display, EZ_ScreenNum),
				     data,
				     width, height)) != None)
    return(AllocateBitmapEntry(EZ_PRIME+1, data, EZ_BITMAP_IS_BITMAP,
			       pixmap, (Pixmap)NULL, width, height, 1, 1));
  return((EZ_Bitmap *)NULL);
}
/******************************************************************
 *
 *  Create a pixmap from pixmap data
 */
EZ_Bitmap *EZ_GetPixmapFromData(data)
     char **data;
{
  EZ_BitmapHTEntry *tmp;
  
  /*-------------------------------------------------------
   * Bitmap created from data are saved in table[EZ_PRIME]
   *------------------------------------------------------*/
  tmp = EZ_BitmapHashTable[EZ_PRIME].next;
  while(tmp != (EZ_BitmapHTEntry *)NULL)
    {
      if((char **)(tmp->name) == data)
	{
	  tmp->ref  += 1;
	  return(tmp);
	}
      tmp = tmp->next;
    }
  /*-------------------------------------
   * so we don't have it already,
   * create a new HT entry
   *------------------------------------*/
  {
    Pixmap pixmap = (Pixmap )NULL;
    Pixmap shape_mask = (Pixmap )NULL;
    unsigned int width=0, height=0;
    
    if(EZ_CreateXPixmapFromXpmData(data, &width, &height, &pixmap,&shape_mask))
      return(AllocateBitmapEntry(EZ_PRIME, (char *)data, EZ_BITMAP_IS_PIXMAP,
				 pixmap, shape_mask, width, height, 1, 0));
  }
  return((EZ_Bitmap *)NULL);
}


/******************************************************************
 *
 *  Create a pixmap from raw rgb data
 *  Arno Dabekaussen, 04-05-97, Maastricht, NL.
 *
 */

EZ_Bitmap *EZ_GetPixmapFromRawRGB(data, width, height)
    char *data;
    int width;
    int height;
{
  EZ_BitmapHTEntry *tmp;
  
  /*-------------------------------------------------------
   * Bitmap created from data are saved in table[EZ_PRIME]
   *------------------------------------------------------*/

  tmp = EZ_BitmapHashTable[EZ_PRIME].next;

  while(tmp != (EZ_BitmapHTEntry *)NULL)
    {
      if((char *)(tmp->name) == data)
	{
	  tmp->ref  += 1;

	  /*
	   * Bug found:
	   * What happens if a bitmap was found in hash table but
	   * the size has been changed ? Maybe better to free it, 
	   * so that a new one can be allocated. Now it is not possible to 
	   * call ConfigureWidget several times with an identical start
	   * pointer to new bitmap data (with different sizes).
	   *
	   * return(tmp);
	   *
	   */
	  /* Sorry arno, I take this off.
	   * If one wants to manipulate images, he/she should
	   * explicitly recreate the image. 
	   *
	   * EZ_FreeBitmap(tmp);
	   * break;
	   */
	  return(tmp);	  
	}
      tmp = tmp->next;
    }

  /*-----------------------------------------
   * so we don't have it already or freed it,
   * create a new HT entry
   *----------------------------------------*/

  {
    Pixmap pixmap = (Pixmap ) NULL;
    Pixmap shape_mask = (Pixmap )NULL;

    
    if(EZ_CreateXPixmapFromRawRGB(data, width, height, &pixmap))
      return(AllocateBitmapEntry(EZ_PRIME, data, EZ_BITMAP_IS_PIXMAP,
				 pixmap, shape_mask, width, height, 1, 0));
  }

  return((EZ_Bitmap *) NULL);
}





EZ_Bitmap  *EZ_GetPixmapFromPixmap(src,x,y,w,h)
     Pixmap src;
     int    x,y,w,h;
{
  EZ_BitmapHTEntry *tmp;
  
  /*-------------------------------------------------------
   * Bitmap created from data are saved in table[EZ_PRIME+2]
   *------------------------------------------------------*/
  tmp = EZ_BitmapHashTable[EZ_PRIME+2].next;
  while(tmp != (EZ_BitmapHTEntry *)NULL)
    {
      if((Pixmap)(tmp->name) == src &&
	 tmp->width == w && tmp->height == h &&
	 tmp->x == x && tmp->y == y)
	{
	  tmp->ref  += 1;
	  return(tmp);
	}
      tmp = tmp->next;
    }
  /*-------------------------------------
   * so we don't have it already,
   * create a new HT entry
   *------------------------------------*/
  tmp = NULL;
  if(src && w > 0 && h > 0 && x >= 0 && y >= 0)
    {
      Window    win = EZ_DummyWindow;
      Pixmap pixmap;
      
      pixmap = XCreatePixmap(EZ_Display, win, w, h, EZ_Depth);
      XCopyArea(EZ_Display,src,pixmap,EZ_WRITABLEGC,x,y,w,h,0,0);
      tmp = AllocateBitmapEntry(EZ_PRIME+2, (char *)src, EZ_BITMAP_IS_PIXMAP,
				pixmap, (Pixmap)NULL, w, h, 1, 0);
      if(tmp) {	tmp->x = x; tmp->y = y;}
    }
  return(tmp);
}

/*******************************************************************
 *
 *   Free a bitmap entry.
 */
void EZ_FreeBitmap(bitmap)
     EZ_Bitmap *bitmap;
{
  int bucket; 
  if(bitmap == (EZ_Bitmap *)NULL) return;

  bucket = bitmap->bucket; 
  bitmap->ref -= 1;
  if(bitmap->ref <= 0 && bitmap->special == 0)
    { 
      EZ_Bitmap *tmp,*prev = EZ_BitmapHashTable + bucket;
      while(prev->next != bitmap)
	prev = prev->next;
      tmp = prev->next;
      prev->next = tmp->next;
      if(bucket < EZ_PRIME) (void)my_free(tmp->name); /* !!!!!!! */
      if(tmp->pixmap != (Pixmap )NULL)
	XFreePixmap(EZ_Display, tmp->pixmap);
      if(tmp->shape != (Pixmap )NULL)
	XFreePixmap(EZ_Display, tmp->shape);
      (void)my_free( (char *)tmp);
    }
}

/*
 * free the bitmap hash table.  EZ_DestroyAllWidget should
 * take care of freeing this table. However, user may use
 * EZ_CreateLabelBitmapFromm*** without freeing them. And
 * the last entry is not freed.
 */
void EZ_DestroyAllBitmaps()
{
  int i, notdone;
  EZ_BitmapHTEntry *tmp;
  
  for(i = 0; i < EZ_PRIME + 4; i++)
    {
      notdone = 1;
      while(notdone)
	{
	  tmp = EZ_BitmapHashTable[i].next;
	  if(tmp)
	    {
	      tmp->ref = 0; tmp->special = 0;
	      EZ_FreeBitmap(tmp);
	    }
	  else notdone = 0;
	}
    }
}
/******************************************************************
 *
 *  Retrieve the bitmap file name for a given bitmap.
 */
char *EZ_GetBitmapFileName(bitmap)
     EZ_Bitmap *bitmap;
{
  if(bitmap)  return(bitmap->name);
  return(NULL);
}
/*******************************************************************/
int EZ_HashString(s)
     char *s;
{
  char *p;
  unsigned long h = 0, g;
  
  for(p = s; *p ; p++) 
    {
      h = (h << 4) + (*p);
      if((g = h & 0xf0000000))
        {
          h = h ^ (g >> 24);
          h = h ^ g;
        }
    }
  return((int) (h % EZ_PRIME));
}
/******************************************************************/

EZ_Bitmap *EZ_GetImageFromFile(file_name, ref)
     char *file_name; int ref;
{
  int              hash_value;
  EZ_BitmapHTEntry *tmp;
  
  /*------------------------------
   * Check the hash table first.
   *-----------------------------*/
  hash_value = EZ_HashString(file_name);
  tmp = EZ_BitmapHashTable[hash_value].next;
  while(tmp != (EZ_BitmapHTEntry *)NULL)
    {
      if((tmp->name)[0] == file_name[0])
	{
	  if(!strcmp(tmp->name,file_name))
	    {
	      /* got it */
	      if(ref) tmp->ref  += 1;
	      else tmp->special = 1;
	      return(tmp);
	    }
	}
      tmp = tmp->next;
    }

  /*-------------------------------------
   * so we don't have it
   *------------------------------------*/
  {
    Pixmap pixmap = (Pixmap )NULL;
    char   *p, *file = file_name;
    char   tmp_name[1024], path[1024];
    char   filename[256];
    int    file_ok = EZ_FileReadable(file);

    if(file_ok == 0)
      {
	/*----------------------------------------
	 * file not found, check $EZ_LIBDIR
	 *---------------------------------------*/
	char *tmp = getenv("EZ_LIBDIR");
	if(ezIconPath != NULL)
	  {
	    sprintf(path, "%s:%s", ezIconPath, tmp);
	    tmp = path;
	  }
	if(tmp != (char *)NULL)
	  {
	    tmp = strcpy(tmp_name, tmp);
	    while(tmp)
	      {
		int len;
		p = strchr(tmp, ':');
		if(p) *p++ = '\0';
		strcpy(filename, tmp);
		len = strlen(filename);
		if(filename[len-1] !='/')
		  {
		    filename[len] = '/';
		    filename[len+1] = '\0';
		  }
		(void) strcat(filename, file_name);
		file_ok = EZ_FileReadable(filename);
		file = filename;
		if(file_ok) break;
		tmp = p;
	      }
	  }
      }
    if(file_ok)
      {
	int width, height,ans;
	ans = EZ_CreateXPixmapFromImageFile(file,&width, &height, &pixmap);
	if(ans != 0)
	  return( AllocateBitmapEntry(hash_value, file_name, EZ_BITMAP_IS_PIXMAP,
				      pixmap, (Pixmap)NULL, width, height, ref, 1));
      }
  }
  return((EZ_Bitmap *)NULL);
}
/*************************************************************************************/
static EZ_Bitmap *AllocateBitmapEntry(bucket, fname, type, pixmap, shape_mask, width,  
				      height, ref_type,savefname)
     int     bucket, width, height, type, ref_type, savefname;
     Pixmap  pixmap, shape_mask;
     char    *fname;
{
  EZ_Bitmap *tmp = EZ_BitmapHashTable[bucket].next;
  EZ_Bitmap *new = (EZ_BitmapHTEntry *)my_malloc(sizeof(EZ_BitmapHTEntry), _BITMAP_HT_ENTRY_);
  if(!new) EZ_OutOfMemory("AllocateBitmapEntry");
  if(savefname)
    {
      new->name = (char *)my_malloc( (1+strlen(fname)) * sizeof(char), _BITMAP_NAME_);
      if(!new->name) EZ_OutOfMemory("AllocateBitmapEntry");      
      (void)strcpy(new->name, fname);
    }
  else new->name = fname;

  if(ref_type) { new->ref = 1; new->special = 0; }
  else  { new->ref = 0; new->special = 1;}
  new->type = type;
  new->width = width;
  new->height = height;
  new->x = 0;
  new->y = 0;
  new->bucket = bucket;
  new->next = tmp;
  new->pixmap = pixmap;
  new->shape = shape_mask;
  EZ_BitmapHashTable[bucket].next = new;
  return(new);
}
/*************************************************************************************/
EZ_Bitmap *EZ_GetAnyPixmapFromFile(file)
     char *file;
{
  EZ_Bitmap *bitmap = EZ_GetBitmapFromFile(file, 0);
  if(bitmap == NULL) bitmap = EZ_GetImageFromFile(file, 0);
  return(bitmap);
}
/*************************************************************************************
 *
 *       Addons ...
 *
 *************************************************************************************/
void  EZ_FreeXPixmap(pixmap)
     Pixmap pixmap;
{
  if(pixmap) XFreePixmap(EZ_Display, pixmap);
}

/*************************************************************************************/
void   EZ_FreeLabelPixmap(pixlabel)
     EZ_Bitmap *pixlabel;
{
  if(pixlabel) EZ_FreeBitmap(pixlabel);
}
/*************************************************************************************/
EZ_Bitmap  *EZ_CreateLabelPixmapFromXpmFile(file)
     char *file;
{
  return(EZ_GetBitmapFromFile(file, 1));
}
EZ_Bitmap  *EZ_CreateLabelPixmapFromXBitmapFile(file)
     char *file;
{
  return(EZ_GetBitmapFromFile(file, 1));
}
/*************************************************************************************/
EZ_Bitmap  *EZ_CreateLabelPixmapFromXBitmapData(data, w, h)
     char *data; unsigned int w, h;
{
  return(EZ_GetBitmapFromData(data, w, h));
}

/*****************************************************************************/

/*
 * Allows labels to consist of raw rgb data, to avoid complicated xpm
 * handling.
 * Arno Dabekaussen, 04-05-97, Maastricht, NL.
 */

EZ_Bitmap  *EZ_CreateLabelPixmapFromRawRGB(data, width, height)
     char *data;
     int  width;
     int  height;
{
  return(EZ_GetPixmapFromRawRGB(data, width, height));
}


/*************************************************************************************/
EZ_Bitmap  *EZ_CreateLabelPixmapFromXpmData(data)
     char **data;
{
  return(EZ_GetPixmapFromData(data));
}
/*************************************************************************************/
EZ_Bitmap  *EZ_CreateLabelPixmapFromImageFile(file)
     char *file;
{
  return(EZ_GetImageFromFile(file, 1));
}
/*************************************************************************************/
EZ_Widget  *EZ_WindowIsWidgetWindow(window)
     Window window;
{
  return(EZ_LookupWidgetFromMappedHT(window));
}
EZ_Widget  *EZ_WidgetExist(widget)
     EZ_Widget *widget;
{
  return(EZ_LookupWidgetFromAllHT(widget));
}
/*************************************************************************************/
int EZ_GetLabelPixmapInfo(bitmap, p_ret, s_ret, w_ret, h_ret)
     EZ_Bitmap *bitmap;
     Pixmap *p_ret, *s_ret;
     int *w_ret, *h_ret;
{
  int  i;
  EZ_BitmapHTEntry *tmp;
  
  for(i = 0; i < EZ_PRIME+4; i++)
    {
      tmp = EZ_BitmapHashTable[i].next;
      while(tmp != (EZ_BitmapHTEntry *)NULL)
	{
	  if(tmp == bitmap)
	    {
	      if(p_ret) *p_ret = bitmap->pixmap;
	      if(s_ret) *s_ret = bitmap->shape;
	      if(w_ret) *w_ret = bitmap->width;
	      if(h_ret) *h_ret = bitmap->height;
	      if(bitmap->type == EZ_BITMAP_IS_BITMAP) return(1);
	      return(EZ_Depth);
	    }
	  tmp = tmp->next;
	}
    }
  return(0);
}
/*************************************************************************************/

#ifdef EZ_DEBUG 
void EZ_DumpWidgetHashTable()
{
  printf("========Mapped Widget Hash Tabble=========\n");
  {
    register int i;

    EZ_MappedWidgetHTEntry  *tmp;
    for(i = 0; i < EZ_WIDGET_HASH_TABLE_SIZE; i++)
      {
	tmp = EZ_MappedWidgetsHashTable[i].next;
	if(tmp)
	  {
	    printf("%d: ", i);
	    while(tmp)
	      {
		printf(" --> %lx == %lx ==> %s",(unsigned long)tmp->widget,
		       (EZ_WidgetWindow(tmp->widget)),
		       EZ_WidgetDefaultClassNames[(int)EZ_WidgetType(tmp->widget)]);
		tmp = tmp->next;
	      }
	    printf("\n");
	  }
      }
  }
  printf("======All Widgets Hash Tabble========\n");
  {
    register int i;
    EZ_AllWidgetHTEntry  *tmp;

    for(i = 0; i < EZ_WIDGET_HASH_TABLE_SIZE; i++)
      {
	tmp = EZ_AllWidgetsHashTable[i].next;
	if(tmp)
	  {
	    printf("%d: ", i);
	    while(tmp)
	      {
		printf(" --> %lx=>%s", (unsigned long)tmp->widget,
		       EZ_WidgetDefaultClassNames[(int)EZ_WidgetType(tmp->widget)]);
		tmp = tmp->next;
	      }
	    printf("\n");
	  }
      }
  }

  printf("======= BitmapHashTable ========\n");
  {
    int i;
    EZ_BitmapHTEntry *tmp;
  
    for(i = 0; i < EZ_PRIME+4; i++)
      {
	tmp = EZ_BitmapHashTable[i].next;
	while(tmp != (EZ_BitmapHTEntry *)NULL)
	  {
	    if(i < EZ_PRIME)     printf("%s ", tmp->name);
	    else    printf("%lx ", (unsigned long)tmp->name);
	    printf(" Ref=%d Special=%d\n", tmp->ref,tmp->special);
	    tmp = tmp->next;
	  }
      }
  }
}
#endif
#undef  EZ_PRIME
#undef _EZ_WIDGET_HASH_C_
