/*********************************************************************
 *
 *            EZFM---EZWGL based file manager for X11
 *
 *             Copyright (C) 1998  Maorong Zou
 *
 *
 *  This file is part of EZFM.
 *
 *  EZFM is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * EZFM 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with EZFM; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 *************************************************************************/

#define _FOLDER_C_
#include "ezfm.h"

/*************************************************************
 *
 * public functions
 */
void     OpenFolder MY_ANSIARGS ((char *pathname, Folder *folder, int dp, int type));
void     updateFolder  MY_ANSIARGS ((Folder *folder, int flag));
Folder   *findFolder MY_ANSIARGS ((char *pathname));
EZ_Item  *getFolderSelection MY_ANSIARGS ((Folder *folder));
Folder   *createNewFolder MY_ANSIARGS((char *pathname, Toplevel *tp, int where, int type));
int      countNFolders  MY_ANSIARGS ((void));
void     BroadcastFolderOpenCloseded MY_ANSIARGS((char *pathname, int mode));
void     OpenCloseDirItemInFolder MY_ANSIARGS((char *pathname, int mode));
void     findOpenedFolderOtherClients MY_ANSIARGS((char *pathname, struct stat  *stat_buf));
int      entryDirNameDecoder MY_ANSIARGS ((void *obj, void *data, char *msg, int len));
int      isToplevel MY_ANSIARGS ((void *ptr));
int      folderExists  MY_ANSIARGS ((Folder *folder));
void     entryCanonicalString MY_ANSIARGS ((EZ_Widget *obj, void *data));
Folder   *getFolderList MY_ANSIARGS((void));
void     setToplevelName MY_ANSIARGS(( Toplevel *tp));
EZ_Widget *makeToolBar MY_ANSIARGS ((Toplevel *tp));
void      ezfmResetAllBgPixmaps MY_ANSIARGS ((void));
void      ConfigureNotifyHandler MY_ANSIARGS((EZ_Widget *widget, void *data, int etype, XEvent *xev));
void      popupRenameEntry MY_ANSIARGS((EZ_Widget *widget, int x, int y, int w, int h,
                                        void *obj, int kind));
void      ezfmSetFolderSorter MY_ANSIARGS((Folder *folder, int sorter));
/*************************************************************
 *
 * private functions
 */
static void toplevelDestroyCallback MY_ANSIARGS ((EZ_Widget *widget, void *data));
static void folderDestroyCallback MY_ANSIARGS ((EZ_Widget *widget, void *data));

static Toplevel *createNewToplevel MY_ANSIARGS ((void));
static void     createFolderFolder MY_ANSIARGS ((Folder *f, int type));

static void      entryCallback MY_ANSIARGS ((EZ_Widget *obj, void *data));
static void      rbtnCallback  MY_ANSIARGS ((EZ_Widget *obj, void *data));
static void      folderMotionCallback  MY_ANSIARGS ((EZ_Widget *obj, void *data));
static void      showSelectionStatus MY_ANSIARGS ((Folder *folder));
static EZ_TreeNode *myFileNodeCreator MY_ANSIARGS ((char *path, void *data));
static void      FindFolderOtherClients MY_ANSIARGS ((char *pathname));

static void   waFolderEHandler MY_ANSIARGS((EZ_Widget *w, void *data, int et, XEvent *xevent));
static void   flFolderEHandler MY_ANSIARGS((EZ_Widget *w, void *data, int et, XEvent *xevent));
static void   ltFolderEHandler MY_ANSIARGS((EZ_Widget *w, void *data, int et, XEvent *xevent));
static void   updateTreeNode   MY_ANSIARGS((EZ_TreeNode *node));
static void   mBarEHandler MY_ANSIARGS((EZ_Widget *w, void *data, int et, XEvent *xevent));
static void   startXtermHere  MY_ANSIARGS ((EZ_Widget *widget, void *data));
static void   openToolBox     MY_ANSIARGS ((EZ_Widget *widget, void *data));
static void   renameEntryCb   MY_ANSIARGS ((EZ_Widget *widget, void *data));
static void   renameEntryEHandler MY_ANSIARGS((EZ_Widget *w, void *data, int et, XEvent *xevent));
/*************************************************************/
static void menuBarEHandler  MY_ANSIARGS((EZ_Widget *w, void *data, int et, XEvent *xevent));
static void toolBarEHandler  MY_ANSIARGS((EZ_Widget *w, void *data, int et, XEvent *xevent));
static void postDockingMenu  MY_ANSIARGS((EZ_Widget *w));
/*************************************************************/
static void sortIconFolder MY_ANSIARGS((EZ_Widget *c, int sorter, int glob, int ch));
static void sortListFolder MY_ANSIARGS((EZ_Widget *c, int sorter, int glob, int ch));
static void sortTreeFolder MY_ANSIARGS((EZ_Widget *c, int sorter, int glob, int ch));
static int  findNameInArray MY_ANSIARGS((char *name, char **array, int count)); 
/*************************************************************
 *
 * The list of opened folders. We track them b/c we don't
 * want to open a directory in two toplevel windows.
 */
static Folder       *folderList = NULL;  
static EZ_Widget    *toolBarMenu = NULL;
/*************************************************************
 *
 * Update a folder. 
 * uflag:   0   folder is new
 *         !=0  update an existing folder
 */
