/*********************************************************************
 *
 *            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 _ICONS_C_
#include "ezfm.h"

/***********************************************************************
 *
 *  This is the list of icons
 */
static Icon       *iconList = NULL;  
static EZ_Timer   *updateIconTimer = NULL;
/***********************************************************************/
EZ_Widget *getCreateIcon        MY_ANSIARGS((char *pathname, int x, int y));
EZ_Widget *createToolItemIcon   MY_ANSIARGS((char *pathname, char *tspec, int x, int y));
EZ_Widget *lookupIcon      MY_ANSIARGS((char *pathname));
EZ_Widget *lookupToolIcon  MY_ANSIARGS((char *pathname));
void itemOrIconCallback    MY_ANSIARGS((EZ_Widget *icon, void *data));
void OpenCloseIcon         MY_ANSIARGS((char *pathname, int mode));
void findOpenedIconOtherClients MY_ANSIARGS((char *path, struct stat *stbuf));
void deleteIcon            MY_ANSIARGS((Icon *icon));
Icon      *getIconList     MY_ANSIARGS((void));
/***********************************************************************/
static void iconEHandler MY_ANSIARGS((EZ_Widget *w, void *data, int et, XEvent *xev));
static void toolIconEHandler MY_ANSIARGS((EZ_Widget *w, void *data, int et, XEvent *xev));
static void setupIconDnDHandlers MY_ANSIARGS((EZ_Widget *iconW, FileInfo *finfo, int isDir));
static void updateIconsTimerCB    MY_ANSIARGS((EZ_Timer *timer, void *data));
/***********************************************************************/