void updateFolder(folder, uflag)
     Folder *folder; int uflag; 
{
  time_t       mtime; 
  int          dirty = 0, status, viewable;
  int          newdir = 0, glob = 0, setname = 0, sorter = 0;
  int          fdrtype, reallyUpdated = 0, sorterChanged;
  FileInfo     *finfo;
  struct stat  statbuf;
  Toplevel     *tp;
  EZ_Widget *toplevel, *optEntry, *statuslabel, *container;
  char      statusString[256];

  if(folder->blocked) return;  /* waiting for dnd to complete */
  finfo = folder->finfo;
  fdrtype = folder->type;
  switch(fdrtype)
    {
    case ICON_FOLDER:       container = folder->workarea;  break;
    case ICON_FOLDER_SMALL: container = folder->workareaS; break;
    case LIST_FOLDER:       container = folder->flistbox;  break;
    case TREE_FOLDER:       container = folder->listtree;  break;
    default:                container = NULL;              break;
    }

  mtime = finfo->mtime;
  if( (mtime == 0) || (uflag == 0)) newdir = 1;
  if( newdir != 0 ||  uflag > 10) dirty += 100;
  
  tp = folder->toplevel;
  toplevel= EZ_GetToplevelWidget(folder->frame);
  optEntry = folder->optentry;
  statuslabel = tp->statuslabel;

  if(finfo->glob == 0)
    {
      if((status = stat(finfo->pathname, &statbuf)) < 0 || !S_ISDIR(statbuf.st_mode))
	{
	  switch(fdrtype)
	    {
	    case ICON_FOLDER:         EZ_WorkAreaClear(container); break;
	    case ICON_FOLDER_SMALL:   EZ_WorkAreaClear(container); break;
	    case LIST_FOLDER:         EZ_FancyListBoxClear(container); break;
	    case TREE_FOLDER:         EZ_SetListTreeWidgetTree(container, NULL); break;
	    default: break;
	    }
	  return;
	}

      if(statbuf.st_ctime == 0) statbuf.st_ctime = 1; /* it happens !! */
      if(statbuf.st_ctime != mtime)
	{
	  finfo->mtime = statbuf.st_ctime;
	  dirty++;
	}
    }
  else /* globing */
    {
      finfo->mtime += 1;
      glob = 1;
      if(finfo->mtime > 5 || uflag > 10) dirty++;
      if(dirty) finfo->mtime  = 1;
    }
  /* update dirname in entry */
  {
    EZ_Widget *entry, *junk;    
    EZ_GetOptionalEntryWidgetComponents(optEntry, &entry, &junk, &junk);
    if(EZ_GetFocus() != entry)
      {
	char *ptr = EZ_GetEntryString(entry);
	if(ptr && strcmp(ptr, finfo->pathname))
	  {
	    EZ_SetOptionalEntryString(optEntry, finfo->pathname); 
	    setname = 1;
	  }
	/* insert pathname into the history listbox */
      }
  }
  viewable = EZ_WidgetIsViewable(toplevel);
  sorter = folder->flags & SORT_BY_BITS;
  sorterChanged = folder->flags & SORTER_CHANGED;
  folder->flags &= ~SORTER_CHANGED;
  
  if(dirty) 
    { /* need updating */
      int           count = 0, dirlength = -1, showhidden, oldShowHidden;
      DIR           *dirptr;
      struct dirent *dent;
      char          *fnames[1024];      
      FileInfo      *dirFinfo = folder->finfo;
      char          *dirpath = dirFinfo->pathname;
      
      showhidden = folder->flags & SHOW_HIDDEN_BIT;
      /* Open dir and read in all entries. This is needed for
       *    iconFolder and listFolder. 
       */
      if(fdrtype == ICON_FOLDER || fdrtype == LIST_FOLDER || fdrtype == ICON_FOLDER_SMALL)
	{
	  if(glob == 0) /* just read the contents of dir */
	    {
	      dirlength = strlen(dirpath);
	      dirlength = (dirlength > 1? dirlength+1 : 1); /* crazy / */
	      
	      if( (dirptr = opendir(dirpath)) != NULL)
		{
		  while( (dent = readdir(dirptr)) != NULL && count < 1024)
		    {
		      char   *d_name = dent->d_name;
		      int    len;
		      
                      if(d_name[0]=='.')
                        {
                          if(showhidden == 0) continue;
                          else if(d_name[1]=='\0' || (d_name[1]== '.' && d_name[2]=='\0')) 
                            continue; /* self or  parent */
                        }
		      len = strlen(d_name);
		      fnames[count] = (char *)EZ_Malloc((len+1)*sizeof(char));
		      strcpy(fnames[count], d_name);
		      count++;
		    }
		  if(count) qsort(fnames, count, sizeof(char *), EZ_CmpStr);
		  closedir(dirptr);
		}
	    }
	  else /* glob files */
	    {
	      char pattern[1024], cpy[1024], tdir_pat[1024];
	      char *patterns[16], *cdir_save = NULL, **cdir = &cdir_save;
	      char *pat = dirpath;
	      int  ii, npatterns, position;
	      char **dirlist;

	      (void)strcpy(cpy, pat);
	      npatterns = EZ_CountSetFilePatterns(cpy, patterns);

	      if(npatterns > 1) /* find the longest common ancestor */
		{
		  int i, j, k;
		  for(i = 0; i < npatterns && i < 16; i++)
		    {
		      (void) strcpy(pattern, patterns[i]);
		      position = EZ_ProcessFileSelectorPattern(cdir, pattern);
		      if(i == 0) { strcpy(tdir_pat, *cdir); dirlength = position;}
		      else
			{
			  char *p, *q;
			  p = *cdir;
			  q = tdir_pat;
			  j = 0; k = 0;
			  while(*p && *q && *p == *q)
			    {
			      j++;
			      if(*p == '/') k = j;
			      p++; q++;
			    }
			  *q = 0;
			  dirlength = k;
			}
		    }
		}
	      /* glob files */
	      oldShowHidden = EZ_GlobHiddenFiles(showhidden);
	      for(ii = 0; ii < npatterns && ii < 16; ii++)
		{
		  (void) strcpy(pattern, patterns[ii]);
      		  position = EZ_ProcessFileSelectorPattern(cdir, pattern);
		  if(dirlength < 0) dirlength = position;
		  if(dirlength > 0) (*cdir)[dirlength] = 0;
		  dirlist = (char **) EZ_GlobFileName(pattern);
		  if(dirlist)
		    {
		      int j = 0; 
		      while(dirlist[j] != NULL)
			{
			  if(count < 1024) fnames[count++] = dirlist[j++];
			  else (void) EZ_Free(dirlist[j++]);
			}
		    }
		  (void)free((char *)dirlist);  /* not allocated by my_malloc */
		}
	      EZ_GlobHiddenFiles(oldShowHidden);
	      if(cdir_save != NULL) EZ_Free(cdir_save);
	      if(count)  qsort(fnames, count, sizeof(char *), EZ_CmpStr);
            }
        }
      
      /* freeze the toplevel window if viewable */
      if(viewable)
	{
	  if(dirty >= 100) EZ_WaitCursor(toplevel, EZ_GetCursor(EZ_C_WATCH));
	  EZ_FreezeWidget(container);	  
	}
      
      /* do the work, update folder */
      if(fdrtype == ICON_FOLDER || fdrtype == ICON_FOLDER_SMALL)
	{
	  char      *ctmp, buf[1024];
	  EZ_Widget *workarea = container;
	  int       i, icount;

	  if(newdir) /* if new dir, rebuild */
	    {
	      EZ_WorkAreaClear(workarea);
	      icount = 0;
	    }
	  else icount = EZ_GetWorkAreaNumberOfItems(workarea);
	  
	  if(icount == 0) /* new dir */
	    {
	      EZ_Item       **items;
	      char          *p;

              reallyUpdated = 1;
	      items = (EZ_Item **)EZ_Malloc( (count+1) * sizeof(EZ_Item *));
	      if(glob == 0)
		{
		  /* parent dir */
		  strcpy(buf, dirpath);
		  p = strrchr(buf, '/');
		  if(p) *p = '\0';
		  if(buf[0] == '\0') { buf[0] = '/'; buf[1] = '\0'; }
		  items[0] = createFileItem(buf, "..", folder, NULL); 
		}
	      /* files in dir */
	      for(i = 0; i < count; i++)
		{
		  if(glob == 0)
		    {
		      sprintf(buf,"%s%s%s\0", dirpath, (dirpath[1] == '\0' ? "" : "/"), fnames[i]);
		      items[i+1] = createFileItem(buf, fnames[i], folder, NULL);
		    }
		  else
		    {
		      items[i] = createFileItem(fnames[i], fnames[i]+dirlength, folder, NULL); 
		    }
		  (void)EZ_Free((void *)fnames[i]);
		  /* */
		  if(i & 8)
		    {
		      sprintf(statusString, "Made %d items ...", i);
		      EZ_ConfigureWidget(statuslabel, EZ_LABEL_STRING, statusString, NULL);
		      XSync(EZ_GetDisplay(), False);
		    }
		  /* */
		}
	      EZ_WorkAreaInsertItems(workarea, items, count+(glob == 0 ? 1: 0));
	      (void)EZ_Free((void *)items);
	    }
	  else if(sorter == 0 && sorterChanged == 0) /* updating an existing folder */
	    {
	      EZ_Item  **oitems, *item, *nitem;
	      char     *oname; 
	      int      indices[1024];
	      FileInfo *ifinfo;
	      int      i,j,k,l, cnt, cmp, update, offset;
	      
	      if(glob) offset = 0; else offset = dirlength;
	      oitems = EZ_GetWorkAreaData(workarea);
	      update = (uflag > 10);
	      /* 1: delete items correspond to deleted files */
	      cnt = 0; 
	      i = (glob == 0)? 1:0;   /* parent dir is at location 0 */
	      j = 0;
	      while(i < icount)
		{
		  if(j < count)
		    {
		      item = oitems[i];
		      ifinfo = (FileInfo *)EZ_GetItemPtrData(item);
		      oname = ifinfo->pathname;
		      cmp = strcmp(oname+offset, fnames[j]);
		    }
		  else { cmp = -1;}
		  
		  if(cmp == 0) /* match */
		    {
		      int up2date = 1;
		      if(update)
			{
			  struct stat fstatbuf;
			  int status = lstat(oname, &fstatbuf);
			  time_t cmtime = (status == 0? fstatbuf.st_ctime: 0);
			  if(cmtime != ifinfo->mtime) /* item is outdated */
			    {
			      indices[cnt++] = i;
			      up2date = 0;
			    }
			}
		      if(up2date)
			{
			  (void)EZ_Free((char *)fnames[j]);
			  fnames[j] = NULL;
			}
		      i++; j++;
		    }
		  else if(cmp < 0) /* delete item */
		    {
		      indices[cnt++] = i;
		      i++;
		    }
		  else
		    {
		      j++;
		      while( j < count && strcmp(oname+offset, fnames[j]) > 0) j++;
		    }
		}
	      if(cnt > 0)
                {
                  reallyUpdated = 1;
                  EZ_WorkAreaDeleteSomeItemsUsingIndices(workarea, indices, cnt);
                }
	      
	      /* 2: insert new items */
	      j = 0;
	      i = (glob == 0) ? 1 : 0;
	      icount = EZ_GetWorkAreaNumberOfItems(workarea); /* icount -= cnt */
	      while(j < count)
		{
		  while(j < count && fnames[j] == NULL) j++;
		  if(j < count)
		    {
                      reallyUpdated = 1;
		      if(glob == 0)
			{
			  sprintf(buf,"%s%s%s\0", dirpath, (dirpath[1] == '\0' ? "" : "/"), fnames[j]);
			  nitem = createFileItem(buf, fnames[j], folder, NULL);
			}
		      else nitem = createFileItem(fnames[j], fnames[j]+dirlength, folder, NULL);
		      
		      /* insertion may change these */
		      oitems = EZ_GetWorkAreaData(workarea);
		      while(i < icount)
			{
			  item = oitems[i];
			  ifinfo = (FileInfo *)EZ_GetItemPtrData(item);
			  oname = ifinfo->pathname;
			  cmp = strcmp(oname+offset, fnames[j]);
			  if(cmp < 0) i++;
			  else break;
			}
		      EZ_WorkAreaInsertItemUsingIdx(workarea, nitem, i< icount? i: 9999999);
		      i++; icount++;
		      (void)EZ_Free((void *)fnames[j]); 
		      fnames[j] = NULL;
		    }
		  j++;
		}
	    }
          else /* sort by size or time  */
            {
	      EZ_Item  **oitems, *item, *nitem;
	      char     *oname; 
	      int      indices[1024];
	      int      findices[1024];
	      FileInfo *ifinfo;
	      int      i,j,k,l, cnt, fcnt, cmp, update, offset, idx0;
	      
	      if(glob) 
                { offset = 0; idx0 = 0;}
              else
                { offset = dirlength; idx0 = 1;}
	      oitems = EZ_GetWorkAreaData(workarea);
	      update = (uflag > 10);
	      /* 1: delete items correspond to deleted files */
	      cnt = 0; fcnt = 0;
              memset(findices, 0, 1024 * sizeof(int));
              for(i = idx0; i < icount; i++)
                {
                  item = oitems[i];
                  ifinfo = (FileInfo *)EZ_GetItemPtrData(item);
                  oname = ifinfo->pathname;
                  cmp = findNameInArray(oname+offset, fnames, count);
		  if(cmp >= 0) /* match */
		    {
		      int up2date = 1;
		      if(update)
			{
			  struct stat fstatbuf;
			  int status = lstat(oname, &fstatbuf);
			  time_t cmtime = (status == 0? fstatbuf.st_ctime: 0);
			  if(cmtime != ifinfo->mtime) /* item is outdated */
			    {
			      indices[cnt++] = i;
			      up2date = 0;
			    }
			}
                      if(up2date) findices[cmp] = 1;
		    }
		  else /*if(cmp < 0) *//* delete item */
                    indices[cnt++] = i;
		}
	      if(cnt > 0)
                {
                  reallyUpdated = 1;
                  EZ_WorkAreaDeleteSomeItemsUsingIndices(workarea, indices, cnt);
                }
	      
	      for( i = 0; i < count; i++)
		{
		  if(findices[i] == 0)
                    {
                      reallyUpdated = 1;
		      if(glob == 0)
			{
			  sprintf(buf,"%s%s%s\0", dirpath, (dirpath[1] == '\0' ? "" : "/"), fnames[i]);
			  nitem = createFileItem(buf, fnames[i], folder, NULL);
			}
		      else nitem = createFileItem(fnames[i], fnames[i]+dirlength, folder, NULL);
		      EZ_WorkAreaInsertItemUsingIdx(workarea, nitem, -1);
                    }
                  (void)EZ_Free((void *)fnames[i]); 
                  fnames[i] = NULL;
		}
            }
	}
      else if(fdrtype == LIST_FOLDER)
	{
	  EZ_Widget *flistbox = container;
	  char      *p, buf[1024];
	  int       icount;
	    
	  if(newdir) /* if new dir, rebuild */
	    {
	      EZ_FancyListBoxClear(flistbox);
	      icount = 0;
	    }
	  else icount = EZ_GetFancyListBoxNumberOfRows(flistbox);
	  
	  if(icount <= 1) /* new dir */
	    {
	      int           i, j = 0;
	      EZ_Item       **items;

              reallyUpdated = 1;
	      items = (EZ_Item **)EZ_Malloc( (count+2) * EZFM_FLISTBOX_N_ENTRIES * sizeof(EZ_Item *));
	      if(glob == 0)
		{
		  /* parent dir */
		  strcpy(buf, dirpath);
		  p = strrchr(buf, '/');
		  if(p) *p = '\0';
		  if(buf[0] == '\0') { buf[0] = '/'; buf[1] = '\0'; }
		  createFileItem(buf, "..", folder, items);	      
		  j=EZFM_FLISTBOX_N_ENTRIES;
		}
		  /* entries in dir */
	      for(i = 0; i < count; i++, j += EZFM_FLISTBOX_N_ENTRIES)
		{
		  if(glob == 0)
		    {
		      sprintf(buf,"%s%s%s\0", dirpath, (dirpath[1] == '\0' ? "" : "/"), fnames[i]);
		      (void) createFileItem(buf, fnames[i], folder, items+j);
		    }
		  else
		    {
		      (void) createFileItem(fnames[i], fnames[i]+dirlength, folder, items+j);
		    }
		  (void)EZ_Free((void *)fnames[i]);
		  /* */
		  if(i & 8)
		    {
		      sprintf(statusString, "Made %d items ...", i);
		      EZ_ConfigureWidget(statuslabel, EZ_LABEL_STRING, statusString, NULL);
		      XSync(EZ_GetDisplay(), False);
		    }
		  /* */
		}
	      EZ_SetFancyListBoxData(flistbox, items, count+ (glob == 0? 1 : 0), EZFM_FLISTBOX_N_ENTRIES);
	      (void)EZ_Free((void *)items);
	    }
	  else if(sorter == 0 && sorterChanged == 0) /* updating */
	    {
	      int      indices[1024];
	      FileInfo *ifinfo;
	      int      i,j,k,l, cnt, cmp, update, offset;
	      EZ_Item  *item, ***oitems;
	      EZ_Item  *new_row[EZFM_FLISTBOX_N_ENTRIES+1];
	      char     *oname;

	      offset = (glob == 0? dirlength: 0);
	      oitems = EZ_GetFancyListBoxData(flistbox);
	      update = (uflag > 10);
	      /* 1: delete items correspond to deleted files */
	      cnt = 0; 
	      i = 1 + (glob==0? 1: 0);   /* parent dir is at location 1, header is at 0 */
	      j = 0;
	      while(i < icount)
		{
		  if(j < count)
		    {
		      item = oitems[i][0];
		      ifinfo = (FileInfo *)EZ_GetItemPtrData(item);
		      oname = ifinfo->pathname;
		      cmp = strcmp(oname+offset, fnames[j]);
		    }
		  else { cmp = -1;}
		  
		  if(cmp == 0) /* match */
		    {
		      int up2date = 1;
		      if(update)
			{
			  struct stat fstatbuf;
			  int status = lstat(oname, &fstatbuf);
			  time_t cmtime = (status == 0? fstatbuf.st_ctime: 0);
			  if(cmtime != ifinfo->mtime) /* item is outdated */
			    {
			      indices[cnt++] = i;
			      up2date = 0;
			    }
			}
		      if(up2date)
			{
			  (void)EZ_Free((char *)fnames[j]);
			  fnames[j] = NULL;
			}
		      i++; j++;
		    }
		  else if(cmp < 0) /* delete item */
		    {
		      indices[cnt++] = i;
		      i++;
		    }
		  else
		    {
		      j++;
		      while( j < count && strcmp(oname+offset, fnames[j]) > 0) j++;
		    }
		}
	      if(cnt > 0)
                {
                  reallyUpdated = 1;
                  EZ_FancyListBoxDeleteSomeRows(flistbox, indices, cnt);
                }
	      
	      /* 2: insert new items */
	      j = 0;
	      i = 1 +(glob==0?1:0); /* skip header and parent dir */
	      while(j < count)
		{
		  while(j < count && fnames[j] == NULL) j++;
		  if(j < count)
		    {
                      reallyUpdated = 1;
		      if(glob == 0)
			{
			  sprintf(buf,"%s%s%s\0", dirpath, (dirpath[1] == '\0' ? "" : "/"), fnames[j]);
			  (void)createFileItem(buf, fnames[j], folder, new_row);
			}
		      else (void)createFileItem(fnames[j], fnames[j]+dirlength, folder, new_row);
		      /* insertion may change these */
		      oitems = EZ_GetFancyListBoxData(flistbox);
		      while(i < icount)
			{
			  item = oitems[i][0];
			  ifinfo = (FileInfo *)EZ_GetItemPtrData(item);
			  oname = ifinfo->pathname;
			  cmp = strcmp(oname+offset, fnames[j]);
			  if(cmp < 0) i++;
			  else break;
			}
		      EZ_FancyListBoxInsertRow(flistbox,  new_row, EZFM_FLISTBOX_N_ENTRIES, 
					       i< icount? i: 9999999);
		      (void)EZ_Free((void *)fnames[j]); 
		      fnames[j] = NULL;
		    }
		  j++;
		}	      
	    }
          else /* sort by size or time */
            {
	      int      indices[1024],findices[1024];
	      FileInfo *ifinfo;
	      int      i,j,k,l, cnt, fcnt, cmp, update, offset, idx0;
	      EZ_Item  *item, ***oitems;
	      EZ_Item  *new_row[EZFM_FLISTBOX_N_ENTRIES+1];
	      char     *oname;

              if(glob) { offset = 0;  idx0 = 1;   }
              else  {offset = dirlength; idx0 = 2;}
	      oitems = EZ_GetFancyListBoxData(flistbox);
	      update = (uflag > 10);
	      /* 1: delete items correspond to deleted files */
	      cnt = 0; fcnt = 0;
              memset(findices, 0, 1024 * sizeof(int));
	      for(i=idx0; i < icount; i++) /* header row, parent dir !!! */
		{
                  item = oitems[i][0];
                  ifinfo = (FileInfo *)EZ_GetItemPtrData(item);
                  oname = ifinfo->pathname;
                  cmp = findNameInArray(oname+offset, fnames, count);
		  if(cmp >= 0) /* match */
		    {
		      int up2date = 1;
		      if(update)
			{
			  struct stat fstatbuf;
			  int status = lstat(oname, &fstatbuf);
			  time_t cmtime = (status == 0? fstatbuf.st_ctime: 0);
			  if(cmtime != ifinfo->mtime) /* item is outdated */
			    {
			      indices[cnt++] = i;
			      up2date = 0;
			    }
			}
		      if(up2date) findices[cmp] = 1;
		    }
		  else /* if(cmp < 0) */ /* delete item */
                    indices[cnt++] = i;
		}
	      if(cnt > 0)
                {
                  reallyUpdated = 1;
                  EZ_FancyListBoxDeleteSomeRows(flistbox, indices, cnt);
                }
	      
	      /* 2: insert new items */
	      for(i = 0; i < count; i++)
		{
		  if(findices[i] == 0)
		    {
                      reallyUpdated = 1;
		      if(glob == 0)
			{
			  sprintf(buf,"%s%s%s\0", dirpath, (dirpath[1] == '\0' ? "" : "/"), fnames[i]);
			  (void)createFileItem(buf, fnames[i], folder, new_row);
			}
		      else (void)createFileItem(fnames[i], fnames[i]+dirlength, folder, new_row);
		      /* insertion may change these */
		      EZ_FancyListBoxInsertRow(flistbox,  new_row, EZFM_FLISTBOX_N_ENTRIES, -1);
                    }
                  (void)EZ_Free((void *)fnames[i]); 
                  fnames[i] = NULL;
                }
            }
	}
      else if(fdrtype == TREE_FOLDER)
	{
	  EZ_Widget   *listtree = folder->listtree;
	  container = listtree;

	  EZ_SetWidgetIntData(statuslabel, 0);
	  oldShowHidden = EZ_GlobHiddenFiles(showhidden);

	  /* uflag == 0x123 indicates that show_hidden_flag has changed.
	   * we set newdir=1 to force a re-creation of the dir tree.
	   * EZ_UpdateDirTreeWidget does not work.
	   */
	  if(uflag == 0x123) newdir = 1;

	  if(newdir)
	    {
	      char *path = finfo->pathname, pattern[1024];
	      EZ_TreeNode  *root;
              reallyUpdated = 1;
              sorterChanged = 1;
	      if(glob == 0)
		{
		  int len = strlen(path);
		  sprintf(pattern, "%s%s*", path, (path[len-1] == '/' ? "" :"/"));
		  root = EZ_CreateDirTree(myFileNodeCreator, pattern, folder, -1); 
		}
	      else root = EZ_CreateDirTree(myFileNodeCreator, path, folder, -1); 
	      
	      /* EZ_TreeSetCharacter(root, EZ_LIST_TREE, 0, 0, 2);*/
	      EZ_SetListTreeWidgetTree(listtree, root); 		
	    }
	  else
	    {
	      reallyUpdated += EZ_UpdateDirTreeWidget(listtree);
	      if(uflag > 10) 
		{
		  EZ_TreeNode *root = EZ_GetListTreeWidgetTree(listtree);
		  EZ_TreeTraverseTree(root, updateTreeNode, NULL);
		  EZ_DisplayWidget(listtree);
		}
	    }
	  EZ_GlobHiddenFiles(oldShowHidden);
	}
      if(viewable)
	{
          if(reallyUpdated || sorterChanged)
            {
              switch(fdrtype)
                {
                case ICON_FOLDER: 
                  sortIconFolder(folder->workarea, sorter, glob, sorterChanged); 
                  break;
                case ICON_FOLDER_SMALL: 
                  sortIconFolder(folder->workareaS, sorter,glob, sorterChanged); 
                  break;
                case LIST_FOLDER: 
                  sortListFolder(folder->flistbox, sorter,glob, sorterChanged); 
                  break;
                case TREE_FOLDER: 
                  if(sorterChanged)
                    sortTreeFolder(folder->listtree, sorter,glob, sorterChanged); 
                  break;
                }
            }
          if(sorterChanged) EZ_ConfigureWidget(container, EZ_MARK_CLEAN, False, 0);
	  EZ_UnFreezeWidget(container);
	  if(dirty >= 100) EZ_NormalCursor(toplevel);
	}
      showSelectionStatus(folder);
      if(newdir || setname) setToplevelName(tp);
    }
}
/*************************************************************
 *
 * set the window name for toplevel windows.
 */
void setToplevelName(tp) Toplevel *tp;
{
  if(tp)
    {
      EZ_Widget *toplevel = tp->toplevel;
      if(EZ_GetWidgetWindow(toplevel))
	{
	  char      name[512];
	  sprintf(name, "%s@%s %s", EZFMVERSIONSTRING, ezfmHostname,
		  tp->folder[0]->finfo->pathname);
	  if(tp->folder[1])
	    {
	      char tmp[256];
	      sprintf(tmp, ":%s", tp->folder[1]->finfo->pathname);
	      strcat(name, tmp);
	    }
	  XStoreName(EZ_GetDisplay(), EZ_GetWidgetWindow(toplevel),name);
	}
    }
}

/*************************************************************
 *
 * For each open folder, there is a timer which repeadly
 * updates the folder. 
 */
static void folderTimerCallback(timer, data)
     EZ_Timer *timer; void *data;
{
  Folder     *ptr = folderList, *folder = (Folder *)data;
  Folder     *find = NULL;

  while(ptr)
    {
      if(ptr == folder) { find = ptr; break;}
      ptr = ptr->next;
    }
  if(find)
    {
      if(folder->flags & DND_UPDATE_PENDING)
        {
          folder->flags &= ~DND_UPDATE_PENDING;
          updateFolder(folder, 100);
	  EZ_SetTimerIntData(timer, 0);
        }
      else if(folder->flags & AUTO_UPDATE_BIT)
	{
	  Toplevel *toplevel = (Toplevel *) folder->toplevel;
	  EZ_Widget  *widget = toplevel->toplevel;
	  int       cnt = EZ_GetTimerIntData(timer) + 1;
	  EZ_SetTimerIntData(timer, cnt>20? 0: cnt); /* do a complete update every 2 minutes */
	  if(EZ_WidgetIsViewable(widget))
	    updateFolder(folder, cnt > 20? cnt: 1);
	}
    }
  else EZ_CancelTimer(timer);
}

/*************************************************************
 *
 *  Given a directory name, create a new folder for it.
 */
Folder *createNewFolder(pathname, toplevel, which, ftype)
     char *pathname; Toplevel *toplevel; int which; /* 0 or 1 */ int ftype;
{
  Folder       *folder; 
  FileInfo     *finfo; 
  int          len;
  EZ_Widget    *pframe, *tmp;
  int          type = (ftype == 0 ? defaultFolderType: ftype);

  if(which != 0 && which != 1) return;
  if(toplevel->folder[which] != NULL) return;

  folder= (Folder *)   EZ_Malloc(sizeof(Folder));
  finfo  = (FileInfo *) EZ_Malloc(sizeof(FileInfo));
  memset(finfo, 0, sizeof(FileInfo));
  len = strlen(pathname);

  finfo->pathname = (char *)EZ_Malloc((len+1) * sizeof(char));
  strcpy(finfo->pathname, pathname);
  finfo->type = FOLDER;
  finfo->ezfmData = GetFileTypeInfo(pathname);
  finfo->obj = (void *)folder;
  finfo->host = NULL;
  finfo->mtime = (time_t)0;
  finfo->glob = EZ_IsGlobPattern(pathname);
  folder->finfo = finfo;
  folder->blocked = 0;
  folder->workarea = NULL;
  folder->workareaS = NULL;
  folder->listtree = NULL;
  folder->flistbox = NULL;
  folder->toplevel = toplevel;
  folder->bgpixmap = NULL;
  folder->flags   = toplevel->flags;

  pframe = toplevel->folderframe;
  if(which == 1)   /* the second folder */
    {
      type = (ftype == 0 ? toplevel->folder[0]->type: ftype);
      toplevel->panehandle = EZ_CreateWidget(EZ_WIDGET_PANE_HANDLE, pframe, NULL);
      EZ_ConfigureWidget(toplevel->folder[0]->frame, EZ_WIDTH, 0, NULL);
      if(toplevel->folder[0]->bgpixmap)
	{
	  int len = strlen(toplevel->folder[0]->bgpixmap) + 1;
	  folder->bgpixmap = (char *) EZ_Malloc(len * sizeof(char));
	  strcpy(folder->bgpixmap, toplevel->folder[0]->bgpixmap);
	}
    }

  folder->frame = EZ_CreateWidgetXrm(EZ_WIDGET_FRAME,      pframe,
				     "FolderFrame",        "folderFrame",
				     EZ_DESTROY_CALLBACK,  folderDestroyCallback, finfo,
				     EZ_ORIENTATION,       EZ_VERTICAL,
				     EZ_FILL_MODE,         EZ_FILL_BOTH,
				     EZ_PADX,              0,
				     EZ_PADY,              0,
				     NULL);
  if(which == 0)  EZ_ConfigureWidget(folder->frame,
				     EZ_FORGET_SIZE,       True,
				     NULL);

  
  folder->barframe = EZ_CreateWidgetXrm(EZ_WIDGET_FRAME,      folder->frame,
					"FolderBarFrame",    "folderBarFrame",
					EZ_GRID_CONSTRAINS,   EZ_COLUMN, 0, 50, 100, 0,
					EZ_HEIGHT,            0,
					EZ_PADX,              0,
					EZ_PADY,              0,
					NULL);
  folder->optentry =EZ_CreateWidgetXrm(EZ_WIDGET_OPTIONAL_ENTRY,folder->barframe,
				       "FolderOptEntry", "folderOptEntry",
				       EZ_GRID_CELL_GEOMETRY,   0, 0, 1, 1,
				       EZ_GRID_CELL_PLACEMENT,  EZ_FILL_BOTH, EZ_LEFT,
				       EZ_POPUP_NAME,           "optEntryPopup",
				       EZ_FONT_ID,              ezfmFontId[TEXT_FONT],
				       EZ_PADX,                 0,
				       EZ_PADY,                 0,
				       NULL);
  {
    EZ_Widget *entry, *listbox, *btn;
    EZ_GetOptionalEntryWidgetComponents(folder->optentry, &entry, &listbox, &btn);
    EZ_ConfigureWidget(listbox, EZ_BORDER_WIDTH, 1, NULL);
    EZ_ConfigureWidget(entry, 
		       EZ_PADX,                 2,
		       EZ_PADY,                 4,
		       NULL);
    /*entryCanonicalString will be invoked before all callbacks */
    EZ_AddWidgetCallBack(entry, EZ_CALLBACK, entryCanonicalString, NULL, -1);
    EZ_AddWidgetCallBack(entry, EZ_CALLBACK, entryCallback, folder, 0);

    EZ_WidgetAddDnDDataDecoder(entry, ezfmFileNameAtom, 0, 
			       entryDirNameDecoder, NULL,  NULL, NULL);
  }
  
  /* 4 radio buttons */
  tmp =             EZ_CreateWidget(EZ_WIDGET_RADIO_BUTTON,  folder->barframe,
				    EZ_GRID_CELL_GEOMETRY,   1, 0, 1, 1,
				    EZ_LABEL_STRING,         "Icon",
				    EZ_BITMAP_FILE,          "iconI.xpm",
				    EZ_PADX,                 0,
				    EZ_PADY,                 0,
				    EZ_BUBBLE_HELP,          "Display files using icons",
				    EZ_RADIO_BUTTON_GROUP,   ezfmRbtnCounter,
				    EZ_RADIO_BUTTON_VALUE,   ICON_FOLDER,
				    EZ_CALLBACK,             rbtnCallback, folder,
				    EZ_INDICATOR_TYPE,       EZ_EMPTY_INDICATOR,
				    EZ_FONT_ID,              ezfmFontId[LABEL_BOLD_FONT],
				    NULL);
  tmp =             EZ_CreateWidget(EZ_WIDGET_RADIO_BUTTON,  folder->barframe,
				    EZ_GRID_CELL_GEOMETRY,   2, 0, 1, 1,
				    EZ_LABEL_STRING,         "IconS",
				    EZ_BITMAP_FILE,          "iconIS.xpm",
				    EZ_PADX,                 0,
				    EZ_PADY,                 0,
				    EZ_BUBBLE_HELP,          "Display files using small icons",
				    EZ_RADIO_BUTTON_GROUP,   ezfmRbtnCounter,
				    EZ_RADIO_BUTTON_VALUE,   ICON_FOLDER_SMALL,
				    EZ_CALLBACK,             rbtnCallback, folder,
				    EZ_INDICATOR_TYPE,       EZ_EMPTY_INDICATOR,
				    EZ_FONT_ID,              ezfmFontId[LABEL_BOLD_FONT],
				    NULL);
  
  tmp =             EZ_CreateWidget(EZ_WIDGET_RADIO_BUTTON,  folder->barframe,
				    EZ_GRID_CELL_GEOMETRY,   3, 0, 1, 1,
				    EZ_LABEL_STRING,         "List",
				    EZ_BITMAP_FILE,          "listI.xpm",
				    EZ_PADX,                 0,
				    EZ_PADY,                 0,
				    EZ_BUBBLE_HELP,          "Display files using long lists",
				    EZ_RADIO_BUTTON_GROUP,   ezfmRbtnCounter,
				    EZ_RADIO_BUTTON_VALUE,   LIST_FOLDER,
				    EZ_CALLBACK,             rbtnCallback, folder,
				    EZ_INDICATOR_TYPE,       EZ_EMPTY_INDICATOR,
				    EZ_FONT_ID,              ezfmFontId[LABEL_BOLD_FONT],
				    NULL);
  tmp =             EZ_CreateWidget(EZ_WIDGET_RADIO_BUTTON,  folder->barframe,
				    EZ_GRID_CELL_GEOMETRY,   4, 0, 1, 1,
				    EZ_LABEL_STRING,         "Tree",
				    EZ_BITMAP_FILE,          "treeI.xpm",
				    EZ_PADX,                 0,
				    EZ_PADY,                 0,
				    EZ_BUBBLE_HELP,          "Display files as directory tree",
				    EZ_RADIO_BUTTON_GROUP,   ezfmRbtnCounter,
				    EZ_RADIO_BUTTON_VALUE,   TREE_FOLDER,
				    EZ_CALLBACK,             rbtnCallback, folder,
				    EZ_INDICATOR_TYPE,       EZ_EMPTY_INDICATOR,
				    EZ_FONT_ID,              ezfmFontId[LABEL_BOLD_FONT],
				    NULL);
  EZ_SetRadioButtonGroupVariableValue(tmp, type);
  ezfmRbtnCounter++;
  
  /* insert 'folder' to folderList */
  folder->next = folderList;
  folderList = folder;
  createFolderFolder(folder, type);

  /* set background pixmap */
  if(ezfmFolderBgPixmap[0]) 
    setObjBgPixmap(folder,ezfmFolderBgPixmap, NULL);
  
  (void) EZ_CreateTimer(2, 0, -1, folderTimerCallback, folder, 0);

  if(finfo->glob == 0) BroadcastFolderOpenCloseded(pathname, 1);
  return(folder);
}

/*************************************************************
 *
 * Create a new toplevel window.
 */
static Toplevel *createNewToplevel()
{
  Toplevel *tp = (Toplevel *)EZ_Malloc(sizeof(Toplevel));
  if(tp)
    {
      EZ_Widget *mfile, *mview, *mhelp, *tmp;
      EZ_LabelPixmap *lbxpm = EZ_CreateLabelPixmapFromXpmFile("Folder.xpm");
      
      tp->toplevel = EZ_CreateWidgetXrm(EZ_WIDGET_FRAME,       NULL,
					"Toplevel",            "toplevel",
					EZ_ORIENTATION,        EZ_VERTICAL,
					EZ_FILL_MODE,          EZ_FILL_BOTH,
					EZ_SIZE,               640,480,
					EZ_DESTROY_CALLBACK,   toplevelDestroyCallback, tp,
					EZ_PADX,               2,
					EZ_PADY,               0,
					EZ_WM_ICON_PIXMAP,     lbxpm,
					EZ_WM_WINDOW_NAME,     EZFMVERSIONSTRING,
					EZ_BG_PIXMAP,          bigPixmap, 
                                        EZ_EVENT_HANDLER,      ConfigureNotifyHandler, NULL,
					NULL);

      tp->menubar = EZ_CreateWidgetXrm(EZ_WIDGET_MENU_BAR,     tp->toplevel,
				       "MenuBar",              "menuBar",
				       EZ_HEIGHT,              0,
				       EZ_IPADX,               6,
				       EZ_PADX,                0,
				       EZ_PADY,                0,
				       EZ_EVENT_HANDLER,       mBarEHandler, NULL,
				       EZ_DOCKABLE,            1,
				       NULL);

      setupMBtnFile(tp->menubar, tp);
      setupMBtnView(tp->menubar, tp);
      setupMBtnSelection(tp->menubar, tp);
      setupMBtnOption(tp->menubar, tp);
      EZ_MenuBarAddItemAndMenu(tp->menubar, NULL, -1, NULL);  /* separator */
      setupMBtnHelp(tp->menubar, tp);


      /* tool bar */
      tp->toolbar = makeToolBar(tp);

      
      /* frame to hold folders */
      tp->folderframe =EZ_CreateWidget(EZ_WIDGET_FRAME,       tp->toplevel,
				       EZ_FILL_MODE,          EZ_FILL_BOTH,
				       EZ_PADX,               0,
				       EZ_PADY,               0,
				       EZ_IPADX,              0,
				       EZ_IPADY,              0,
				       NULL);
      /* bottom status label */
      tp->statuslabel =EZ_CreateWidgetXrm(EZ_WIDGET_LABEL,       tp->toplevel,
					  "StatusLabel",         "statusLabel",
					  EZ_EXPAND,             True,
					  EZ_LABEL_POSITION,     EZ_LEFT,
					  EZ_PROPAGATE,          False,
					  EZ_TEXT_LINE_LENGTH,   256,
					  EZ_FONT_ID,            ezfmFontId[ITEM_MEDIUM_FONT],
					  EZ_HEIGHT,             0,
					  NULL);
      tp->panehandle = NULL;
      tp->folder[0] = NULL;
      tp->folder[1] = NULL;
      tp->activeFolder = NULL;
      tp->flags = ezfmFlags;
    }
  return(tp);
}
/********************************************************************************
 *
 * create the tool bar
 */
static void openHome(widget, data) EZ_Widget* widget; void *data;
{
  EZ_Widget *frame = (EZ_Widget *)data; /* parent frame */
  Toplevel  *tp;
  if(frame && (tp = (Toplevel *)EZ_GetWidgetPtrData(frame)) != NULL)
    gotoHome(NULL, tp);
  else  OpenFolder(getenv("HOME"), NULL, 1, 0);
}

static void tbarDestroyCB(widget, data) EZ_Widget* widget; void *data;
{
}