EZ_Widget *getCreateIcon(pathname, x,y)
     char      *pathname;
     int       x, y;
{
  EZ_Widget *iconW;
  Icon      *icon;
  if( (iconW = lookupIcon(pathname)) != NULL)
    EZ_SetWidgetPosition(iconW,x,y);
  else
    {
      char      lxpmFile[64], sxpmFile[64], *pixmap_file;
      char      *tspec = GetFileTypeInfo(pathname);     
      char      *label, *clr="black", color[256];
      Icon      *icon;
      FileInfo  *finfo; 
      int       fontId, status, dpyW, dpyH;
      struct stat stat_buf;
      EZ_LabelPixmap *labPixmap;

      icon = (Icon *)EZ_Malloc(sizeof(Icon));
      finfo= (FileInfo *)EZ_Malloc(sizeof(FileInfo));
      memset(finfo, 0, sizeof(FileInfo));

      getSpecPixmap(tspec, lxpmFile, sxpmFile);
      getSpecColor(tspec, color); if(color[0]) clr = color;
      fontId = getSpecFontId(tspec);
      pixmap_file = lxpmFile;
      label = strrchr(pathname, '/');
      if(label) label++; else label = pathname;

      EZ_GetDisplaySize(&dpyW, &dpyH);
      if(x < 0) x = 0;
      if(y < 0) y = 0;
      if(x > dpyW -16) x = dpyW -16;
      if(y > dpyH -16) y = dpyH -16;

      labPixmap = EZ_CreateLabelPixmapFromXpmFile(pixmap_file);
      if(!labPixmap) labPixmap = EZ_CreateLabelPixmapFromXpmFile("unknown.xpm");

      iconW= EZ_CreateWidgetXrm(EZ_WIDGET_ICON,     NULL,
				"FileIcon",         "fileIcon",
				EZ_ORIENTATION,     EZ_VERTICAL_CENTER, 
				EZ_LABEL_PIXMAP,    labPixmap,
				EZ_LABEL_STRING,    label,
				EZ_CLIENT_PTR_DATA, finfo,
				EZ_CALLBACK,        itemOrIconCallback, finfo,
				EZ_EVENT_HANDLER,   iconEHandler, finfo,
				EZ_FONT_ID,         ezfmFontId[fontId],
				EZ_SHAPED_WINDOW,   1,
				EZ_LABELED_ICON,    1,  /* fix it later */
				EZ_FOREGROUND,     clr,
				EZ_BUBBLE_HELP,     pathname,
				EZ_BORDER_TYPE,     EZ_BORDER_UP,
				EZ_BORDER_WIDTH,    1,
				EZ_IPADX,           2,
				EZ_IPADY,           2, 
				EZ_X,               x,
				EZ_Y,               y,
                                EZ_BG_PIXMAP,       bigPixmap,                                
				NULL);
      
      status = stat(pathname, &stat_buf);
      if(ezfmDirPixmaps[0] != NULL && status >= 0 && S_ISDIR(stat_buf.st_mode))
	{
	  if(findFolder(pathname) != NULL)
	    EZ_ConfigureWidget(iconW,   EZ_LABEL_PIXMAP,  ezfmDirPixmaps[1],  NULL);
	  else  findOpenedIconOtherClients(pathname, &stat_buf);
	}
      
      /* cross link */
      finfo->ezfmData = tspec;  /* perm string */
      finfo->pathname = (char *)EZ_Malloc( (1 + strlen(pathname)) * sizeof(char));
      strcpy(finfo->pathname, pathname);	  
      finfo->type = ICON;
      finfo->obj = icon;
      finfo->host = NULL;
      finfo->mtime = (status == 0? stat_buf.st_ctime : 0);
      
      /* insert icon to the icon list */
      icon->icon = iconW;
      icon->finfo = finfo;
      icon->isTool = 0;
      icon->next = iconList;
      iconList = icon;
      
      /* dnd stuff */
      setupIconDnDHandlers(iconW, finfo, (status==0 && S_ISDIR(stat_buf.st_mode)));
    }
  if(updateIconTimer == NULL)
    updateIconTimer = EZ_CreateTimer(5, 0, -1, updateIconsTimerCB, NULL, 0);

  return(iconW);
}
/******************************************************************************/
static void setupIconDnDHandlers(iconW, finfo, isDir)
     EZ_Widget *iconW; FileInfo *finfo; int isDir;
{
  if(iconW)
    {
      EZ_WidgetAddDnDDataEncoder(iconW, EZ_DND_DRAG_INIT_ATOM, 
				 0, ezfmSetDragIconEncoder, finfo, NULL, NULL);

      /* 
       * When an item is droped to a dropsite, we append pathname
       * and stat info to the initial handshaking message. The dropsite
       * will decide which target it wants. We do this to avoid uncessary
       * conversion for local files.
       */
	EZ_WidgetAddDnDDataEncoder(iconW, EZ_DND_DRAG_START_ATOM,  /* drag setup    */
				 0, ezfmIIEncodeStartFilter, finfo, NULL, NULL);
	EZ_WidgetAddDnDDataEncoder(iconW, EZ_DND_DRAG_FINISH_ATOM, /* drag clean up */ 
				 0, ezfmIIEncodeFinishFilter, finfo, NULL, NULL);

	/*
	 * Normal Encoders
	 */
	/* encode filename, content and tared content */
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmFileNameAtom, 0, 
				 ezfmEncodeFileName, finfo, NULL, NULL);
	if(!isDir)
	  EZ_WidgetAddDnDDataEncoder(iconW, ezfmFileContentAtom, 0,
				     ezfmEncodeFileContent, finfo,  NULL, NULL);
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmFileTaredContentAtom, 0,
				 ezfmEncodeTaredFileContent, finfo, NULL, NULL);

	EZ_WidgetAddDnDDataEncoder(iconW, ezfmFileInfoAtom, 0,
				 ezfmEncodeFileInfo, finfo, NULL, NULL);


	/* move file (by name only) */
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmMoveFileByNameAtom, 0, 
				 ezfmEncodeFileName, finfo, NULL, NULL);

	/* copy file */
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmCopyFileByNameAtom, ControlMask,
				 ezfmEncodeFileName, finfo, NULL, NULL);
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmCopyFileByContentAtom, ControlMask,
				 ezfmEncodeFileContent, finfo, NULL, NULL);
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmCopyFileByTarAtom, ControlMask,
				 ezfmEncodeTaredFileContent, finfo, NULL, NULL);  
	/* link file */
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmLinkFileByNameAtom, ShiftMask,
				 ezfmEncodeFileName, finfo, NULL, NULL);

	/* tool execution on mainitem */

	EZ_WidgetAddDnDDataDecoder(iconW, ezfmToolExecutionAtom, 0,
				   ezfmDecodeToolInfo, finfo, NULL, NULL);
      
	/*
	 * decoders
	 */
	if(isDir)
	  {
	    /*
	     * For directory items, the setup does two things if drag src
	     * is a local file:
	     *  1. sanity check, abort drop if src is parent or drop to its current dir;
	     *  2. eliminate all targets except FILE_NAME.
	     */
	    EZ_WidgetAddDnDDataDecoder(iconW, EZ_DND_DROP_START_ATOM, /* drop setup    */
				       0, dirDnDTargetStartFilter, finfo, NULL, NULL);
	    EZ_WidgetAddDnDDataDecoder(iconW, EZ_DND_DROP_FINISH_ATOM,/* drag clean up */
				       0,dirDnDTargetFinishFilter, finfo, NULL, NULL);

	    /*
	       * Normal Decoders
	       */
	      /* move file (by name only) */
	    EZ_WidgetAddDnDDataDecoder(iconW, ezfmMoveFileByNameAtom, 0,
				       ezfmMoveToDirByName, finfo, NULL, NULL);

	    /* copy file */
	    EZ_WidgetAddDnDDataDecoder(iconW, ezfmCopyFileByNameAtom, ControlMask,
				       ezfmCopyToDirByName, finfo, NULL, NULL);
	    EZ_WidgetAddDnDDataDecoder(iconW, ezfmCopyFileByContentAtom, ControlMask,
				       ezfmCopyToDirByContent, finfo, NULL, NULL);
	    EZ_WidgetAddDnDDataDecoder(iconW, ezfmCopyFileByTarAtom, ControlMask,
				       ezfmCopyToDirByTar, finfo, NULL, NULL);
	      
	    /* link file */	      
	    EZ_WidgetAddDnDDataDecoder(iconW, ezfmLinkFileByNameAtom, ShiftMask,
				       ezfmLinkToDirByName, finfo, NULL, NULL);


            /* move multiple files (by name only) */
            EZ_WidgetAddDnDDataDecoder(iconW, ezfmMoveMultipleFilesAtom, 0,
                                       ezfmMoveMultipleFilesD, finfo, NULL, NULL);
            /* copy multiple files (by name only) */
            EZ_WidgetAddDnDDataDecoder(iconW, ezfmCopyMultipleFilesAtom, ControlMask,
                                       ezfmCopyMultipleFilesD, finfo, NULL, NULL);
            /* link multiple file */	      
            EZ_WidgetAddDnDDataDecoder(iconW, ezfmLinkMultipleFilesAtom, ShiftMask,
                                       ezfmLinkMultipleFilesD, finfo, NULL, NULL);
	  }
    }
}
/**************************************************************************************/
static void   iconEHandler(w, data, et, xev)
     EZ_Widget *w; void *data; int et; XEvent *xev;
{
  EXTERN EZ_Widget *renameEntry;
  static Time btnClickTime = 0;
  static EZ_Widget *selection = NULL;
  static int sx, sy;

  if(xev->type == ButtonPress)
    {
      if(xev->xbutton.button == EZ_Btn1)
	{
          int ww, hh;
          btnClickTime = xev->xbutton.time;
          selection = w;
          EZ_GetWidgetAbsoluteGeometry(w, &sx, &sy,&ww, &hh);                    
          EZ_HideWidget(renameEntry);
	}
      else if(xev->xbutton.button == EZ_Btn2)
        {
          FileInfo *finfo = (FileInfo *)data;
          EZ_Widget *popup;
          if(finfo)
            {
              popup = createPopupFileInfo(finfo);
              EZ_DoPopupX(w,popup, -1);
            }
        }
    }
  else  if(xev->type == ButtonRelease)
    {
      if(xev->xbutton.button == EZ_Btn1)
	{
	  int xx, yy, ww, hh, dx, dy;
          Time t = xev->xbutton.time;
          EZ_GetWidgetAbsoluteGeometry(w, &xx, &yy,&ww, &hh);          
          dx = sx -xx; 
          dy = sy -yy;
          dx = (dx > 0)? dx: -dx;
          dy = (dy > 0)? dy: -dy;
          if(w == selection && (t- btnClickTime) > 500 && dx < 4 && dy < 4)
            {
              int xr,yr,wr,hr;
              EZ_GetIconTextGeometry(w, &xr, &yr, &wr, &hr);
              popupRenameEntry(w,xx+xr,yy+yr, wr, hr,w, 1);
            }
	}        
    }
}
/**************************************************************************/
Icon *getIconList()
{
  return(iconList);
}
/**************************************************************************
 *
 *  Double click action on icons.
 */