EZ_Widget *makeToolBar(tp) Toplevel *tp;
{
  EZ_Widget *frame, *tmp, *parent = NULL;
  int       type = EZ_WIDGET_FREE_LABEL;

  if(tp) 
    {
      parent = tp->toplevel;
      type = EZ_WIDGET_FRAME;
    }
  
  frame       = EZ_CreateWidgetXrm(type,                   parent,
				   "ToolBar",              "toolBar",
				   EZ_CLIENT_PTR_DATA,     tp,
				   EZ_TRANSIENT,           True,
				   EZ_EXPAND,              True,
				   /*EZ_PROPAGATE,           False,*/
				   EZ_BORDER_WIDTH,        1,
				   EZ_BORDER_TYPE,         EZ_BORDER_RAISED,
				   EZ_IPADX,               6,
				   EZ_PADX,                2,
				   EZ_PADY,                0,				       
				   EZ_HEIGHT,              0,
				   EZ_GRID_CONSTRAINS,     EZ_COLUMN, 4,  20, 30, 0,/*idx,min,wei,pad*/
				   EZ_GRID_CONSTRAINS,     EZ_COLUMN, 13, 20, 30, 0,
				   EZ_GRID_CONSTRAINS,     EZ_COLUMN, 15, 20, 30, 0,
				   EZ_DOCKABLE,            1,
				   NULL);

  /* popup a menu to hide the toolbar */
  EZ_AddEventHandler(frame, toolBarEHandler, frame, 0);
  
  /* printer */ 
  tmp =            EZ_CreateWidgetXrm(EZ_WIDGET_NORMAL_BUTTON, frame,
				      "ToolPrint",          "toolPrint",
				      EZ_LABEL_STRING,        "Print",
				      EZ_BITMAP_FILE,         "printer.xpm",
				      EZ_BUBBLE_HELP,         "Print selected file",
				      EZ_DND_BUBBLE_HELP,     "Print draged file",
				      EZ_GRID_CELL_GEOMETRY,  0, 0, 1, 1, /* x, y, w, h */
				      EZ_UNDERLINE,           0,
				      EZ_PADX,                0,
				      EZ_PADY,                0,
				      EZ_PROPAGATE,           False,
				      NULL);
  setupPrinter(tmp, frame);

      
      /* trash can */
  tmp =            EZ_CreateWidgetXrm(EZ_WIDGET_NORMAL_BUTTON, frame,
				      "ToolTrash",         "toolTrash",
				      EZ_LABEL_STRING,        "Delete",
				      EZ_BITMAP_FILE,         "trashcan.xpm",
				      EZ_BUBBLE_HELP,         "Delete selected file",
				      EZ_DND_BUBBLE_HELP,     "Delete draged file",
				      EZ_GRID_CELL_GEOMETRY,  1, 0, 1, 1, /* x, y, w, h */
				      EZ_UNDERLINE,           0,
				      EZ_PADX,                0,
				      EZ_PADY,                0,
				      EZ_PROPAGATE,           False,
				      NULL);
  setupTrashButton(tmp, frame);

      /* info */
  tmp =            EZ_CreateWidgetXrm(EZ_WIDGET_NORMAL_BUTTON, frame,
				      "ToolInfo",         "toolInfo",
				      EZ_LABEL_STRING,        "Info",
				      EZ_BITMAP_FILE,         "finfo.xpm",
				      EZ_BUBBLE_HELP,         "Show info about the selected file",
				      EZ_DND_BUBBLE_HELP,     "Show info about the drag",
				      EZ_GRID_CELL_GEOMETRY,  2, 0, 1, 1, /* x, y, w, h */
				      EZ_UNDERLINE,           0,
				      EZ_PADX,                0,
				      EZ_PADY,                0,
				      EZ_PROPAGATE,           False,
				      NULL);
  setupInfoButton(tmp, frame);

  /* removable devices */            
#ifdef REMOVABLE_DRIVES
  setupDrivesButtons(frame, 5); /* 5 is the startind index in gridbag row */
#endif
      
  tmp =            EZ_CreateWidgetXrm(EZ_WIDGET_NORMAL_BUTTON, frame,
				      "ToolHome",          "toolHome",
				      EZ_LABEL_STRING,        "Home",
				      EZ_BITMAP_FILE,         "home.xpm",
				      EZ_BUBBLE_HELP,         "Open home folder",
				      EZ_GRID_CELL_GEOMETRY,  16, 0, 1, 1, /* x, y, w, h */
				      EZ_UNDERLINE,           0,
				      EZ_PADX,                0,
				      EZ_PADY,                0,
				      EZ_PROPAGATE,           False,
				      EZ_CALLBACK,            openHome, frame,
				      NULL);

  tmp =            EZ_CreateWidgetXrm(EZ_WIDGET_NORMAL_BUTTON, frame,
				      "ToolXterm",     "toolXterm",
				      EZ_LABEL_STRING,        "Xterm",
				      EZ_BITMAP_FILE,         "xtermx.xpm",
				      EZ_BUBBLE_HELP,         "Start an xterm in current folder",
				      EZ_GRID_CELL_GEOMETRY,  17, 0, 1, 1, /* x, y, w, h */
				      EZ_UNDERLINE,           0,
				      EZ_PADX,                0,
				      EZ_PADY,                0,
				      EZ_PROPAGATE,           False,
				      EZ_CALLBACK,            startXtermHere, frame,
				      NULL);

  tmp =            EZ_CreateWidgetXrm(EZ_WIDGET_NORMAL_BUTTON, frame,
				      "ToolToolBox",       "toolToolBox",
				      EZ_LABEL_STRING,        "Tools",
				      EZ_BITMAP_FILE,         "tools.xpm",
				      EZ_BUBBLE_HELP,         "Open tool box",
				      EZ_GRID_CELL_GEOMETRY,  18, 0, 1, 1, /* x, y, w, h */
				      EZ_UNDERLINE,           0,
				      EZ_PADX,                0,
				      EZ_PADY,                0,
				      EZ_CALLBACK,            openToolBox, NULL,
				      EZ_PROPAGATE,           False,
				      NULL);
  return(frame);
}

/*************************************************************
 *
 *  Find a folder with the given pathname
 */
Folder *findFolder(pathname) 
     char *pathname;
{
  if(pathname)
    {
      Folder     *folder = NULL, *ptr = folderList;      
      int        len;

      while(ptr != NULL)
	{
	  FileInfo *finfo = ptr->finfo;
	  if(!strcmp(pathname, finfo->pathname)) return(ptr);
	  ptr = ptr->next;
	}
    }
  return(NULL);
}
/*
 * count the number of folders cached.
 */
int countNFolders()
{
  Folder *ptr = folderList;
  int cnt = 0;
  while(ptr) { cnt++; ptr=ptr->next;}
  return(cnt);
}

/*
 * Set Folder Options
 */
void modifyDpyOptionOneFolder(folder, flag, bg, dobg)
     Folder *folder; int flag; char *bg; int dobg;
{
  /* printf("[%d] %s\n", flag &SHOW_HIDDEN_BIT, bg);*/
  if(folder)
    {
      int or = folder->flags;
      int nr = flag;
      if(or != nr)
	{ 
	  Toplevel *tp = folder->toplevel;
          int v =  (nr & RUBBER_BAND_BIT) !=0? 2 : 0;
	  tp->flags = nr;
	  folder->flags = nr;
          if(folder->workarea)
            EZ_ConfigureWidget(folder->workarea,  EZ_RUBBER_BAND, v , 0);
          if(folder->workareaS)
            EZ_ConfigureWidget(folder->workareaS, EZ_RUBBER_BAND, v , 0);
          if(folder->flistbox)
            EZ_ConfigureWidget(folder->flistbox,  EZ_RUBBER_BAND, v , 0);
          if(folder->listtree)
            EZ_ConfigureWidget(folder->listtree,  EZ_RUBBER_BAND, v , 0);
	  updateFolder(folder, 0x123);
	}
      if(dobg) setObjBgPixmap(folder, bg, NULL);
    }
}
void modifyDpyOptionAllFolders(flag, bg)
     int flag; char *bg;
{
  Folder *ptr = folderList;
  while(ptr)
    {
      modifyDpyOptionOneFolder(ptr, flag, bg, 1);
      ptr=ptr->next;
    }
}
/*************************************************************
 *
 *    Open a folder. pathname must be a valid dir name !!
 *
 *     1. if there is an opened folder for pathname,
 *        that folder is raised;
 *     2. otherwise if 'cfolder' is a valid folder,
 *        'pathname' is opened in it, otherwise
 *        a new folder will be created.
 */
void OpenFolder(pathname, cfolder, dp, ftype)
     char *pathname; Folder *cfolder; int dp, ftype;
{
  struct stat   stat_buf;
  Folder        *folder;
  int           plen;

  folder = findFolder(pathname);
  if(folder != NULL)
    {
      EZ_Widget *widget = NULL;
      if(folder->type == ICON_FOLDER)       widget = folder->workarea;
      else if(folder->type == ICON_FOLDER_SMALL) widget = folder->workareaS;
      else if(folder->type == LIST_FOLDER)  widget = folder->flistbox;
      else if(folder->type == TREE_FOLDER)  widget = folder->listtree;
      if(widget && dp)
	{
	  EZ_RedisplayWidgetTree(widget);
	  EZ_BlinkWidget(widget, 1);
	}
      return;
    }

  plen = strlen(pathname);
  if((stat(pathname, &stat_buf) >= 0) && S_ISDIR (stat_buf.st_mode))
    {
      /*
       * we are going to open the folder, either in 
       * cfolder (the folder supplied by the caller) 
       * open a new toplevel folder.  We'll send a 
       * message out to see if there is another ezfm
       * has an folder with the same pathname. Warn
       * the user if we ever get an reply.
       */
      FindFolderOtherClients(pathname);
      folder = cfolder;
      if(folder && folderExists(folder))
	{
	  char oldpath[1024];
	  if(folder->finfo->glob == 0) strcpy(oldpath, folder->finfo->pathname);
	  else oldpath[0] = 0;
	  /* open 'pathname' in the current folder */
	  folder->finfo->pathname = (char *)EZ_Realloc(folder->finfo->pathname, 
						       (plen+1)*sizeof(char));
	  (void)strcpy(folder->finfo->pathname, pathname);
	  folder->finfo->mtime = (time_t)0;
	  if(oldpath[0] && findFolder(oldpath) == NULL)
	    BroadcastFolderOpenCloseded(oldpath, 0);
	  updateFolder(folder, 1);   
	}
      else 
	{
	  Toplevel *toplevel = createNewToplevel();
	  int type = ftype == 0? defaultFolderType: ftype;
	  folder = toplevel->folder[0] = createNewFolder(pathname, toplevel, 0, type);
	  if(dp) EZ_DisplayWidget(toplevel->toplevel);
	  updateFolder(folder, 0);	  
	}
      BroadcastFolderOpenCloseded(pathname, 1);
    }
  else if(EZ_IsGlobPattern(pathname))
    {
      folder = cfolder;
      if(folder && folderExists(folder))
	{
	  char oldpath[1024];
	  if(folder->finfo->glob == 0)
	    strcpy(oldpath, folder->finfo->pathname);
	  else oldpath[0] = 0;
	  /* open 'pathname' in the current folder */
	  folder->finfo->pathname = (char *)EZ_Realloc(folder->finfo->pathname, plen+1);
	  (void)strcpy(folder->finfo->pathname, pathname);
	  folder->finfo->mtime = (time_t)0;
	  folder->finfo->glob = 1;
	  if(oldpath[0] && findFolder(oldpath) == NULL)
	    BroadcastFolderOpenCloseded(oldpath, 0);
	  updateFolder(folder, 2);
	}   
      else
	{
	  Toplevel *toplevel = createNewToplevel();
	  int type = ftype == 0? defaultFolderType: ftype;
	  folder = toplevel->folder[0] = createNewFolder(pathname, toplevel, 0, type);
	  if(dp) EZ_DisplayWidget(toplevel->toplevel);
	  updateFolder(folder, 0);	  
	}
    }
}

/*************************************************************
 *
 *    delete a folder
 */
void deleteFolder(folder)
     Folder *folder;
{
  Folder *prev, *next, *del = NULL;

  prev = folderList;
  if(prev == NULL) /* something is wrong */
    {
      fprintf(stderr, "Internal error: folderList is empty\n");
      return;
    }
  if(folder == prev)
    {
      folderList = prev->next;
      del = prev;
    }
  else
    {
      while(prev->next && prev->next != folder)
	prev = prev->next;
      
      if(prev->next)
	{
	  prev->next = folder->next;
	  del = folder;
	}
    }
  if(del)
    {
      BroadcastFolderOpenCloseded(del->finfo->pathname,0);
      (void)EZ_Free((void *) del->finfo->pathname);
      (void)EZ_Free((void *) del->finfo);
      (void)EZ_Free((void *) del);
      if(del->bgpixmap) (void)EZ_Free((void *) del->bgpixmap);
    }
}

int isToplevel(tp)
     void *tp;
{
  Folder *ptr, *next;
  Toplevel *toplevel = (Toplevel *)tp;

  ptr = folderList;
  while(ptr)
    {
      if(ptr->toplevel == tp) return(1);
      ptr = ptr->next;
    }
  return(0);
}
/*---------------------------------------------------------- 
 * Destroy a folder
 */
static void folderDestroyCallback(widget, data)
     EZ_Widget *widget; void *data;
{
  FileInfo *finfo = (FileInfo *)data;
  Folder *folder = (Folder *)finfo->obj;

  deleteFolder(folder);
}

int  folderExists(folder)
     Folder *folder;
{
  Folder *ptr = folderList;
  
  while(ptr)
    {
      if(folder == ptr) return(1);
      ptr = ptr->next;
    }
  return(0);
}
/**********************************************************
 *
 * Create the real folder.
 */
static int      smallIconGData[] = { EZ_LABEL_POSITION, EZ_LEFT,   0};
static int      largeIconGData[] = { EZ_LABEL_POSITION, EZ_CENTER, 0};

static void createFolderFolder(folder, type)
     Folder *folder; int type; 
{
  if(folder)
    {
      EZ_Widget *frame = folder->frame;
      EZ_Widget *theFolder = NULL;
      int rubberband = 0;
      if((ezfmFlags | folder->flags) & RUBBER_BAND_BIT) rubberband = 2;

      EZ_FreezeWidget(frame);

      switch(type)
	{
	case ICON_FOLDER:
	  if(EZ_WidgetExist(folder->workarea) == NULL)
	    {
	      EZ_DestroyWidget(folder->flistbox);  folder->flistbox = NULL;
	      EZ_DestroyWidget(folder->listtree);  folder->listtree = NULL;
	      EZ_DestroyWidget(folder->workareaS); folder->workareaS= NULL;
	      theFolder =  EZ_CreateWidgetXrm(EZ_WIDGET_WORK_AREA,   frame,
					      "IconLister",          "iconLister",
					      EZ_CLIENT_PTR_DATA,    folder->finfo,
					      EZ_ITEM_MOVABLE,       False,
					      /* EZ_OPTIONAL_VSCROLLBAR,False,*/
					      EZ_BORDER_WIDTH,       1,
					      EZ_BITMAP_FILE,        folder->bgpixmap,
					      EZ_IPADX,              2,
					      EZ_IPADY,              1,
					      EZ_RUBBER_BAND,        rubberband,
					      NULL);
	      EZ_SetWorkAreaGeometryManager(theFolder, EZ_WorkAreaGeometryManagerDefault, largeIconGData);
	      folder->workarea = theFolder;
	      EZ_AddEventHandler(theFolder, waFolderEHandler, folder, 0);

	    }
	  break;
	case ICON_FOLDER_SMALL:
	  if(EZ_WidgetExist(folder->workareaS) == NULL)
	    {
	      EZ_DestroyWidget(folder->flistbox);  folder->flistbox = NULL;
	      EZ_DestroyWidget(folder->listtree);  folder->listtree = NULL;
	      EZ_DestroyWidget(folder->workarea);  folder->workarea = NULL;
	      theFolder =  EZ_CreateWidgetXrm(EZ_WIDGET_WORK_AREA,   frame,
					      "SmallIconLister",     "smallIconLister",
					      EZ_CLIENT_PTR_DATA,    folder->finfo,
					      EZ_ITEM_MOVABLE,       False,
					      /* EZ_OPTIONAL_VSCROLLBAR,False,*/
					      EZ_BORDER_WIDTH,       1,
					      EZ_BITMAP_FILE,        folder->bgpixmap,
					      EZ_IPADX,              2,
					      EZ_IPADY,              1,
					      EZ_RUBBER_BAND,        rubberband,
					      NULL);
	      EZ_SetWorkAreaGeometryManager(theFolder, EZ_WorkAreaGeometryManagerDefault, smallIconGData);
	      folder->workareaS = theFolder;
	      EZ_AddEventHandler(theFolder, waFolderEHandler, folder, 0);

	    }
	  break;
	case LIST_FOLDER:
	  if(EZ_WidgetExist(folder->flistbox) == NULL)
	    {
	      EZ_DestroyWidget(folder->workarea);  folder->workarea = NULL;
	      EZ_DestroyWidget(folder->listtree);  folder->listtree = NULL;
	      EZ_DestroyWidget(folder->workareaS); folder->workareaS= NULL;
	      theFolder =  EZ_CreateWidgetXrm(EZ_WIDGET_FANCY_LIST_BOX,  frame,
					      "LongLister",    "longLister",
					      EZ_FANCY_LISTBOX_TYPE,     1, /* a row a time */
					      EZ_FANCY_LISTBOX_COLUMNS,  EZFM_FLISTBOX_N_ENTRIES,
					      EZ_CLIENT_PTR_DATA,    folder->finfo,
					      EZ_BORDER_WIDTH,       1,
					      EZ_BITMAP_FILE,        folder->bgpixmap,
					      EZ_IPADX,              0,
					      EZ_IPADY,              2,
					      EZ_RUBBER_BAND,        rubberband,
					      NULL);
	      folder->flistbox = theFolder;
	      EZ_AddEventHandler(theFolder, flFolderEHandler, folder, 0);

	      if(1)
		{
		  EZ_Item  *fancyListboxHeaderItems[8];
		  fancyListboxHeaderItems[0] =  EZ_CreateItem(EZ_LABEL_ITEM, 
							      EZ_PADX,         0,
							      EZ_PADY,         0,
							      EZ_BORDER_WIDTH, 1,
							      EZ_BORDER_TYPE,  EZ_BORDER_RAISED,
							      EZ_LABEL_STRING, "Name",
							      NULL);
		  fancyListboxHeaderItems[1] =  EZ_CreateItem(EZ_LABEL_ITEM, 
							      EZ_PADX,         0,
							      EZ_PADY,         0,
							      EZ_BORDER_WIDTH, 1,
							      EZ_BORDER_TYPE,  EZ_BORDER_RAISED,
							      EZ_LABEL_POSITION, EZ_CENTER,
							      EZ_LABEL_STRING, "Size  ",
							      NULL);
		  fancyListboxHeaderItems[2] =  EZ_CreateItem(EZ_LABEL_ITEM, 
							      EZ_PADX,         0,
							      EZ_PADY,         0,
							      EZ_BORDER_WIDTH, 1,
							      EZ_BORDER_TYPE,  EZ_BORDER_RAISED,
							      EZ_LABEL_STRING, " Modified",
							      NULL);
		  fancyListboxHeaderItems[3] =  EZ_CreateItem(EZ_LABEL_ITEM, 
							      EZ_PADX,         0,
							      EZ_PADY,         0,
							      EZ_BORDER_WIDTH, 1,
							      EZ_BORDER_TYPE,  EZ_BORDER_RAISED,
							      EZ_LABEL_STRING, "Owner",
							      NULL);
		  fancyListboxHeaderItems[4] =  EZ_CreateItem(EZ_LABEL_ITEM, 
							      EZ_PADX,         0,
							      EZ_PADY,         0,
							      EZ_BORDER_WIDTH, 1,
							      EZ_BORDER_TYPE,  EZ_BORDER_RAISED,
							      EZ_LABEL_STRING, "Group",
							      NULL);
		  fancyListboxHeaderItems[5] =  EZ_CreateItem(EZ_LABEL_ITEM, 
							      EZ_PADX,         0,
							      EZ_PADY,         0,
							      EZ_BORDER_WIDTH, 1,
							      EZ_BORDER_TYPE,  EZ_BORDER_RAISED,
							      EZ_LABEL_STRING, "Permission",
							      NULL);
		  EZ_SetFancyListBoxHeader(theFolder, fancyListboxHeaderItems, 6);
		}
	    }
	  break;
	case TREE_FOLDER:
	  if(EZ_WidgetExist(folder->listtree) == NULL)
	    {
	      EZ_DestroyWidget(folder->workarea); folder->workarea = NULL;
	      EZ_DestroyWidget(folder->flistbox); folder->flistbox = NULL;
	      EZ_DestroyWidget(folder->workareaS); folder->workareaS= NULL;
	      theFolder =  EZ_CreateWidgetXrm(EZ_WIDGET_TREE,            frame,
					      "TreeLister",       "treeLister",
					      EZ_CLIENT_PTR_DATA,    folder->finfo,
					      EZ_BORDER_WIDTH,       1,
					      EZ_BITMAP_FILE,        folder->bgpixmap,
					      EZ_IPADX,              2,
					      EZ_IPADY,              1,
					      EZ_RUBBER_BAND,        rubberband,
					      NULL);
	      folder->listtree = theFolder;
	      EZ_AddEventHandler(theFolder, ltFolderEHandler, folder, 0);

	    }
	  break;	  
	default:
	  break;
	}
      
      /* dnd decoders */
      if(theFolder != NULL)
	{
	  FileInfo  *finfo = folder->finfo;
	  EZ_Widget *tmp;
	  
	  folder->type = type;
	  finfo->mtime = 0;
	  /*if(transparent == 0)*/
	    {
	      tmp = EZ_CreateWidgetXrm(EZ_WIDGET_NORMAL_BUTTON, theFolder,
				       "TheRedDot", "theRedDot",
				       EZ_GRID_CELL_GEOMETRY,   1, 1, 1, 1, /* x, y, w, h */
				       EZ_GRID_CELL_PLACEMENT,  EZ_FILL_BOTH, EZ_CENTER,
				       EZ_BORDER_WIDTH,         0,
				       EZ_BORDER_TYPE,          EZ_BORDER_GROOVE,
				       EZ_BITMAP_FILE,          "rball_s.xpm",
				       EZ_PADX, 0, EZ_PADY,0, EZ_IPADX, 0, EZ_IPADY,0,
				       EZ_CALLBACK,             setBackdropCB, folder,
				       NULL);
	    }
	  /* motion callback, deselect selection in other folder */
	  EZ_AddWidgetCallBack(theFolder, EZ_MOTION_CALLBACK, folderMotionCallback, folder, 0);


	  EZ_WidgetAddDnDDataDecoder(theFolder, ezfmMoveFileByNameAtom, 0,
				     ezfmMoveToDirByName, finfo, NULL, NULL);
	  EZ_WidgetAddDnDDataDecoder(theFolder, ezfmCopyFileByNameAtom, ControlMask,
				     ezfmCopyToDirByName, finfo, NULL, NULL);
	  EZ_WidgetAddDnDDataDecoder(theFolder, ezfmCopyFileByContentAtom, ControlMask,
				     ezfmCopyToDirByContent, finfo, NULL, NULL);
	  EZ_WidgetAddDnDDataDecoder(theFolder, ezfmCopyFileByTarAtom, ControlMask,
				     ezfmCopyToDirByTar, finfo, NULL, NULL);
	  EZ_WidgetAddDnDDataDecoder(theFolder, ezfmLinkFileByNameAtom, ShiftMask,
				     ezfmLinkToDirByName, finfo, NULL, NULL);

          /* mv, cp, ln multiple files (by name only) */
          EZ_WidgetAddDnDDataDecoder(theFolder, ezfmMoveMultipleFilesAtom, 0,
                                     ezfmMoveMultipleFilesD, finfo, NULL, NULL);
          EZ_WidgetAddDnDDataDecoder(theFolder, ezfmCopyMultipleFilesAtom, ControlMask,
                                     ezfmCopyMultipleFilesD, finfo, NULL, NULL);
          EZ_WidgetAddDnDDataDecoder(theFolder, ezfmLinkMultipleFilesAtom, ShiftMask,
                                     ezfmLinkMultipleFilesD, finfo, NULL, NULL);
          /* multiple files */
          EZ_WidgetAddDnDDataEncoder(theFolder, ezfmMoveMultipleFilesAtom, 0,
                                     ezfmEncodeMultipleFileNames, folder, NULL, NULL);
          EZ_WidgetAddDnDDataEncoder(theFolder, ezfmCopyMultipleFilesAtom, ControlMask,
                                     ezfmEncodeMultipleFileNames, folder, NULL, NULL);
          EZ_WidgetAddDnDDataEncoder(theFolder, ezfmLinkMultipleFilesAtom, ShiftMask,
                                     ezfmEncodeMultipleFileNames, folder, NULL, NULL);
	  
	  /* these two are the "special decoders", they setup/clean up a drop transaction */
	  EZ_WidgetAddDnDDataDecoder(theFolder, EZ_DND_DROP_START_ATOM,  0,
				     dirDnDTargetStartFilter, finfo, NULL, NULL);
	  EZ_WidgetAddDnDDataDecoder(theFolder, EZ_DND_DROP_FINISH_ATOM, 0,
				     dirDnDTargetFinishFilter, finfo, NULL, NULL);


          EZ_WidgetAddDnDDataEncoder(theFolder, EZ_DND_DRAG_START_ATOM,  /* drag setup    */
                                     0, ezfmFolderEncodeStartFilter, folder, NULL, NULL);
          EZ_WidgetAddDnDDataEncoder(theFolder, EZ_DND_DRAG_FINISH_ATOM, /* drag clean up */ 
                                     0, ezfmFolderEncodeFinishFilter, folder, NULL, NULL);

	}
      EZ_UnFreezeWidget(frame);
    }
}
/***********************************************************************************
 *
 * OptionEntry callback. If the entry string is a valid pathname for a directory
 * and it differs with the directory name current listed. Update the folder.
 */