void itemOrIconCallback(obj, data)
     void *obj; void *data;
{
  FileInfo *finfo = (FileInfo *)data;
  ezfmDoSomething(finfo);
}

/***********************************************************************
 *
 *  Icon management routines.  Icons are maintained in a list.
 *
 ***********************************************************************/
EZ_Widget *lookupIcon(pathname)
     char *pathname;
{
  if(pathname)
    {
      Icon *ptr = iconList;
      while(ptr)
	{
	  EZ_Widget *iconWidget = ptr->icon;
	  FileInfo *finfo = ptr->finfo;
	  if(!strcmp(pathname, finfo->pathname)) 
	    return(ptr->icon);
	  ptr = ptr->next;
	}
    }
  return(NULL);
}

EZ_Widget *lookupToolIcon(pathname)
     char *pathname;
{
  if(pathname)
    {
      Icon *ptr = iconList;
      while(ptr)
	{
	  FileInfo *finfo = ptr->finfo;
	  if( ptr->isTool && !strcmp(pathname, finfo->pathname)) 
	    return(ptr->icon);
	  ptr = ptr->next;
	}
    }
  return(NULL);
}

/********************************************************
 *
 * remove icon from the icon list.
 */
void deleteIcon(icon) Icon *icon;
{
  if(icon)
    {
      FileInfo *finfo = NULL; 
      EZ_Widget *iconW = NULL;
      Icon *next, *ptr = iconList;
      if(ptr == icon)
	{
	  iconList = ptr->next;
          finfo = ptr->finfo;
          iconW = ptr->icon;
	  (void)EZ_Free(ptr);
	}
      else
	{
	  next = ptr->next;
	  while(next)
	    {
	      if(next == icon)
		{
		  ptr->next = next->next;
                  finfo = next->finfo;
                  iconW = next->icon;
		  EZ_Free(next);
                  break;
		}
	      ptr = next;
	      next = next->next;
	    }
	}
      if(finfo) { (void)EZ_Free(finfo->pathname); (void)EZ_Free(finfo);}
      EZ_DestroyWidget(iconW);
    }
}
/**************************************************************************/
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;
      OpenCloseIcon(path, 1);
      EZ_DeleteMessageHandler(None, msg->messageId, data, findOpenedFolderOtherClientMsgHdlr);
    }
}