static void entryCallback(widget, data)
     EZ_Widget *widget; void *data;
{
  Folder *folder = (Folder *)data;
  if(folder)
    {
      FileInfo *finfo = folder->finfo;
      char  *pathname = finfo->pathname;
      char  *str= EZ_GetEntryString(widget);
      struct stat  statbuf;

      if(str && *str && strcmp(str, pathname))
	{
	  if(EZ_IsGlobPattern(str))
	    {
	      char *oldpath = finfo->pathname;
	      int len = strlen(str);
		  
	      if(finfo->glob == 0) BroadcastFolderOpenCloseded(oldpath, 0);
	      finfo->pathname = (char *)EZ_Realloc(finfo->pathname, (len+1) * sizeof(char));
	      strcpy(finfo->pathname, str);
	      finfo->mtime = 0;
	      finfo->glob = 1;
	      updateFolder(folder, 2);
	    }
	  else if(stat(str, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
	    {
	      Folder  *cfolder = findFolder(str) ;
	      if(cfolder != NULL)
		{
		  EZ_Widget *widget = NULL;
		  if(cfolder->type == ICON_FOLDER)       widget = cfolder->workarea;
		  else if(cfolder->type == ICON_FOLDER_SMALL) widget = cfolder->workareaS;
		  else if(cfolder->type == LIST_FOLDER)  widget = cfolder->flistbox;
		  else if(cfolder->type == TREE_FOLDER)  widget = cfolder->listtree;
		  if(widget)
		    {
		      EZ_RedisplayWidgetTree(widget);
		      EZ_BlinkWidget(widget, 1);
		    }
		  return;
		}
	      else
		{
		  char *oldpath = finfo->pathname;
		  int len = strlen(str);
		  
		  if(finfo->glob == 0) BroadcastFolderOpenCloseded(oldpath, 0);
		  finfo->pathname = (char *)EZ_Realloc(finfo->pathname, (len+1) * sizeof(char));
		  strcpy(finfo->pathname, str);
		  finfo->mtime = 0;
		  finfo->glob = 0;
		  updateFolder(folder, 2);
		  BroadcastFolderOpenCloseded(str, 1);
		  FindFolderOtherClients(str);
		  return;
		}
	    }
	  else 	  /* not a valid directory name or a glob pattern */
	    {
	      EZ_Widget *optEntry = folder->optentry;
	      EZ_Widget *junk, *listbox;
	      EZ_GetOptionalEntryWidgetComponents(optEntry, &junk, &listbox, &junk);
	      EZ_DeleteListBoxString(listbox, str);
	      ezfmWarning(str, "is not a directory");
	    }
	}
    }
}

/**********************************************************************************
 *
 * view radio button callback. Select a type of view: ICON, LIST or TREE
 */
static void rbtnCallback(widget, data)
     EZ_Widget *widget; void *data;
{
  Folder *folder = (Folder *)data;
  if(folder)
    {
      int type = EZ_GetRadioButtonGroupVariableValue(widget);
      createFolderFolder(folder, type);
      updateFolder(folder,2);
      if(folder->bgpixmap != NULL)
	{
	  char tmp[256];
	  EZ_LabelPixmap *pxm = EZ_CreateLabelPixmapFromImageFile(folder->bgpixmap);
	  strcpy(tmp, folder->bgpixmap);
	  setObjBgPixmap(folder, tmp, pxm);
	}
    }
}
/**********************************************************************************
 *
 * When an item is draged to an optional entry, open the dir if needed.
 *
 */
int entryDirNameDecoder(obj, data, msg, len)
     void *obj; void *data; char *msg; int len;
{
  /* printf("Here: msg=[%s], length=%d\n", msg, len);*/
  if(len > PATHNAME_OFFSET)
    {
      EZ_Widget *entry = (EZ_Widget *)obj;
      char *path = msg+PATHNAME_OFFSET;
      /* printf("PATH is: [%s]\n", path);*/
      EZ_SetEntryString(entry, path);
      EZ_CallWidgetCallbacks(entry);
      return(EZ_DND_SUCCESS);
    }
  return(EZ_DND_FAILURE);
}
/**********************************************************************************/
static EZ_TreeNode *myFileNodeCreator(path, data)
     char *path; void *data;
{
  Folder        *folder = (Folder *)data;
  EZ_TreeNode   *node = NULL;
  char          *label, tstr[256];
  EZ_Item       *item;
  int           restore = -1;

  if(path[1] == '\0') label = path;
  else
    {
      int len = strlen(path);
      if(path[len-1] == '/')
	{
	  char *s = path+len-2, *d = tstr+255;
	  *d-- = '\0';
	  while( *s != '/' && s != path)
	    { *d-- = *s--;}
	  label = d+1;
	  restore = len-1;
	  path[restore] = 0;
	}
      else
	{
	  char *s = path+len-1;
	  while( *s != '/' && s != path) s--; s++;
	  label = s;
	}
    }

  item = createFileItem(path, label, folder, NULL);
  if(item) node = EZ_CreateTreeNode(NULL, item);
  if(restore >= 0) path[restore] ='/';

  /**/
  {
    Toplevel  *tp = folder->toplevel;
    EZ_Widget *statuslabel = tp->statuslabel;
    char      statusString[256];
    int       cnt = EZ_GetWidgetIntData(statuslabel) + 1;
    EZ_SetWidgetIntData(statuslabel, cnt);

    if( cnt & 8 )
      {
	sprintf(statusString, "Made %d items ...", cnt);
	EZ_ConfigureWidget(statuslabel, EZ_LABEL_STRING, statusString, NULL);
	XSync(EZ_GetDisplay(), False);    
      }
  }
  /**/
  return(node);
}

/**********************************************************************************/
static void folderMotionCallback(widget, data)
     EZ_Widget *widget; void *data;
{
  Folder    *folder = (Folder *)data;
  if(folder)
    {
      Toplevel  *tp = folder->toplevel;
      Folder    **flds = tp->folder;
      if(flds[0] && flds[1])
	{
	  Folder *other = (folder == flds[0])? flds[1]: flds[0];
	  switch(other->type)
	    {
	    case ICON_FOLDER:
	      {
		EZ_Widget *wa = other->workarea;
		EZ_WorkAreaSelectItem(wa, NULL, NULL);
	      }
	    break;
	    case ICON_FOLDER_SMALL:
	      {
		EZ_Widget *wa = other->workareaS;
		EZ_WorkAreaSelectItem(wa, NULL, NULL);
	      }
	    break;
	    case LIST_FOLDER:
	      {
		EZ_Widget *flb = other->flistbox;
		EZ_FancyListBoxSelectItem(flb, NULL, NULL);
	      }
	    break;
	    case TREE_FOLDER:
	      {
		EZ_Widget *tree = other->listtree;
		EZ_ListTreeWidgetSelectNode(tree, NULL, NULL);
	      }
	    break;
	    default:
	      break;
	    }
	}
      showSelectionStatus(folder);
    }
}
/*****************************************************************/
static void showSelectionStatus(folder)
     Folder *folder;
{
  if(folder)
    {
      Toplevel  *tp = folder->toplevel;
      EZ_Item   *selection = getFolderSelection(folder);
      char      str[256], color[32];
      char      *uclr, *clr = "black";

      if(selection)
	{
	  FileInfo *finfo = EZ_GetItemPtrData(selection);
	  char     *uclr, *path = finfo->pathname;
	  getSpecField(finfo->ezfmData, SPEC_COLOR, color);
	  if(color[0]) clr = color;
	  (void)   getFileShortInfo(path, str);
	}
      else str[0] = '\0';
      EZ_ConfigureWidget(tp->statuslabel, EZ_FOREGROUND, clr, EZ_LABEL_STRING, str,NULL);
    }
}
/**********************************************************************************/
EZ_Item *getFolderSelection(folder)
     Folder *folder;
{
  if(folder)
    {
      switch(folder->type)
	{
	case ICON_FOLDER:
	  return(EZ_GetWorkAreaSelection(folder->workarea));
	  break;
	case ICON_FOLDER_SMALL:
	  return(EZ_GetWorkAreaSelection(folder->workareaS));
	  break;
	case LIST_FOLDER:
	  {
	    EZ_Item   **selRow = EZ_GetFancyListBoxSelection(folder->flistbox);
	    if(selRow) return(selRow[0]);
	  }
	break;
	case TREE_FOLDER:
	  {
	    EZ_TreeNode *node = EZ_GetListTreeWidgetSelection(folder->listtree);
	    if(node) return(EZ_TreeNodeGetItem(node));
	  }
	break;
	default:
	  break;
	}
    }
  return(NULL);
}

/**********************************************************************************/
static void findFolderOtherClientMsgHdlr(msg, data)
     EZ_Message *msg; void *data;
{
  if(msg->messageLength > 0 && msg->senderIsSelf == 0)
    {
      ezfmExecutionErrorI("Another client has an open folder for", 
			  msg->message + strlen(msg->message)+1,
			  "Here are some info about this folder",
			  msg->message);
      EZ_DeleteMessageHandler(None, msg->messageId, data, findFolderOtherClientMsgHdlr);
    }
}

static void FindFolderOtherClients(pathname)
     char *pathname;
{
  struct stat  stat_buf;  
  if(stat(pathname, &stat_buf) >= 0)
    {
      char message[256];
      int  mid = (rand() >> 5)+1;
      /* this msg handler will self destruct in 10 seconds */
      EZ_RegisterMessageHandler(ezfmMsgFolderInqueryAtom, mid+1, NULL, findFolderOtherClientMsgHdlr, 10, 
                                NULL, NULL); 
      finfoEncodeStatInfoAndPathname(pathname, &stat_buf, message);
      EZ_BroadcastMessage(ezfmMsgFolderInqueryAtom, message, 256, mid, mid+1);      
    }
}
/**********************************************************************************/
void entryCanonicalString(entry, data) EZ_Widget *entry; void *data;
{
  char *str = EZ_GetEntryString(entry);
  if(str)
    {
      int plen = strlen(str);
      int glob = EZ_IsGlobPattern(str);
      int olen = plen;

      while(plen > 0 && str[plen-1] == ' ')  plen--;
      if(plen > 1 && glob == 0 && str[plen -1] == '/') plen--;
      if(olen != plen)
	{
	  EZ_EntryEditGotoPosition(entry, plen);
	  EZ_EntryEditKillEndOfLine(entry, 0);
	  EZ_DisplayWidget(entry);
	}
    }
}
/**********************************************************************************/
static void   renameEntryEHandler(w, data, et, xev)
     EZ_Widget *w; void *data; int et; XEvent *xev;
{
  if(xev->type == KeyPress)
    {
      KeySym keysym = XLookupKeysym((XKeyEvent *)xev, 0);
      if(keysym == XK_Tab 
#ifdef 	 XK_KP_Tab
	 || keysym == XK_KP_Tab
#endif
	 ) 
        EZ_HideWidget(w);
    }
  else if(xev->type == FocusOut)
    EZ_SetFocusTo(w);
}

static void renameEntryCb(entry, data) EZ_Widget *entry; void *data;
{
  EZ_Item *item = NULL;
  EZ_Widget *icon = NULL;
  int kind = EZ_GetWidgetIntData(entry);
  FileInfo *finfo = NULL;
  if(kind == 0) 
    {
      item = (EZ_Item *)EZ_GetWidgetPtrData(entry);
      finfo = (FileInfo *)EZ_GetItemPtrData(item);
    }
  else
    {
      icon = (EZ_Widget *) EZ_GetWidgetPtrData(entry);
      finfo = (FileInfo *)EZ_GetWidgetPtrData(icon);
    }
     
  if(finfo)
    {
      char *str = EZ_GetEntryString(entry);
      char *pathname = finfo->pathname;
      char *ptr, tmp[1024];
      strcpy(tmp, pathname);
      ptr = strrchr(tmp, '/');
      if(ptr)
        {
          strcpy(ptr+1, str);
          if(rename(pathname, tmp) == 0) 
            {
              int len = strlen(pathname);
              int nlen = strlen(tmp);
              if(len >= nlen) strcpy(pathname, tmp);
              else
                {
                  (void) EZ_Free(finfo->pathname);
                  finfo->pathname = (char *)EZ_Malloc( (1 + nlen) * sizeof(char));
                  strcpy(finfo->pathname, tmp);
                }
              if(kind == 0) EZ_ConfigureItem(item, EZ_LABEL_STRING, str, 0);
              else EZ_ConfigureWidget(icon, EZ_LABEL_STRING, str,
                                      EZ_BUBBLE_HELP, tmp,  0);
            }
          else
            {
              char *err = (errno >= 0 && errno <sys_nerr)? 
                sys_errlist[errno] : "Unknown error";
              ezfmWarning("Rename File Failed", err);                
            }
        }
    }
  EZ_HideWidget(entry);
}

void popupRenameEntry(widget, x,y, w,h, obj, kind)
     int x,y; void *obj; EZ_Widget *widget;
{
  EZ_Item   *item;
  EZ_Widget *icon;

  if(renameEntry == NULL)
    renameEntry  =   EZ_CreateWidget(EZ_WIDGET_ENTRY,    renameEntry,
                                     EZ_CALLBACK,        renameEntryCb, NULL,
                                     EZ_EVENT_HANDLER,   renameEntryEHandler, NULL,
                                     EZ_BORDER_WIDTH,    1,
                                     EZ_BORDER_TYPE,     EZ_BORDER_SUNKEN,
                                     EZ_PADX,            0,
                                     EZ_PADY,            0,
                                     EZ_HIGHLIGHT_PAD,   1,
                                     EZ_WM_IGNORE,       True,
                                     0);
  if(kind == 0)
    {
      if( (item = (EZ_Item *)obj) )
        {
          char *label = NULL;
          int  jnk, fontId;
          FileInfo *finfo = (FileInfo *)EZ_GetItemPtrData(item);
          if(finfo)
            {
              fontId = getSpecFontId(finfo->ezfmData);
              EZ_GetLabelItemStringInfo(item, &label, &jnk);
              EZ_ConfigureWidget(renameEntry,
                                 EZ_GEOMETRY, x, y-1,w+8,h+2, 
                                 EZ_ENTRY_STRING, label,
                                 EZ_FONT_ID, ezfmFontId[fontId],
                                 EZ_CLIENT_PTR_DATA, item,
                                 EZ_CLIENT_INT_DATA, 0,
                                 0);
              EZ_DisplayWidget(renameEntry);
              EZ_EntryEditBeginOfInput(renameEntry);
              EZ_EntryEditEndOfInput(renameEntry);
              EZ_SetFocusTo(renameEntry);
            }
        }
    }
  else  /* kind = 1; */
    {
      icon = (EZ_Widget *)obj;
      if(icon)
        { 
          char *label;
          int  jnk, fontId;
          FileInfo *finfo = (FileInfo *)EZ_GetWidgetPtrData(icon);
          if(finfo)
            {
              fontId = getSpecFontId(finfo->ezfmData);
              label = EZ_GetWidgetLabelString(icon);
              EZ_ConfigureWidget(renameEntry,
                                 EZ_GEOMETRY, x, y-1,w+8,h+2, 
                                 EZ_ENTRY_STRING, label,
                                 EZ_FONT_ID, ezfmFontId[fontId],
                                 EZ_CLIENT_PTR_DATA, icon,
                                 EZ_CLIENT_INT_DATA, 1,
                                 0);
              EZ_DisplayWidget(renameEntry);
              EZ_EntryEditBeginOfInput(renameEntry);
              EZ_EntryEditEndOfInput(renameEntry);
              EZ_SetFocusTo(renameEntry);
            }
        }
    }
}
/**********************************************************************************/
static void   waFolderEHandler(w, data, et, xev)
     EZ_Widget *w; void *data; int et; XEvent *xev;
{
  static EZ_Item *selection = NULL;
  static Time     btnClickTime = 0;
  static int      sx,sy;

  if(xev->type == ButtonPress)
    {
      if(xev->xbutton.button == EZ_Btn1)
	{
	  Folder *folder = (Folder *)data;	  
	  Toplevel *tp = (Toplevel *)folder->toplevel;
	  sx = xev->xbutton.x;
	  sy = xev->xbutton.y;
          selection = EZ_WorkAreaFindItemAtXY(w, sx, sy);
	  tp->activeFolder = data;
          btnClickTime = xev->xbutton.time;
          EZ_HideWidget(renameEntry);
	}
      else if(xev->xbutton.button == EZ_Btn2)
	{
	  int x = xev->xbutton.x;
	  int y = xev->xbutton.y;
	  EZ_Item *item = EZ_WorkAreaFindItemAtXY(w, x, y);
	  FileInfo *finfo;
	  EZ_Widget *popup;
	  if(item) 
	    {
	      EZ_WorkAreaSelectItem(w, item, NULL);
	      finfo =  (FileInfo *)EZ_GetItemPtrData(item);
	    }
	  else
	    {
	      Folder *folder = (Folder *)data;
	      finfo = folder->finfo;
	    }
	  popup = createPopupFileInfo(finfo);
	  EZ_DoPopupX(w, popup, -1);
	}
    }
  else if(xev->type == ButtonRelease)
    {
      if(xev->xbutton.button == EZ_Btn1)
	{
	  int x = xev->xbutton.x;
	  int y = xev->xbutton.y;
	  EZ_Item *item = EZ_WorkAreaFindItemAtXY(w, x, y);
          Time t = xev->xbutton.time;
          int dx = sx -x;
          int dy = sy -y;
          dx = (dx > 0)? dx: -dx;
          dy = (dy > 0)? dy : -dy;
          if(item && item == selection && (t- btnClickTime) > 500 && dx < 4 && dy < 4)
            {
              int xr,yr,wr,hr, ww,hh,xx,yy;
              EZ_GetLabelItemTextGeometry(item, &xr, &yr, &wr, &hr);
              if(x >= xr && x < xr + wr && y >= yr && y < yr+hr)
                {
                  EZ_GetWidgetAbsoluteGeometry(w, &xx, &yy,&ww, &hh);
                  popupRenameEntry(w,xx+xr,yy+yr, wr, hr,item, 0);
                }
            }
	}  
    }
}

static void   flFolderEHandler(w, data, et, xev)
     EZ_Widget *w; void *data; int et; XEvent *xev;
{
  static EZ_Item *selection = NULL;
  static Time     btnClickTime = 0;

  if(xev->type == ButtonPress)
    {
      if(xev->xbutton.button == EZ_Btn1)
	{
	  Folder *folder = (Folder *)data;	  
	  Toplevel *tp = (Toplevel *)folder->toplevel;
	  int x = xev->xbutton.x;
	  int y = xev->xbutton.y;
          EZ_Item  **sss = EZ_GetFancyListBoxSelection(w);
          if(sss)
            {
              selection = sss[0];
              btnClickTime = xev->xbutton.time;
            }
	  tp->activeFolder = data;
          EZ_HideWidget(renameEntry);
	}
      else if( xev->xbutton.button == EZ_Btn2)
	{
	  int x = xev->xbutton.x;
	  int y = xev->xbutton.y;
	  int row, col;
	  FileInfo *finfo;
	  EZ_Widget *popup;
	  EZ_Item *item = EZ_FancyListBoxFindItemAtXY(w, x,y, &row, &col);
	  if(item)
	    {
	      EZ_FancyListBoxSelectItem(w, item, NULL);
	      finfo =  (FileInfo *)EZ_GetItemPtrData(item);	  
	    }
	  else
	    {
	      Folder *folder = (Folder *)data;
	      finfo = folder->finfo;
	    }
	  popup = createPopupFileInfo(finfo);
	  EZ_DoPopupX(w, popup, -1);
	}
    }
  else if(xev->type == ButtonRelease)
    {
      if(xev->xbutton.button == EZ_Btn1)
	{
	  int x = xev->xbutton.x;
	  int y = xev->xbutton.y;
          EZ_TreeNode *node = EZ_ListTreeFindNodeAtXY(w, x, y);
          Time t = xev->xbutton.time;
          EZ_Item  **sss = EZ_GetFancyListBoxSelection(w);
          EZ_Item *item = NULL;
          if(sss) item = sss[0];
          if(item && item == selection && (t- btnClickTime) > 500)
            {
              int xr,yr,wr,hr, ww,hh,xx,yy;
              EZ_GetLabelItemTextGeometry(item, &xr, &yr, &wr, &hr);
              if(x >= xr && x < xr + wr && y >= yr && y < yr+hr)
                {
                  EZ_GetWidgetAbsoluteGeometry(w, &xx, &yy,&ww, &hh);
                  popupRenameEntry(w,xx+xr,yy+yr, wr, hr,item, 0);
                }
            }  
        }
    }
}
static void   ltFolderEHandler(w, data, et, xev)
     EZ_Widget *w; void *data; int et; XEvent *xev;
{
  static EZ_Item *selection = NULL;
  static Time     btnClickTime = 0;
  
  if(xev->type == ButtonPress)
    {
      if(xev->xbutton.button == EZ_Btn1)
	{
	  Folder *folder = (Folder *)data;	  
	  Toplevel *tp = (Toplevel *)folder->toplevel;
	  int x = xev->xbutton.x;
	  int y = xev->xbutton.y;
          EZ_TreeNode *node = EZ_ListTreeFindNodeAtXY(w, x, y);
          if(node)
            {
              selection = EZ_TreeNodeGetItem(node);
              btnClickTime = xev->xbutton.time;
            }
          else selection = NULL;
          tp->activeFolder = data;
          EZ_HideWidget(renameEntry);
	}
      else if( xev->xbutton.button == EZ_Btn2)
	{
	  int x = xev->xbutton.x;
	  int y = xev->xbutton.y;
	  EZ_TreeNode *node = EZ_ListTreeFindNodeAtXY(w, x, y);
	  FileInfo *finfo;
	  EZ_Widget *popup;
	  EZ_Item   *item;

	  if(node)
	    {
	      EZ_ListTreeWidgetSelectNode(w, node, NULL);
	      item = EZ_TreeNodeGetItem(node);
	      finfo =  (FileInfo *)EZ_GetItemPtrData(item);	  	  
	    }
	  else
	    {
	      Folder *folder = (Folder *)data;
	      finfo = folder->finfo;
	    }
	  popup = createPopupFileInfo(finfo);
	  EZ_DoPopupX(w, popup, -1);
	}
    }
  else if(xev->type == ButtonRelease)
    {
      if(xev->xbutton.button == EZ_Btn1)
	{
	  int x = xev->xbutton.x;
	  int y = xev->xbutton.y;
          EZ_TreeNode *node = EZ_ListTreeFindNodeAtXY(w, x, y);
          EZ_Item *item = NULL;
          Time t = xev->xbutton.time;
          if(node) item  = EZ_TreeNodeGetItem(node);
          if(item && item == selection && (t- btnClickTime) > 500)
            {
              int xr,yr,wr,hr, ww,hh,xx,yy;
              EZ_GetLabelItemTextGeometry(item, &xr, &yr, &wr, &hr);
              if(x >= xr && x < xr + wr && y >= yr && y < yr+hr)
                {
                  EZ_GetWidgetAbsoluteGeometry(w, &xx, &yy,&ww, &hh);
                  popupRenameEntry(w,xx+xr,yy+yr, wr, hr,item, 0);
                }
            }  
        }
    }
}
/**********************************************************************************/
void BroadcastFolderOpenCloseded(pathname, mode) char *pathname; int mode;
{
  struct stat stat_buf;
  if(ezfmDirPixmaps[0] == NULL) return;

  if(stat(pathname, &stat_buf) >= 0)
    {
      char message[256];
      finfoEncodeStatInfoAndPathname(pathname, &stat_buf, message);
      if(mode)  EZ_BroadcastMessage(ezfmMsgFolderOpenedAtom, message, 256, 1, 0);      
      else      EZ_BroadcastMessage(ezfmMsgFolderClosedAtom, message, 256, 2, 0); 
    }
}
/**********************************************************************************/
static EZ_TreeNode *findTreeNode(root,path) EZ_TreeNode *root; char *path;
{
  if(root)
    {
      EZ_Item   *item = EZ_TreeNodeGetItem(root);
      FileInfo  *finfo = (FileInfo *)EZ_GetItemPtrData(item);
      char      *pathname = finfo->pathname;
      if(*path == *pathname && !strcmp(path, pathname))
	return(root);
      /* traverse */
      {
	EZ_TreeNode  *child = EZ_TreeNodeGetChildren(root);
	EZ_TreeNode  *ans  = findTreeNode(child, path);
	if(ans) return(ans);
      }
      {
	EZ_TreeNode  *sib = EZ_TreeNodeGetSibling(root);
	EZ_TreeNode  *ans  = findTreeNode(sib, path);
	if(ans) return(ans);
      }
    }
  return(NULL);
}
/**********************************************************************************/
static void findOpenedFolderOtherClientMsgHdlr(msg, data)
     EZ_Message *msg; void *data;
{
  if(msg->messageLength > 0 && msg->senderIsSelf == 0)
    {
      char *path = msg->message + strlen(msg->message)+1;
      OpenCloseDirItemInFolder(path, 1);
      EZ_DeleteMessageHandler(None, msg->messageId, data, findFolderOtherClientMsgHdlr);
    }
}

void findOpenedFolderOtherClients(path, stbuf) char *path; struct stat  *stbuf;  
{
  char message[256];
  int  mid = (rand() >> 5)+1;
  /* this msg handler will self destruct in 10 seconds */
  EZ_RegisterMessageHandler(ezfmMsgFolderInqueryAtom, mid+1, NULL, findOpenedFolderOtherClientMsgHdlr, 10, 
                            NULL, NULL); 
  finfoEncodeStatInfoAndPathname(path, stbuf, message);
  EZ_BroadcastMessage(ezfmMsgFolderInqueryAtom, message, 256, mid, mid+1);      
}
/**********************************************************************************/
void OpenCloseDirItemInFolder(path, mode)
     char *path;  int mode;
{
  char     *tspec, *ptr;
  Folder   *folder, *folderPtr = folderList;
  char     spath[1024];
  FileInfo *dinfo;
  char     *dirname;

  if(ezfmDirPixmaps[0] == NULL) return;

  tspec = GetFileTypeInfo("/");
  strcpy(spath, path);
  ptr = strrchr(spath,'/');
  if(ptr && ptr != path) *ptr = 0;

  while(folderPtr)
    {
      folder = folderPtr;
      folderPtr = folderPtr->next;
      dinfo = folder->finfo;
      dirname = dinfo->pathname;

      if(folder->blocked) continue;
      folder->blocked++;

      if(!strcmp(spath, dirname)) /* opened/closed dir is an item in folder */
	{
	  switch(folder->type)
	    {
	    case ICON_FOLDER:
	      {
		EZ_Widget *workarea = folder->workarea;
		FileInfo  *finfo;
		EZ_Item   *item, **items;
		int       i, nitems;

		nitems =EZ_GetWorkAreaNumberOfItems(workarea);
		items  =EZ_GetWorkAreaData(workarea);

		for(i = 0; i < nitems; i++)
		  {
		    item = items[i];
		    finfo = (FileInfo *)EZ_GetItemPtrData(item);
		    if(finfo && finfo->ezfmData == tspec)
		      {
			char *iname = finfo->pathname;
			if(!strcmp(iname, path))
			  {
			    if(mode) EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[1], NULL);
			    else     EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[0], NULL);
			    break;
			  }
		      }
		  }
	      }
	    break;
	    case ICON_FOLDER_SMALL:
	      {
		EZ_Widget *workarea = folder->workareaS;
		FileInfo  *finfo;
		EZ_Item   *item, **items;
		int       i, nitems;

		nitems =EZ_GetWorkAreaNumberOfItems(workarea);
		items  =EZ_GetWorkAreaData(workarea);

		for(i = 0; i < nitems; i++)
		  {
		    item = items[i];
		    finfo = (FileInfo *)EZ_GetItemPtrData(item);
		    if(finfo && finfo->ezfmData == tspec)
		      {
			char *iname = finfo->pathname;
			if(!strcmp(iname, path))
			  {
			    if(mode) EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[3], NULL);
			    else     EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[2], NULL);
			    break;
			  }
		      }
		  }
	      }
	    break;
	    case LIST_FOLDER:
	      {
		EZ_Widget *flistbox = folder->flistbox;
		FileInfo  *finfo;
		int       i, nrows;
		EZ_Item   *item;

		nrows = EZ_GetFancyListBoxNumberOfRows(flistbox);
		for(i = 1; i < nrows; i++)
		  {
		    item = EZ_GetFancyListBoxItemUsingIdx(flistbox, i, 0);
		    finfo = (FileInfo *)EZ_GetItemPtrData(item);
		    if(finfo && finfo->ezfmData == tspec)
		      {
			char *iname = finfo->pathname;
			if(!strcmp(iname, path))
			  {
			    if(mode) EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[3], NULL);
			    else     EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[2], NULL);
			    break;
			  }	 
		      }
		  }
	      }
	    break;
	    case TREE_FOLDER:
	      {
		EZ_Widget   *listtree = folder->listtree;
		EZ_TreeNode *root = EZ_GetListTreeWidgetTree(listtree);
		EZ_TreeNode *node = findTreeNode(root,path);
		if(node)
		  {
		    EZ_Item *item = EZ_TreeNodeGetItem(node);
		    if(mode) EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[3], NULL);
		    else     EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[2], NULL);
		  }
	      }
	    default:
	      break;
	    }
	}
      else
	{
	  switch(folder->type)
	    {
	    case ICON_FOLDER:   /* check for .. */
	      {
		int   len = strlen(path);
		int   len1 = strlen(dirname);
		if(len < len1)
		  {
		    char tmp[1024], *ptr;
		    strcpy(tmp, dirname);
		    ptr = strrchr(tmp, '/');
		    if(ptr && ptr - tmp == len && !strncmp(path, tmp, len))
		      {
			EZ_Widget *workarea = folder->workarea;
			FileInfo  *finfo;
			EZ_Item   *item, **items;
			int       i, nitems;
			
			nitems =EZ_GetWorkAreaNumberOfItems(workarea);
			items  =EZ_GetWorkAreaData(workarea);

			for(i = 0; i < nitems && i < 3; i++)
			  {
			    item = items[i];
			    finfo = (FileInfo *)EZ_GetItemPtrData(item);
			    if(finfo && finfo->ezfmData == tspec)
			      {
				char *iname = finfo->pathname;
				if(!strcmp(iname, path))
				  {
				    if(mode) EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[1], NULL);
				    else     EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[4], NULL);
				    break;
				  }
			      }
			  }
		      }
		  }
	      }
	    break;
	    case ICON_FOLDER_SMALL:   /* check for .. */
	      {
		int   len = strlen(path);
		int   len1 = strlen(dirname);
		if(len < len1)
		  {
		    char tmp[1024], *ptr;
		    strcpy(tmp, dirname);
		    ptr = strrchr(tmp, '/');
		    if(ptr && ptr - tmp == len && !strncmp(path, tmp, len))
		      {
			EZ_Widget *workarea = folder->workareaS;
			FileInfo  *finfo;
			EZ_Item   *item, **items;
			int       i, nitems;
			
			nitems =EZ_GetWorkAreaNumberOfItems(workarea);
			items  =EZ_GetWorkAreaData(workarea);

			for(i = 0; i < nitems && i < 3; i++)
			  {
			    item = items[i];
			    finfo = (FileInfo *)EZ_GetItemPtrData(item);
			    if(finfo && finfo->ezfmData == tspec)
			      {
				char *iname = finfo->pathname;
				if(!strcmp(iname, path))
				  {
				    if(mode) EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[3], NULL);
				    else     EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[5], NULL);
				    break;
				  }
			      }
			  }
		      }
		  }
	      }
	    break;
	    case LIST_FOLDER:   /* check for .. */
	      {
		int   len = strlen(path);
		int   len1 = strlen(dirname);
		if(len < len1)
		  {
		    char tmp[1024], *ptr;
		    strcpy(tmp, dirname);
		    ptr = strrchr(tmp, '/');
		    if(ptr && ptr - tmp == len && !strncmp(path, tmp, len))
		      {	      
			EZ_Widget *flistbox = folder->flistbox;
			FileInfo  *finfo;
			int       i, nrows;
			EZ_Item   *item;
			
			nrows = EZ_GetFancyListBoxNumberOfRows(flistbox);
			for(i = 1; i < nrows && i < 3; i++)
			  {
			    item = EZ_GetFancyListBoxItemUsingIdx(flistbox, i, 0);
			    finfo = (FileInfo *)EZ_GetItemPtrData(item);
			    if(finfo && finfo->ezfmData == tspec)
			      {
				char *iname = finfo->pathname;
				if(*iname == *path && !strcmp(iname, path))
				  {
				    if(mode) EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[3], NULL);
				    else     EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[5], NULL);
				    break;
				  }	 
			      }
			  }
		      }
		  }
	      }
	    break;
	    case TREE_FOLDER:   /* check for  ancestors */
	      {
		int   len = strlen(path);
		int   len1 = strlen(dirname);
		if(len < len1)
		  {
		    EZ_Widget   *listtree = folder->listtree;
		    EZ_TreeNode *root = EZ_GetListTreeWidgetTree(listtree);
		    EZ_TreeNode *node = findTreeNode(root,path);
		    if(node)
		      {
			EZ_Item *item = EZ_TreeNodeGetItem(node);
			if(mode) EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[3], NULL);
			else     EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,ezfmDirPixmaps[2], NULL);
		      }
		  }
	      }
	    break;
	    default:
	      break;	    
	    }
	}
      folder->blocked--;
    }

  /* if a folder is closed, check if other copies of ezfm has path open */
  if(mode == 0)
    {
      struct stat  stat_buf;
      if(stat(path, &stat_buf) >= 0)
	findOpenedFolderOtherClients(path, &stat_buf);
    }
}
/**********************************************************************************/
static void updateTreeNode(node)
     EZ_TreeNode *node;
{
  EZ_Item *item;
  if(node && (item = EZ_TreeNodeGetItem(node)) != NULL)
    {
      FileInfo *finfo = (FileInfo *)EZ_GetItemPtrData(item);
      char *pathname = finfo->pathname;
      time_t cmtime = finfo->mtime;
      struct stat statbuf;
      int status = lstat(pathname, &statbuf);
      if(status == 0 && (statbuf.st_ctime != cmtime)) /* outdated */
	{
	  char  *tspec = GetFileTypeInfo(pathname);
	  char  lxpmFile[64], sxpmFile[64], *pixmap_file;
	  char  *clr = "black", color[256];
	  int   status, type, fontId, isDir, plen;

	  /* remove all DnD handlers */
	  EZ_ItemDeleteAllDnDDataDecoders(item);
	  EZ_ItemDeleteAllDnDDataEncoders(item);

	  finfo->ezfmData = tspec;  /* perm string */
	  finfo->mtime = statbuf.st_ctime;
	  /* extract icon pixmap */
	  getSpecPixmap(tspec, lxpmFile, sxpmFile);
	  getSpecColor(tspec, color); if(color[0]) clr = color;
	  fontId = getSpecFontId(tspec);
	  isDir = S_ISDIR(statbuf.st_mode);
	  if(sxpmFile[0])  pixmap_file = sxpmFile;
	  else if(isDir) pixmap_file = "dir_s.xpm";
	  else pixmap_file = "file.xpm";

	  EZ_ConfigureItem(item,
			   EZ_FOREGROUND,        clr,
			   EZ_PIXMAP_FILE,       pixmap_file,
			   EZ_PIXMAP_FILE,       pixmap_file, /* a trick! cache all allocated pixmaps */
			   EZ_FONT_ID,           ezfmFontId[fontId],
			   NULL);
	  if(isDir && ezfmDirPixmaps[0] != NULL)
	    {
	      if(findFolder(pathname) != NULL)
		EZ_ConfigureItem(item, EZ_LABEL_PIXMAP,  ezfmDirPixmaps[3], NULL);
	      else  findOpenedFolderOtherClients(pathname, &statbuf);
	    }
	  /* reinstall DnD handlers */
	  setupDnDForItem(item, finfo,  isDir);
	}
    }
}
/**********************************************************************************/
static void toplevelDestroyCallback(widget, data)
     EZ_Widget *widget; void *data;
{
  Toplevel *tp = (Toplevel *)data;
  if(tp) (void) EZ_Free((void *)tp);
}
/**********************************************************************************
 * trick mbar so the middle button posts the menus also.
 */
static void   mBarEHandler(w, data, et, xev)
     EZ_Widget *w; void *data; int et; XEvent *xev;
{
  if(xev->type == ButtonPress)
    {
      if(xev->xbutton.button == EZ_Btn2)
	{
	  int x = xev->xbutton.x;
	  int y = xev->xbutton.y;
	  if(EZ_OnFrameDragHandle(w, x,y)) postDockingMenu(w);
	  else xev->xbutton.button = EZ_Btn1;
	}
    }
  else if(xev->type == ButtonRelease)
    {
      if(xev->xbutton.button == EZ_Btn2) xev->xbutton.button = EZ_Btn1;
    }
}
/**********************************************************************************/
Folder *ezfmGetFolderList() { return(folderList);}
/**********************************************************************************/
static void startXtermHere(widget, data) EZ_Widget *widget; void *data;
{
  char      command[1024], *xterm, *dftxterm = "xterm";
  Toplevel  *tp;
  EZ_Widget *frame = (EZ_Widget *)data; /* parent frame */
  
  if((xterm = lookupNameFromHashTable(dftxterm)) == NULL) xterm = dftxterm;
  
  if(frame && (tp = (Toplevel *)EZ_GetWidgetPtrData(frame)) != NULL)
    {
      FileInfo *finfo;
      char *pathname, *ptr, ppath[512];
      Folder *folder = tp->activeFolder;
      if(folder == NULL) folder = tp->folder[0];
      finfo = folder->finfo;
      pathname = finfo->pathname;
      ezfmQuotePathname(pathname, ppath);
      if(finfo->glob == 0) sprintf(command, "(cd %s; %s)&", ppath, xterm);
      else
	{
	  char tstr[256];
	  int pos = position_after_last_slash_before_glob_chars(ppath);
	  strncpy(tstr, ppath, pos); 
	  tstr[pos] = 0;
	  sprintf(command, "(cd %s; %s)&", tstr, xterm);
	}
    }
  else sprintf(command, "%s &", xterm);
  executeShCmd(command, NULL, 0, NULL);    
}
/**********************************************************************************/
static void openToolBox(widget, data)   EZ_Widget *widget; void *data;
{
  if(EZ_WidgetIsViewable(ezfmToolBox)) EZ_BlinkWidget(ezfmToolBox, 1);
  else if(EZ_WidgetExist(ezfmToolBox)) EZ_DisplayWidget(ezfmToolBox);
}
/**********************************************************************************/
Folder *getFolderList()
{ return(folderList);}

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