void findOpenedIconOtherClients(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 OpenCloseIcon(pathname, mode)
     char *pathname;  int mode;
{
  EZ_Widget *iconW;
  Icon      *icon;
  if( (iconW = lookupIcon(pathname)) != NULL)
    {
      if(mode) EZ_ConfigureWidget(iconW, EZ_LABEL_PIXMAP,ezfmDirPixmaps[1], NULL);
      else     EZ_ConfigureWidget(iconW, EZ_LABEL_PIXMAP,ezfmDirPixmaps[0], NULL);
      /* if a folder is closed, check if other copies of ezfm has path open */
      if(mode == 0)
	{
	  struct stat  stat_buf;
	  if(stat(pathname, &stat_buf) >= 0)
	    findOpenedIconOtherClients(pathname, &stat_buf);
	}
    }
}
/**************************************************************************************/
static void updateIconsTimerCB(timer, data)
     EZ_Timer *timer; void *data;
{
  Icon *next, *ptr = iconList;

  while(ptr)
    {
      EZ_Widget *iconW = ptr->icon;
      FileInfo *finfo = ptr->finfo;

      char     *pathname = finfo->pathname;
      struct stat stat_buf;
      int    status;

      next = ptr->next;

      if(ptr->blocked <= 0) 
	{
	  if(stat(pathname, &stat_buf) < 0)
            { deleteIcon(ptr); return;}
	  else
	    {
	      if(ptr->isTool == 0) /* tool */
		{
		  if(finfo->mtime != stat_buf.st_ctime)
		    {
		      char      lxpmFile[64], sxpmFile[64], *pixmap_file;
		      char      *tspec = GetFileTypeInfo(pathname);     
		      char      *label, *clr="black", color[256];
		      int       fontId;

		      /* remove all DnD handlers */
		      EZ_WidgetDeleteAllDnDDataEncoders(iconW);
		      EZ_WidgetDeleteAllDnDDataDecoders(iconW);

		      finfo->ezfmData = tspec;
		      finfo->mtime = stat_buf.st_ctime;
		      getSpecPixmap(tspec, lxpmFile, sxpmFile);
		      getSpecColor(tspec, color); if(color[0]) clr = color;
		      fontId = getSpecFontId(tspec);

		      EZ_ConfigureWidget(iconW,
					 EZ_BITMAP_FILE,    lxpmFile,
					 EZ_FONT_ID,         ezfmFontId[fontId],
					 EZ_FOREGROUND,     clr,
					 NULL);

		      if(ezfmDirPixmaps[0] != NULL && S_ISDIR(stat_buf.st_mode))
			{
			  if(findFolder(pathname) != NULL)
			    EZ_ConfigureWidget(iconW,   EZ_LABEL_PIXMAP,  ezfmDirPixmaps[1],  NULL);
			  else  findOpenedIconOtherClients(pathname, &stat_buf);
			}
	      
		      /* dnd stuff */
		      setupIconDnDHandlers(iconW, finfo, S_ISDIR(stat_buf.st_mode));
		      EZ_DisplayWidget(iconW);
		    }
		}
	    }
	}
      ptr = next;
    }
}
/***************************************************************************************
 *
 *  ToolIcon behave differently. We also make it look differently.
 */
EZ_Widget *createToolItemIcon(pathname, tspec, x,y)
     char      *pathname; char *tspec;
     int       x, y;
{
  EZ_Widget *iconW, *nwlabel;
  Icon      *icon;
  if( (iconW = lookupToolIcon(pathname)) != NULL)
    EZ_SetWidgetPosition(iconW,x,y);
  else
    {
      char      lxpmFile[64], sxpmFile[64], *pixmap_file;
      char      *label, *clr="black", color[256], action[256];
      Icon      *icon;
      FileInfo  *finfo; 
      int       fontId, status, dpyW, dpyH;
      struct stat stat_buf;
      EZ_LabelPixmap *labPixmap;

      icon = (Icon *)EZ_Malloc(sizeof(Icon));
      finfo= (FileInfo *)EZ_Malloc(sizeof(FileInfo));
      memset(finfo, 0, sizeof(FileInfo));

      getSpecPixmap(tspec, lxpmFile, sxpmFile);
      getSpecColor(tspec, color); if(color[0]) clr = color;
      fontId = getSpecFontId(tspec);
      pixmap_file = lxpmFile;
      label = strrchr(pathname, '/');
      if(label) label++; else label = pathname;

      EZ_GetDisplaySize(&dpyW, &dpyH);
      if(x < 0) x = 0;
      if(y < 0) y = 0;
      if(x > dpyW -16) x = dpyW -16;
      if(y > dpyH -16) y = dpyH -16;

      labPixmap = EZ_CreateLabelPixmapFromXpmFile(lxpmFile);
      if(!labPixmap) labPixmap = EZ_CreateLabelPixmapFromXpmFile("unknown.xpm");

      iconW= EZ_CreateWidgetXrm(EZ_WIDGET_ICON,     NULL,
				"ToolIcon",         "toolIcon",
				EZ_ORIENTATION,     EZ_VERTICAL_CENTER, 
				EZ_LABEL_PIXMAP,    labPixmap,
				EZ_LABEL_STRING,    label,
				EZ_CLIENT_PTR_DATA, finfo,
				EZ_CALLBACK,        toolItemOrIconCB, finfo,
				EZ_FONT_ID,         ezfmFontId[fontId],
				EZ_FOREGROUND,     clr,
				EZ_BUBBLE_HELP,     pathname,
				EZ_SHAPED_WINDOW,   1,
				EZ_LABELED_ICON,    1,
				EZ_BORDER_TYPE, 2, EZ_BORDER_WIDTH,2,
				EZ_IPADX,           0,
				EZ_IPADY,           0, 
				EZ_X,               x,
				EZ_Y,               y,
                                EZ_BG_PIXMAP,          bigPixmap, 
				NULL);
      EZ_AddEventHandler(iconW, toolIconEHandler, finfo,       1);
      EZ_AddEventHandler(iconW,  ConfigureNotifyHandler, NULL, 1);
      
      status = stat(pathname, &stat_buf);
      /* cross link */
      finfo->ezfmData = tspec;  
      finfo->pathname = (char *)EZ_Malloc( (1 + strlen(pathname)) * sizeof(char));
      strcpy(finfo->pathname, pathname);	  
      finfo->type = ICON;
      finfo->obj = icon;
      finfo->host = NULL;
      finfo->mtime = (status == 0? stat_buf.st_ctime : 0);
      
      /* insert icon to the icon list */
      icon->icon = iconW;
      icon->next = iconList;
      icon->finfo = finfo;
      iconList = icon;
      icon->isTool = 1;


      EZ_WidgetAddDnDDataEncoder(iconW, EZ_DND_DRAG_INIT_ATOM,  /* drag initialization  */
				 0, ezfmSetDragIconEncoder, finfo, NULL, NULL);

      /* 
       * When an item is droped to a dropsite, we append pathname
       * and stat info to the initial handshaking message. The dropsite
       * will decide which target it wants. We do this to avoid uncessary
       * conversion for local files.
       */
	EZ_WidgetAddDnDDataEncoder(iconW, EZ_DND_DRAG_START_ATOM,  /* drag setup    */
				   0, ezfmIIEncodeStartFilter, finfo, NULL, NULL);
	/*
	 * Normal Encoders
	 */
	/* encode filename, content and tared content */
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmFileNameAtom, 0, 
				   ezfmEncodeFileName, finfo, NULL, NULL);
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmFileInfoAtom, 0,
				   ezfmEncodeFileInfo, finfo, NULL, NULL);

	/* DnD action: what to do if item can see the drag in its host's local file system */
	getSpecField(tspec, SPEC_DROP_BY_NAME_ACTION, action);
	if(action[0] != '\0')
	  EZ_WidgetAddDnDDataDecoder(iconW, ezfmFileNameAtom, 0,
				     toolExecByName, finfo, NULL, NULL);
	/* DnD action: what to do if item can't see the drag in its host's local file system */
	getSpecField(tspec, SPEC_DROP_BY_CONTENT_ACTION, action);
	if(action[0] != '\0')
	  EZ_WidgetAddDnDDataDecoder(iconW, ezfmFileContentAtom, 0,
				     toolExecByContent, finfo, NULL, NULL);
	
	/* DnD action: what to do if item is draged and droped on an item/icon */
	EZ_WidgetAddDnDDataEncoder(iconW, ezfmToolExecutionAtom, 0,
				   ezfmEncodeToolInfo, finfo, NULL, NULL);

    }
  return(iconW);
}
/***************************************************************************/
static void   toolIconEHandler(w, data, et, xev)
     EZ_Widget *w; void *data; int et; XEvent *xev;
{
  if(xev->type == ButtonPress && xev->xbutton.button == EZ_Btn2)
    {
      FileInfo *finfo = (FileInfo *)data;
      EZ_Widget *popup;
      if(finfo)
	{
	  popup = createPopupFileInfo(finfo);
	  EZ_DoPopupX(w, popup, -1);
	}
    }
}
/***************************************************************************/

#undef _ICONS_C_