static void   toolBarEHandler(w, data, et, xev)
     EZ_Widget *w; void *data; int et; XEvent *xev;
{
  if(xev->type == ButtonPress && xev->xbutton.button == EZ_Btn2)
    {
      int x = xev->xbutton.x;
      int y = xev->xbutton.y;

      if(EZ_OnFrameDragHandle(w, x,y)) postDockingMenu(w);
    }
}

/**********************************************************************************
 *
 * Docking menubar and toolbar
 */
static void dockingItemCb(EZ_Widget *widget, void *data)
{
  EZ_Widget *frame = (EZ_Widget *)EZ_GetWidgetPtrData(widget);
  if(data) EZ_DetachFrame(frame, 20,0); /* detach */
  else  EZ_DockFrame(frame, 1);  /* dock */
}

static void hidemtbar(EZ_Widget *widget, void *data)
{
  EZ_Widget *frame = (EZ_Widget *)EZ_GetWidgetPtrData(widget);
  if(data) EZ_ActivateChildren(frame);
  else  EZ_DeActivateChildren(frame);
}

static void postDockingMenu(EZ_Widget *widget)
{
  static EZ_Widget *dockingMenu = NULL;
  static EZ_Widget *detach = NULL, *dock = NULL;  
  static EZ_Widget *hide = NULL, *show = NULL;

  if( !EZ_WidgetExist(dockingMenu))
    {
      dockingMenu = EZ_CreateWidgetXrm(EZ_WIDGET_POPUP_MENU, NULL,
				       "DockingMenu", "dockingMenu",
				       EZ_MENU_TEAR_OFF, 0, 
				       EZ_LABEL_STRING, "Docking",
				       0);
      hide  =   EZ_CreateWidget(EZ_WIDGET_MENU_NORMAL_BUTTON, dockingMenu,
				EZ_LABEL_STRING,   "Hide",
				EZ_UNDERLINE,       0,
				EZ_CALLBACK,        hidemtbar, NULL,
				0);
      show  =   EZ_CreateWidget(EZ_WIDGET_MENU_NORMAL_BUTTON, dockingMenu,
				EZ_LABEL_STRING,   "Show",
				EZ_UNDERLINE,       0,
				EZ_CALLBACK,        hidemtbar,dockingMenu,
				0);
      detach =  EZ_CreateWidget(EZ_WIDGET_MENU_NORMAL_BUTTON, dockingMenu,
				EZ_LABEL_STRING,   "Detach",
				EZ_UNDERLINE,       1,
				EZ_CALLBACK,        dockingItemCb, dockingMenu,
				0);
      dock  =   EZ_CreateWidget(EZ_WIDGET_MENU_NORMAL_BUTTON, dockingMenu,
				EZ_LABEL_STRING,   "Dock",
				EZ_UNDERLINE,       0,
				EZ_CALLBACK,        dockingItemCb, NULL,
				0);
    }
  EZ_SetWidgetPtrData(detach, widget);
  EZ_SetWidgetPtrData(dock, widget);
  EZ_SetWidgetPtrData(hide, widget);
  EZ_SetWidgetPtrData(show, widget);
  if(EZ_FrameIsDetached(widget) == 0) { EZ_DisableWidget(dock); EZ_EnableWidget(detach);}
  else { EZ_DisableWidget(detach); EZ_EnableWidget(dock);}
  if(EZ_GetNumberOfActiveChildren(widget) == 0)
    { EZ_DisableWidget(hide); EZ_EnableWidget(show);}
  else  { EZ_DisableWidget(show); EZ_EnableWidget(hide);}
  EZ_DoPopupX(widget, dockingMenu, -1);
}
/*************************************************************************************/
void ConfigureNotifyHandler (EZ_Widget *widget, void *data, int etype, XEvent *xev)
{
  if(transparent && bigPixmap != NULL)
    {
      if(xev->type == ConfigureNotify)
        {
          int x, y,w,h, tox, toy;
          EZ_GetWidgetAbsoluteGeometry(widget, &x,&y,&w,&h);
          EZ_GetWidgetTileOrigin(widget, &tox, &toy);
          if(tox != -x || toy != -y)
            EZ_ConfigureWidget(widget, EZ_TILE_ORIGIN, 1, -x, -y, 0);
        }
    }
}
/*************************************************************************************/
static void redisplayWidget(EZ_Widget *widget, void *data)
{
  if(EZ_GetParentWidget(widget) == NULL && EZ_WidgetIsViewable(widget))
    EZ_DisplayWidget(widget);
}

void  ezfmResetAllBgPixmaps()
{
  EZ_TraverseAllWidgets(redisplayWidget, NULL);
}
/*************************************************************************************/
void ezfmSetFolderSorter(folder, sorter)
     Folder *folder; int sorter;
{
  if(folder)
    {
      int ss = folder->flags;
      if( (ss & SORT_BY_BITS) != sorter)
        {
          int type = folder->type;
          EZ_Item *item=NULL, **srow=NULL; 
          EZ_TreeNode *selnode=NULL;
          switch(type)
            {
            case ICON_FOLDER: 
              item = EZ_GetWorkAreaSelection(folder->workarea);
              break;
            case ICON_FOLDER_SMALL:
              item = EZ_GetWorkAreaSelection(folder->workareaS);
              break;
            case LIST_FOLDER:
              srow = EZ_GetFancyListBoxSelection(folder->flistbox); 
              break;
            case TREE_FOLDER: 
              selnode = EZ_GetListTreeWidgetSelection(folder->listtree);
              break;
            }
          folder->flags = (ss & ~SORT_BY_BITS) | sorter | SORTER_CHANGED;
          updateFolder(folder, 11);
          switch(type)
            {
            case ICON_FOLDER: 
              if(item)EZ_WorkAreaSelectItem(folder->workarea, item, NULL);
              break;
            case ICON_FOLDER_SMALL:
              if(item)EZ_WorkAreaSelectItem(folder->workareaS, item, NULL);
              break;
            case LIST_FOLDER:
              if(srow)EZ_FancyListBoxSelectItem(folder->flistbox, srow[0], NULL);
              break;
            case TREE_FOLDER: 
              if(selnode) EZ_ListTreeWidgetSelectNode(folder->listtree, selnode, NULL);
              break;
            }          
        }
    }
}
/*************************************************************************************/
static int cmpName(a,b) void *a, *b;
{
  EZ_Item **pa = (EZ_Item **)a;
  EZ_Item **pb = (EZ_Item **)b;
  EZ_Item *na = *pa;
  EZ_Item *nb = *pb;

  if(na == NULL) return (-1);
  else if(nb == NULL) return (1);
  else
    {
      char *astr, *bstr; int jnk1, jnk2;
      EZ_GetLabelItemStringInfo(na, &astr, &jnk1);
      EZ_GetLabelItemStringInfo(nb, &bstr, &jnk1);
      return(EZ_CmpStr( &astr, &bstr));
    }
}
static int cmpSize(a,b) void *a, *b;
{
  EZ_Item **pa = (EZ_Item **)a;
  EZ_Item **pb = (EZ_Item **)b;
  EZ_Item *na = *pa;
  EZ_Item *nb = *pb;

  if(na == NULL) return (-1);
  else if(nb == NULL) return (1);
  else
    {
      FileInfo *infoA = (FileInfo *) EZ_GetItemPtrData(na);
      FileInfo *infoB = (FileInfo *) EZ_GetItemPtrData(nb);
      if(infoA->size < infoB->size) return(1);
      else return(-1);
    }
}
static int cmpTime(a,b) void *a, *b;
{
  EZ_Item **pa = (EZ_Item **)a;
  EZ_Item **pb = (EZ_Item **)b;
  EZ_Item *na = *pa;
  EZ_Item *nb = *pb;

  if(na == NULL) return (-1);
  else if(nb == NULL) return (1);
  else
    {
      FileInfo *infoA = (FileInfo *) EZ_GetItemPtrData(na);
      FileInfo *infoB = (FileInfo *) EZ_GetItemPtrData(nb);
      if(infoA->mtime < infoB->mtime) return(1);
      else return(-1);
    }
}

static int cmpNameP(a,b) void *a, *b;
{
  EZ_Item ***pa = (EZ_Item ***)a;
  EZ_Item ***pb = (EZ_Item ***)b;
  EZ_Item **ra =  *pa;
  EZ_Item **rb =  *pb;

  if(ra == NULL) return (-1);
  else if(rb == NULL) return (1);
  else
    {
      EZ_Item *na = ra[0];
      EZ_Item *nb = rb[0];
      char *astr, *bstr; int jnk1, jnk2;
      EZ_GetLabelItemStringInfo(na, &astr, &jnk1);
      EZ_GetLabelItemStringInfo(nb, &bstr, &jnk1);
      return(EZ_CmpStr( &astr, &bstr));
    }
}
static int cmpSizeP(a,b) void *a, *b;
{
  EZ_Item ***pa = (EZ_Item ***)a;
  EZ_Item ***pb = (EZ_Item ***)b;
  EZ_Item **ra =  *pa;
  EZ_Item **rb =  *pb;

  if(ra == NULL) return (-1);
  else if(rb == NULL) return (1);
  else
    {
      EZ_Item *na = ra[0];
      EZ_Item *nb = rb[0];
      FileInfo *infoA = (FileInfo *) EZ_GetItemPtrData(na);
      FileInfo *infoB = (FileInfo *) EZ_GetItemPtrData(nb);
      if(infoA->size < infoB->size) return(1);
      else return(-1);
    }
}
static int cmpTimeP(a,b) void *a, *b;
{
  EZ_Item ***pa = (EZ_Item ***)a;
  EZ_Item ***pb = (EZ_Item ***)b;
  EZ_Item **ra =  *pa;
  EZ_Item **rb =  *pb;

  if(ra == NULL) return (-1);
  else if(rb == NULL) return (1);
  else
    {
      EZ_Item *na = ra[0];
      EZ_Item *nb = rb[0];
      FileInfo *infoA = (FileInfo *) EZ_GetItemPtrData(na);
      FileInfo *infoB = (FileInfo *) EZ_GetItemPtrData(nb);
      if(infoA->mtime < infoB->mtime) return(1);
      else return(-1);
    }
}
static int cmpNodeName(a,b) void *a, *b;
{
  EZ_TreeNode **nap = (EZ_TreeNode **)a;
  EZ_TreeNode **nbp = (EZ_TreeNode **)b;
  EZ_TreeNode *na = *nap;
  EZ_TreeNode *nb = *nbp;

  if(na == NULL) return (-1);
  else if(nb == NULL) return (1);
  else
    {
      EZ_Item *ia = EZ_TreeNodeGetItem(na);
      EZ_Item *ib = EZ_TreeNodeGetItem(nb);
      char    *astr, *bstr; int jnk1, jnk2;
      EZ_GetLabelItemStringInfo(ia, &astr, &jnk1);
      EZ_GetLabelItemStringInfo(ib, &bstr, &jnk1);
      return(EZ_CmpStr( &astr, &bstr));
    }
}
static int cmpNodeSize(a,b) void *a, *b;
{
  EZ_TreeNode **nap = (EZ_TreeNode **)a;
  EZ_TreeNode **nbp = (EZ_TreeNode **)b;
  EZ_TreeNode *na = *nap;
  EZ_TreeNode *nb = *nbp;

  if(na == NULL) return (-1);
  else if(nb == NULL) return (1);
  else
    {
      EZ_Item *ia = EZ_TreeNodeGetItem(na);
      EZ_Item *ib = EZ_TreeNodeGetItem(nb);
      FileInfo *infoA = (FileInfo *) EZ_GetItemPtrData(ia);
      FileInfo *infoB = (FileInfo *) EZ_GetItemPtrData(ib);
      if(infoA->size < infoB->size) return(1);
      else return(-1);
    }
}

static int cmpNodeTime(a,b) void *a, *b;
{
  EZ_TreeNode **nap = (EZ_TreeNode **)a;
  EZ_TreeNode **nbp = (EZ_TreeNode **)b;
  EZ_TreeNode *na = *nap;
  EZ_TreeNode *nb = *nbp;

  if(na == NULL) return (-1);
  else if(nb == NULL) return (1);
  else
    {
      EZ_Item *ia = EZ_TreeNodeGetItem(na);
      EZ_Item *ib = EZ_TreeNodeGetItem(nb);
      FileInfo *infoA = (FileInfo *) EZ_GetItemPtrData(ia);
      FileInfo *infoB = (FileInfo *) EZ_GetItemPtrData(ib);
      if(infoA->mtime < infoB->mtime) return(1);
      else return(-1);
    }
}
/*************************************************************************************/
static void sortIconFolder(widget, sorter, glob, sch) 
     EZ_Widget *widget; int sorter, glob, sch;
{
  EZ_Item **items = EZ_GetWorkAreaData(widget);
  int       nitems= EZ_GetWorkAreaNumberOfItems(widget);
  int       offset = (glob == 0? 1: 0);

  if(sorter == SORT_BY_SIZE)
    qsort(items+offset, nitems-offset, sizeof(EZ_Item *),cmpSize);
  else if(sorter == SORT_BY_TIME)  
    qsort(items+offset, nitems-offset, sizeof(EZ_Item *),cmpTime);
  else if(sch)
    qsort(items+offset, nitems-offset, sizeof(EZ_Item *),cmpName);
}
static void sortListFolder(widget, sorter, glob,sch)
     EZ_Widget *widget; int sorter,glob, sch;
{
  EZ_Item    ***rows = EZ_GetFancyListBoxData(widget);
  int        nrows =  EZ_GetFancyListBoxNumberOfRows(widget);
  int        offset = (glob == 0? 2: 1);
  
  if(sorter == SORT_BY_SIZE)  
    qsort(rows+offset, nrows-offset, sizeof(EZ_Item **), cmpSizeP);
  else if(sorter == SORT_BY_TIME)  
    qsort(rows+offset, nrows-offset, sizeof(EZ_Item **), cmpTimeP);
  else if(sch)
    qsort(rows+offset, nrows-offset, sizeof(EZ_Item **), cmpNameP);
}

static void sortTreeFolder(widget, sorter, glob, sch)
     EZ_Widget *widget; int sorter, glob, sch;
{
  EZ_TreeNode *root = EZ_GetListTreeWidgetTree(widget);

  if(sorter == SORT_BY_SIZE)  EZ_SetDirTreeSorter(root, cmpNodeSize);
  else if(sorter == SORT_BY_TIME) EZ_SetDirTreeSorter(root, cmpNodeTime);
  else EZ_SetDirTreeSorter(root, cmpNodeName);
}
/*************************************************************************************/
static int findNameInArray(name, array, count)
     char *name, **array; int count;
{
  int left = 0;
  int right = count - 1;
  while (left <= right) 
    {
      int i = (left + right) >> 1;
      int test = strcmp(name, array[i]);
      if( test < 0)
        right = i - 1;
      else if( test > 0)
        left = i + 1;
      else  /* match */
        return(i);
    }
  return(-1);
}
/*************************************************************************************/
#undef _FOLDER_C_

