/*
** XmgFancy.c for  in 
** 
** Made by vianney rancurel
** Login   <vianney@epita.fr>
** 
** Started on  Wed Aug 25 14:14:56 1999 vianney rancurel
** Last update Thu Oct 28 20:22:32 1999 
*/
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xatom.h>
#include <X11/Xmu/Xmu.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Toggle.h>
#include "TextField.h"
#include "XmgI.h"
#include "XmgMacro.h"
#include "Xmg.h"
#include "XmgDict.h"
#include "XmgPulldown.h"
#include "XmgFancyI.h"
#include "XmgFancyP.h"

typedef int			(*t_draw_string_proc) P((Display *display,
							 Drawable d,
							 GC gc,
							 int x,
							 int y,
							 _Xconst char *string,
							 int length));

typedef VOID_FUNC			(*t_cmd_proc) P((Widget w,
							 t_vec *args));

typedef struct				s_cmd
{
  char					*name;
  t_cmd_proc				proc;	
} t_cmd;

typedef enum				s_elt_type
{
  ELT_BR,
  ELT_STR,
  ELT_NOP,
  ELT_TABLE,
  ELT_ROW,
  ELT_CELL,
  ELT_EMPTY_CELL,
  ELT_CODE,
  ELT_NO_CODE,
  ELT_LINK,
  ELT_ROOT,
  ELT_FORM,
  ELT_INPUT,
  ELT_SELECT,
  ELT_OPTION,
  ELT_B,
  ELT_NO_B,
  ELT_I,
  ELT_NO_I,
  ELT_SMALL,
  ELT_NO_SMALL,
  ELT__TINY,
  ELT_NO__TINY,
  ELT_IMG,
  ELT_HR,
  ELT_HTML,
  ELT_H1,
  ELT_NO_H1,
  ELT_H2,
  ELT_NO_H2,
  ELT__CIRCLE
} t_elt_type;

typedef struct		s_elt 
{
  t_elt_type		type;		/* Type of elt			*/
  int			idx;		/* Index in container->sub_elts	*/
  int			colspan;	/* Used to compute cell widths	*/
  int			percent;	/* Used to comp. cell or table widths*/
  int			jump;		/* Jump offset on line-breaks	*/
  int			align;		/* Align parameter, i.e. ALIGN_CENTER*/
  int			input_type;	/* Valid if elt is ELT_INPUT	*/
  Widget		self;		/* Ref. to fancy widget		*/
  Widget		widget;		/* Valid if elt has a widget	*/
  FancyImgType		img_type;	/* Specifies pixmap or XImage*	*/
  Pixmap		pixmap;		/* Valid according to img_type	*/
  XImage		*ximage;	/* Valid according to img_type	*/
  Boolean		img_inited;	/* True if img has been computed */
  Boolean		displayable;	/* True is elt is visual	*/
  Boolean		computable;	/* False is elt has no size, i.e.FORM*/
  int			highlight_pos;	/* Pos. of highlight in str.	*/
  int			highlight_len;	/* Len. of highlight in str.	*/
  Boolean		selected;	/* Valid for "option" elts	*/
  Boolean		checked;	/* Valid for checkboxes and radios */
  Boolean		title;		/* True if str is a title	*/
  Boolean		mapped;		/* True if elt->widget is mapped */
  Position		x;		/* Absolute x			*/
  Position		y;		/* Absolute y			*/
  Position		relative_x;	/* Relative x (to container)	*/
  Position		relative_y;	/* Relative y (to container)	*/
  Position		cursor_x;	/* Current (relative) cursor x	*/
  Position		cursor_y;	/* Current (relative) cursor x	*/
  Dimension		width;		/* Value computed in layout	*/
  Dimension		fixed_width;	/* Fixed value used in layout	*/
  Dimension		height;		/* Value computed in layout	*/
  Dimension		min_width;	/* Value computed in layout     */
  Dimension		min_height;	/* Value computed in layout	*/
  Dimension		cellspacing;	/* Spaces between cells		*/
  Dimension		cellpadding;	/* Top/left margin inside cell	*/
  Dimension		border;		/* Value used in layout		*/
  Dimension		depth;		/* Value used by images		*/
  t_vec			*sub_elts;	/* Infinite vector of sub-elts	*/
  struct s_elt		*table;		/* Table ref. if elt is a row	*/
  struct s_elt		*tr;		/* Row ref. if elt is a cell	*/
  struct s_elt		*current_row;	/* Current row stored by table	*/
  struct s_elt		*current_cell;	/* Current cell stored by table	*/
  struct s_elt		*th;		/* Ref. to first row stored by table */
  struct s_elt		*form;		/* Ref. to form stored by inputs */
  struct s_elt		*current_option;/* Current option stored by select */
  XFontStruct		*prev_xfs;	/* Previous XFS stored for reset */
  XFontStruct		*current_xfs;	/* Current XFS (should be a stack?) */
  XFontStruct		*xfs;		/* Computed elt XFS (acc. to context)*/
  Pixel			bgcolor;	/* Fixed or inherited background */
  Pixel			fgcolor;	/* Fixed foreground		*/
  char			*href;		/* Valid if elt is an anchor	*/
  char			*str;		/* Valid if elt is a str or a link */
  int			len;		/* Valid if elt is a str or a link */
  char			*name;		/* Valid if elt is input or select */
  char			*_name;		/* Valid if elt is a table	*/
  char			*value;		/* Valid if elt is input or select */
  char			*action;	/* Valid if elt is a form	*/
  char			*src;		/* Valid if elt is an img	*/
} t_elt;

typedef struct				s_amp_esc
{
  char					*tag;
  int					value;	
} t_amp_esc;

#define ALIGN_NONE			0 
#define ALIGN_CENTER			1 
#define ALIGN_RIGHT			2

#define INPUT_TYPE_DEFAULT		0 
#define INPUT_TYPE_SUBMIT		1 
#define INPUT_TYPE_HIDDEN		2 
#define INPUT_TYPE_RESET		3 
#define INPUT_TYPE_CHECKBOX		4 
#define INPUT_TYPE_RADIO		5 

#define WIDTH_STR			"width="
#define COLSPAN_STR			"colspan="
#define BORDER_STR			"border="
#define BGCOLOR_STR			"bgcolor="
#define HREF_STR			"href="
#define ALIGN_STR			"align="
#define LINK_STR			"link="
#define VLINK_STR			"vlink="
#define TEXT_STR			"text="
#define BACKGROUND_STR			"background="
#define TYPE_STR			"type="
#define NAME_STR			"name="
#define VALUE_STR			"value="
#define SELECTED_STR			"selected"
#define CHECKED_STR			"checked"
#define CELLSPACING_STR			"cellspacing="
#define CELLPADDING_STR			"cellpadding="
#define ACTION_STR			"action="
#define SRC_STR				"src="
#define _NAME_STR			"_name="

/* FROM LIBHTMLW */
static t_amp_esc			amp_escs[] =
{
  {"lt",				'<'},
  {"LT",				'<'},
  {"gt",				'>'},
  {"GT",				'>'},
  {"amp",				'&'},
  {"AMP",				'&'},
  {"quot",				'\"'},
  {"QUOT",				'\"'},
  {"nbsp",				'\240'},
  {"iexcl",				'\241'},
  {"cent",				'\242'},
  {"pound",				'\243'},
  {"curren",				'\244'},
  {"yen",				'\245'},
  {"brvbar",				'\246'},
  {"sect",				'\247'},
  {"uml",				'\250'},
  {"copy",				'\251'},
  {"ordf",				'\252'},
  {"laquo",				'\253'},
  {"not",				'\254'},
  {"shy",				'\255'},
  {"reg",				'\256'},
  {"hibar",				'\257'},
  {"deg",				'\260'},
  {"plusmn",				'\261'},
  {"sup2",				'\262'},
  {"sup3",				'\263'},
  {"acute",				'\264'},
  {"micro",				'\265'},
  {"para",				'\266'},
  {"middot",				'\267'},
  {"cedil",				'\270'},
  {"sup1",				'\271'},
  {"ordm",				'\272'},
  {"raquo",				'\273'},
  {"frac14",				'\274'},
  {"frac12",				'\275'},
  {"frac34",				'\276'},
  {"iquest",				'\277'},
  {"Agrave",				'\300'},
  {"Aacute",				'\301'},
  {"Acirc",				'\302'},
  {"Atilde",				'\303'},
  {"Auml",				'\304'},
  {"Aring",				'\305'},
  {"AElig",				'\306'},
  {"Ccedil",				'\307'},
  {"Egrave",				'\310'},
  {"Eacute",				'\311'},
  {"Ecirc",				'\312'},
  {"Euml",				'\313'},
  {"Igrave",				'\314'},
  {"Iacute",				'\315'},
  {"Icirc",				'\316'},
  {"Iuml",				'\317'},
  {"ETH",				'\320'},
  {"Ntilde",				'\321'},
  {"Ograve",				'\322'},
  {"Oacute",				'\323'},
  {"Ocirc",				'\324'},
  {"Otilde",				'\325'},
  {"Ouml",				'\326'},
  {"times",				'\327'}, /* ? */
  {"Oslash",				'\330'},
  {"Ugrave",				'\331'},
  {"Uacute",				'\332'},
  {"Ucirc",				'\333'},
  {"Uuml",				'\334'},
  {"Yacute",				'\335'},
  {"THORN",				'\336'},
  {"szlig",				'\337'},
  {"agrave",				'\340'},
  {"aacute",				'\341'},
  {"acirc",				'\342'},
  {"atilde",				'\343'},
  {"auml",				'\344'},
  {"aring",				'\345'},
  {"aelig",				'\346'},
  {"ccedil",				'\347'},
  {"egrave",				'\350'},
  {"eacute",				'\351'},
  {"ecirc",				'\352'},
  {"euml",				'\353'},
  {"igrave",				'\354'},
  {"iacute",				'\355'},
  {"icirc",				'\356'},
  {"iuml",				'\357'},
  {"eth",				'\360'},
  {"ntilde",				'\361'},
  {"ograve",				'\362'},
  {"oacute",				'\363'},
  {"ocirc",				'\364'},
  {"otilde",				'\365'},
  {"ouml",				'\366'},
  {"divide",				'\367'}, /* ? */
  {"oslash",				'\370'},
  {"ugrave",				'\371'},
  {"uacute",				'\372'},
  {"ucirc",				'\373'},
  {"uuml",				'\374'},
  {"yacute",				'\375'},
  {"thorn",				'\376'},
  {"yuml",				'\377'},
  {NULL,				'\0'},
};

/*
 * UTILITIES
 */

static int				get_char_from_amp(str)
char					*str;
{
  t_amp_esc				*ae;

  ae = amp_escs;
  while (ae->tag)
    {
      if (!strcmp(str,ae->tag))
	{
	  return (ae->value);
	}
      ae++;
    }
  return (0);
}

static char				*get_type(type)
int					type;
{
  switch (type)
    {
    case ELT_BR:			return ("ELT_BR");
    case ELT_STR:			return ("ELT_STR");
    case ELT_NOP:			return ("ELT_NOP");
    case ELT_TABLE:			return ("ELT_TABLE");
    case ELT_ROW:			return ("ELT_ROW");
    case ELT_CELL:			return ("ELT_CELL");
    case ELT_EMPTY_CELL:		return ("ELT_EMPTY_CELL");
    case ELT_CODE:			return ("ELT_CODE");
    case ELT_NO_CODE:			return ("ELT_NO_CODE");
    case ELT_LINK:			return ("ELT_LINK");
    case ELT_ROOT:			return ("ELT_ROOT");
    case ELT_FORM:			return ("ELT_FORM");
    case ELT_INPUT:			return ("ELT_INPUT");
    case ELT_SELECT:			return ("ELT_SELECT");
    case ELT_OPTION:			return ("ELT_OPTION");
    case ELT_B:				return ("ELT_B");
    case ELT_NO_B:			return ("ELT_NO_B");
    case ELT_I:				return ("ELT_I");
    case ELT_NO_I:			return ("ELT_NO_I");
    case ELT_SMALL:			return ("ELT_SMALL");
    case ELT_NO_SMALL:			return ("ELT_NO_SMALL");
    case ELT__TINY:			return ("ELT__TINY");
    case ELT_NO__TINY:			return ("ELT_NO__TINY");
    case ELT_IMG:			return ("ELT_IMG");
    case ELT_HR:			return ("ELT_HR");
    case ELT_HTML:			return ("ELT_HTML");
    case ELT_H1:			return ("ELT_H1");
    case ELT_NO_H1:			return ("ELT_NO_H1");
    case ELT_H2:			return ("ELT_H2");
    case ELT_NO_H2:			return ("ELT_NO_H2");
    case ELT__CIRCLE:			return ("ELT__CIRCLE");
    }
  return (NULL); /* IT SHOULDN'T HAPPEN */
}

static int				get_input_type(self,str)
Widget					self;
char					*str;
{
  if (!strcasecmp(str,"submit"))
    return (INPUT_TYPE_SUBMIT);
  if (!strcasecmp(str,"reset"))
    return (INPUT_TYPE_RESET);
  if (!strcasecmp(str,"checkbox"))
    return (INPUT_TYPE_CHECKBOX);
  if (!strcasecmp(str,"radio"))
    return (INPUT_TYPE_RADIO);
  if (FANCY.badHTMLWarnings)
    XmgWarning("XmgFancyWidget: bad input TYPE %s",str);
  return (INPUT_TYPE_HIDDEN);
}

static char				*get_input_type_str(input_type)
int					input_type;
{
  switch (input_type)
    {
    case INPUT_TYPE_SUBMIT:		return ("INPUT_TYPE_SUBMIT");
    case INPUT_TYPE_RESET:		return ("INPUT_TYPE_RESET");
    case INPUT_TYPE_CHECKBOX:		return ("INPUT_TYPE_CHECKBOX");
    case INPUT_TYPE_RADIO:		return ("INPUT_TYPE_RADIO");
    case INPUT_TYPE_HIDDEN:		return ("INPUT_TYPE_HIDDEN");
    }
  return ("INPUT_TYPE_DEFAULT");
}

static int				get_align(self,str)
Widget					self;
char					*str;
{
  if (!strcasecmp(str,"center"))
    return (ALIGN_CENTER);
  if (!strcasecmp(str,"right"))
    return (ALIGN_RIGHT);
  if (FANCY.badHTMLWarnings)
    XmgWarning("XmgFancyWidget: bad ALIGN %s",str);
  return (ALIGN_NONE);
}

static t_elt				*get_link(self,event,container)
Widget					self;
XEvent					*event;
t_elt					*container;
{
  assert(event->type == ButtonPress || event->type == ButtonRelease);
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    t_elt			*found_link;
	    
	    if (found_link = get_link(self,event,elt))
	      return (found_link);
	    break ;
	  }
	case ELT_LINK:
	  {
	    if (event->xbutton.x > elt->x &&
		event->xbutton.x < (elt->x + elt->width) &&
		event->xbutton.y > elt->y &&
		event->xbutton.y < (elt->y + elt->height))
              return (elt);
	  }
	}
    }
  VEC_ENDFOR;
  return (NULL);
}

static t_elt				*get_table(self,event,container)
Widget					self;
XEvent					*event;
t_elt					*container;
{
  assert(event->type == ButtonPress || event->type == ButtonRelease);
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    t_elt			*found_table;
	    
	    if (found_table = get_table(self,event,elt))
	      return (found_table);
	    if (elt->type == ELT_TABLE)
	      {
		if (event->xbutton.x > elt->x &&
		    event->xbutton.x < (elt->x + elt->width) &&
		    event->xbutton.y > elt->y &&
		    event->xbutton.y < (elt->y + elt->height))
		  return (elt);
	      }
	    break ;
	  }
	}
    }
  VEC_ENDFOR;
  return (NULL);
}

static t_elt				*get_table_from_xy(self,x,y,container)
Widget					self;
Position				x;
Position				y;
t_elt					*container;
{
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    t_elt			*found_table;
	    
	    if (found_table = get_table_from_xy(self,x,y,elt))
	      return (found_table);
	    if (elt->type == ELT_TABLE)
	      {
		if (x > elt->x &&
		    x < (elt->x + elt->width) &&
		    y > elt->y &&
		    y < (elt->y + elt->height))
		  return (elt);
	      }
	    break ;
	  }
	}
    }
  VEC_ENDFOR;
  return (NULL);
}

static t_elt				*get_elt(self,event,container)
Widget					self;
XEvent					*event;
t_elt					*container;
{
  assert(event->type == ButtonPress || event->type == ButtonRelease ||
	 event->type == MotionNotify);
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    t_elt			*found_elt;
	    
	    if (found_elt = get_elt(self,event,elt))
	      return (found_elt);
	    break ;
	  }
	default:
	  if (elt->displayable)
	    {
	      int			x;
	      int			y;
	      
	      if (event->type == ButtonPress || event->type == ButtonRelease)
		{
		  x = event->xbutton.x;
		  y = event->xbutton.y;
		}
	      else
		if (event->type == MotionNotify)
		  {
		    x = event->xmotion.x;
		    y = event->xmotion.y;
		  }
	      if (x > elt->x &&
		  x < (elt->x + elt->width) &&
		  y > elt->y &&
		  y < (elt->y + elt->height))
		return (elt);
	    }
	  break ;
	}
    }
  VEC_ENDFOR;
  return (NULL);
}

static t_elt				*get_child_from_widget(container,w)
t_elt					*container;
Widget					w;
{
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    t_elt			*child;
	    
	    if (child = get_child_from_widget(elt,w))
	      return (child);
	    break ;
	}
	case ELT_INPUT:
	  if (elt->widget == w)
	    return (elt);
	  break ;
	}
    }
  VEC_ENDFOR;
  return (NULL);
}

static t_elt				*get_next_widget_child(container,
							       ref,
							       next_is_ok)
t_elt					*container;
t_elt					*ref;
t_boolean				*next_is_ok;
{
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    t_elt			*child;
	    
	    if (child = get_next_widget_child(elt,ref,next_is_ok))
	      return (child);
	    break ;
	}
	case ELT_INPUT:
	  if (*next_is_ok && elt->widget != NULL)
	    return (elt);
	  if (elt == ref)
	    (*next_is_ok) = TRUE;
	  break ;
	}
    }
  VEC_ENDFOR;
  return (NULL);
}

static Pixel				get_pixel(self,color)
Widget					self;
char					*color;
{
  t_hash_elt				*he;
  t_status				status;
  Pixel					pixel;

  if ((status = XmgPixelDictGet(color,
				DefaultColormap(XtDisplay(self),
					   DefaultScreen(XtDisplay(self))),
				&pixel)) == 0)
    return (pixel);
  else
    {
      XColor				screen_def_return;
      XColor				exact_def_return;

      if (XAllocNamedColor(XtDisplay(self),
			   DefaultColormap(XtDisplay(self),
					   DefaultScreen(XtDisplay(self))),
			   color,
			   &screen_def_return,
			   &exact_def_return) == BadColor)
	{
	  XmgWarning("XmgFancyWidget: bad color %s",color);
	  return ((Pixel)-1);
	}
      if ((status = XmgPixelDictAdd(color,
				  DefaultColormap(XtDisplay(self),
					   DefaultScreen(XtDisplay(self))),  
			     exact_def_return.pixel)) != 0)
	{
	  XmgWarning("XmgFancyWidget: %s",err_msg(status));
	  return ((Pixel)-1);
	}
      return (exact_def_return.pixel);
    }
}

static VOID_FUNC			get_img(self,
						src,
						wanted_type,
						wanted_depth,
						type,
						ptr)
Widget					self;
char					*src;
FancyImgType				wanted_type;
int					wanted_depth;
FancyImgType				*type;
VOID_PTR				*ptr;
{
  t_status				status;
  XmgFancyImgCallbackStruct		cbs;
	  
  cbs.base_href = FANCY.base_href;
  cbs.src = src;
  cbs.type = wanted_type;
  cbs.depth = wanted_depth;
  XtCallCallbackList(self,FANCY.imgCallback,&cbs);
  (*type) = cbs.type;
  (*ptr) = cbs.ptr;
}

static XFontStruct			*get_xfs(self,name)
Widget					self;
char					*name;
{
  t_hash_elt				*he;
  t_status				status;
  XFontStruct				*xfs;

  if ((status = XmgXFSDictGet(name,&xfs)) == 0)
    return (xfs);
  else
    {
      if ((xfs = XLoadQueryFont(XtDisplay(self),name)) == NULL)
	{
	  XmgWarning("XmgFancyWidget: bad font %s",name);
	  return (NULL);
	}
      if ((status = XmgXFSDictAdd(name,xfs)) != 0)
	{
	  XmgWarning("XmgFancyWidget: %s",err_msg(status));
	  return (NULL);
	}
      return (xfs);
    }
}

static t_elt				*get_any_parent(self)
Widget					self;
{
  if (FANCY.current_table)
    {
      if (FANCY.current_table->current_row)
	{
	  if (FANCY.current_table->current_cell)
	    return (FANCY.current_table->current_cell);
	  else
	    return (FANCY.current_table->current_row);
	}
      else
	return (FANCY.current_table);
    }
  return (FANCY.root_elt);
}

static t_elt				*get_parent(self)
Widget					self;
{
  if (FANCY.current_select)
    {
      if (FANCY.current_select->current_option)
	return (FANCY.current_select->current_option);
      return (NULL);
    }
  if (FANCY.current_table)
    {
      if (FANCY.current_table->current_row)
	if (FANCY.current_table->current_cell)
	  return (FANCY.current_table->current_cell);
      return (NULL);
    }
  return (FANCY.root_elt);
}

static char				*fancy_strdup(str,comment)
char					*str;
char					*comment;
{
  char					*nstr;
  t_status				status;

  if ((nstr = strdup_alloc(str,
			   FANCY_ALLOC_PROC,
			   "fancy",
			   comment,
			   &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: fancy_strdup %s\n",err_msg(status));
      exit(1);
    }
  return (nstr);
}

static t_elt				*elt_new(self,type,parent)
Widget					self;
int					type;
t_elt					*parent;
{
  t_elt					*elt;
  t_status				status;
  
  if ((elt = FANCY_ALLOC_PROC(sizeof (t_elt),
			      "fancy",
			      "elt_new:elt",
			      &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: FANCY_ALLOC_PROC %s",err_msg(status));
      exit(1);
    }
  bcopy((char *)parent,(char *)elt,sizeof (t_elt));
  if ((elt->idx = vec_add(parent->sub_elts,elt)) != 0)
    {
      XmgWarning("XmgFancyWidget: vec_add %s",err_msg(status));
      exit(1);
    }
  elt->type = type;
  elt->self = self;
  elt->displayable = False;
  elt->computable = True;
  elt->highlight_len = 0;
  elt->border = 0;
  return (elt);
}

static VOID_FUNC			cmd_br(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;
  
  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_BR,parent);
}

static VOID_FUNC			cmd_table(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_status				status;
  t_elt					*parent;
  char					*_name;
  
  if ((parent = get_parent(self)) == NULL)
    return ;
  if ((elt = elt_new(self,ELT_TABLE,parent)) == NULL)
    return ;
  elt->cellspacing = 1;
  elt->cellpadding = 1;
  elt->border = 0;
  elt->percent = -1;
  elt->fixed_width = 0;
  elt->current_row = NULL;
  elt->current_cell = NULL;
  elt->th = NULL;
  _name = "";
  if ((elt->sub_elts = FANCY_VEC_NEW(FANCY.subEltVecBase,
				     &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: FANCY_VEC_NEW %s",err_msg(status));
      exit(1);
    }
  if (args)
    {
      VEC_FOR_FROM(args,1,char *arg)
	{
	  if (!strncasecmp(arg,WIDTH_STR,strlen(WIDTH_STR)))
	    {
	      char			*ptr;
	      
	      arg += strlen(WIDTH_STR);
	      if (ptr = index(arg,'%'))
		{
		  *ptr = 0;
		  elt->percent = atoi(arg);
		}
	      else
		elt->fixed_width = atoi(arg);
	      continue ;
	    }
	  if (!strncasecmp(arg,BORDER_STR,strlen(BORDER_STR)))
	    {
	      arg += strlen(BORDER_STR);
	      elt->border = atoi(arg);
	      continue ;
	    }
	  if (!strncasecmp(arg,BGCOLOR_STR,strlen(BGCOLOR_STR)))
	    {
	      arg += strlen(BGCOLOR_STR);
	      if ((elt->bgcolor = get_pixel(self,arg)) == (Pixel)-1)
		elt->bgcolor = FANCY.brokenPixel;
	      continue ;
	    }
	  if (!strncasecmp(arg,CELLSPACING_STR,strlen(CELLSPACING_STR)))
	    {
	      arg += strlen(CELLSPACING_STR);
	      elt->cellspacing = atoi(arg);
	      continue ;
	    }
	  if (!strncasecmp(arg,_NAME_STR,strlen(_NAME_STR)))
	    {
	      arg += strlen(_NAME_STR);
	      _name = arg;
	      continue ;
	    }
	}
      VEC_ENDFOR;
    }
  elt->_name = fancy_strdup(_name,"cmd_table:_name");
  if (FANCY.forceBorder != 0)
    elt->border = FANCY.forceBorder;
  if (FANCY.debugCellSpacing != 0)
    elt->cellspacing = FANCY.debugCellSpacing;
  if (FANCY.current_table)
    if ((status = stack_push(FANCY.table_stack,
			     (VOID_PTR)(FANCY.current_table))) != 0)
      {
	XmgWarning("XmgFancyWidget: stack_push %s",err_msg(status));
	exit(1);
      }
  elt->displayable = True;
  FANCY.current_table = elt;
}

static VOID_FUNC			cmd_no_table(self,args)
Widget					self;
t_vec					*args;
{
  t_status				status;
  t_elt					*table;
  
  if ((status = stack_pop(FANCY.table_stack,(VOID_PTR *)(&table))) != 0)
    FANCY.current_table = NULL;
  else
    FANCY.current_table = table;
}

static VOID_FUNC			cmd_no_tr();

static VOID_FUNC			cmd_tr(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_status				status;

  if (!FANCY.current_table)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: TR: not in table");
      cmd_table(self,NULL);
    }
  if (FANCY.current_table->current_row)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: TR: missing /TR");
      cmd_no_tr(self,NULL);
    }
  if ((elt = elt_new(self,ELT_ROW,FANCY.current_table)) == NULL)
    return ;
  elt->table = FANCY.current_table;
  elt->table->current_row = elt;
  elt->border = elt->table->border;
  if (elt->table->th == NULL)
    {
      elt->table->th = elt;
    }
  if ((elt->sub_elts = FANCY_VEC_NEW(FANCY.subEltVecBase,
				     &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: %s",err_msg(status));
      exit(1);
    }
  elt->displayable = True;
}

static VOID_FUNC			cmd_no_tr(self,args)
Widget					self;
t_vec					*args;
{
  if (!FANCY.current_table)
    {
      XmgWarning("XmgFancyWidget: /TR: not in TABLE");
      exit(1);
    }
  if (!FANCY.current_table->current_row)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: /TR: not in TR");
      return ;
    }
  FANCY.current_table->current_row = NULL;
}

static VOID_FUNC			cmd_td(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_status				status;
  
  if (!FANCY.current_table)
    {
      XmgWarning("XmgFancyWidget: TD: not in TABLE");
      exit(1);
    }
  if (!FANCY.current_table->current_row)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: TD: not in TR");
      cmd_tr(self,NULL);
    }
  if ((elt = elt_new(self,ELT_CELL,FANCY.current_table->current_row)) == NULL)
    return ;
  elt->tr = FANCY.current_table->current_row; 
  FANCY.current_table->current_cell = elt;
  if ((elt->sub_elts = FANCY_VEC_NEW(FANCY.subEltVecBase,
				     &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: FANCY_VEC_NEW %s",err_msg(status));
      exit(1);
    }
  elt->percent = -1;
  elt->colspan = 1;
  elt->fixed_width = 0;
  elt->align = ALIGN_NONE;
  elt->bgcolor = FANCY.current_table->bgcolor;
  VEC_FOR_FROM(args,1,char *arg)
    {
      if (!strncasecmp(arg,WIDTH_STR,strlen(WIDTH_STR)))
	{
	  char				*ptr;

	  arg += strlen(WIDTH_STR);
	  if (ptr = index(arg,'%'))
	    {
	      *ptr = 0;
	      elt->percent = atoi(arg);
	    }
	  else
	    elt->fixed_width = atoi(arg);
	  continue ;
	}
      if (!strncasecmp(arg,COLSPAN_STR,strlen(COLSPAN_STR)))
	{
	  int				i;

	  arg += strlen(COLSPAN_STR);
	  elt->colspan = atoi(arg);
	  i = 1;
	  while (i < elt->colspan)
	    {
	      t_elt	*empty_cell;

	      if ((empty_cell = 
		   elt_new(self,
			   ELT_EMPTY_CELL,
			   FANCY.current_table->current_row)) == NULL)
		break ;
	      i++;
	    }
	  continue ;
	}
      if (!strncasecmp(arg,BGCOLOR_STR,strlen(BGCOLOR_STR)))
	{
	  arg += strlen(BGCOLOR_STR);
	  if ((elt->bgcolor = get_pixel(self,arg)) == (Pixel)-1)
	    elt->bgcolor = FANCY.brokenPixel;
	  continue ;
	}
      if (!strncasecmp(arg,ALIGN_STR,strlen(ALIGN_STR)))
	{
	  arg += strlen(ALIGN_STR);
	  elt->align = get_align(self,arg);
	  continue ;
	}
      if (!strncasecmp(arg,CELLPADDING_STR,strlen(CELLPADDING_STR)))
	{
	  arg += strlen(CELLPADDING_STR);
	  elt->cellpadding = atoi(arg);
	  continue ;
	}
    }
  VEC_ENDFOR;
  elt->border = FANCY.current_table->border;
  elt->displayable = True;
}

static VOID_FUNC			cmd_no_td(self,args)
Widget					self;
t_vec					*args;
{
  if (!FANCY.current_table)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: /TD: not in TABLE");
      return ;
    }
  if (!FANCY.current_table->current_row)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: /TD: not in TR");
      return ;
    }
  if (!FANCY.current_table->current_cell)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: /TD: not in TD");
      return ;
    }
  FANCY.current_table->current_cell = NULL;
}

static VOID_FUNC			cmd_body(self,args)
Widget					self;
t_vec					*args;
{
  VEC_FOR_FROM(args,1,char *arg)
    {
      if (!strncasecmp(arg,LINK_STR,strlen(LINK_STR)))
	{
	  arg += strlen(LINK_STR);
	  FANCY_FREE_PROC(FANCY.link_color_name,
			  "fancy",
			  "*:link_color_name");
	  FANCY.link_color_name = fancy_strdup(arg,
					       "cmd_body:link_color_name");
	  continue ;
	}
      if (!strncasecmp(arg,VLINK_STR,strlen(VLINK_STR)))
	{
	  arg += strlen(VLINK_STR);
	  FANCY_FREE_PROC(FANCY.v_link_color_name,
			  "fancy",
			  "*:v_link_color_name");
	  FANCY.v_link_color_name = fancy_strdup(arg,
						 "cmd_body:v_link_color_name");
	  continue ;
	}
      if (!strncasecmp(arg,TEXT_STR,strlen(TEXT_STR)))
	{
	  arg += strlen(TEXT_STR);
	  FANCY_FREE_PROC(FANCY.text_color_name,
			  "fancy",
			  "*:text_color_name");
	  FANCY.text_color_name = fancy_strdup(arg,
					       "cmd_body:text_color_name");
	  continue ;
	}
      if (!strncasecmp(arg,BGCOLOR_STR,strlen(BGCOLOR_STR)))
	{
	  arg += strlen(BGCOLOR_STR);
	  if (strcmp(arg,"_inherit_bgcolor"))
	    {
	      if ((FANCY.root_elt->bgcolor = get_pixel(self,arg)) == (Pixel)-1)
		FANCY.root_elt->bgcolor = FANCY.brokenPixel;
	      /* WE COULD DO THAT ELSEWHERE */
	      XtVaSetValues(self,
			    XtNbackground,	FANCY.root_elt->bgcolor,
			    NULL);
	    }
	  continue ;
	}
      if (!strncasecmp(arg,BACKGROUND_STR,strlen(BACKGROUND_STR)))
	{
	  FancyImgType			type;
	  XtPointer			ptr;

	  arg += strlen(BACKGROUND_STR);
	  if (!strcmp(arg,"_none"))
	    continue ;
	  get_img(self,
		  arg,
		  FancyImgTypePixmap,
		  CORE.depth,
		  &type,
		  &ptr);
	  if (type == FancyImgTypePixmap)
	    {
	      XtVaSetValues(self,
			    XtNbackgroundPixmap,	(Pixmap)ptr,
			    NULL);
	    }
	  continue ;
	}
    }
    VEC_ENDFOR;
}

static VOID_FUNC			cmd_html(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;
  t_elt					*elt;

  FANCY.do_br_on_nl = False;
  if ((parent = get_parent(self)) == NULL)
    return ;
  elt = elt_new(self,ELT_HTML,parent);
}

static VOID_FUNC			cmd_no_html(self,args)
Widget					self;
t_vec					*args;
{
  /* TODO */
}

static VOID_FUNC			cmd_nop(self,args)
Widget					self;
t_vec					*args;
{
  /* NOP */
}

static VOID_FUNC			cmd_code(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_CODE,parent);
}

static VOID_FUNC			cmd_no_code(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_NO_CODE,parent);
}

static VOID_FUNC			cmd_a(self,args)
Widget					self;
t_vec					*args;
{
  t_status				status;

  if (FANCY.href)
    {
      FANCY_FREE_PROC(FANCY.href,
		      "fancy",
		      "*:href");
      FANCY.href = NULL;
    }
  VEC_FOR_FROM(args,1,char *arg)
    {
      if (!strncasecmp(arg,HREF_STR,strlen(HREF_STR)))
	{
	  arg += strlen(HREF_STR);
	  FANCY.href = fancy_strdup(arg,"cmd_a:href");
	  continue ;
	}
    }
  VEC_ENDFOR;
  if (!FANCY.href)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: A: missing href");
    }
  else
    FANCY.next_str_is_a_link = True;
}

static VOID_FUNC			cmd_no_a(self,args)
Widget					self;
t_vec					*args;
{
  FANCY.next_str_is_a_link = False;
}

static VOID_FUNC			cmd_base(self,args)
Widget					self;
t_vec					*args;
{
  t_status				status;

  if (FANCY.base_href)
    {
      FANCY_FREE_PROC(FANCY.base_href,
		      "fancy",
		      "*:base_href");
      FANCY.base_href = NULL;
    }
  VEC_FOR_FROM(args,1,char *arg)
    {
      if (!strncasecmp(arg,HREF_STR,strlen(HREF_STR)))
	{
	  arg += strlen(HREF_STR);
	  FANCY.base_href = fancy_strdup(arg,"cmd_base:base_href");
	  continue ;
	}
    }
  VEC_ENDFOR;
  if (!FANCY.base_href)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: BASE: missing href");
    }
}

static VOID_FUNC			cmd_title(self,args)
Widget					self;
t_vec					*args;
{
  FANCY.next_str_is_a_title = True;
}

static VOID_FUNC			cmd_no_title(self,args)
Widget					self;
t_vec					*args;
{
  FANCY.next_str_is_a_title = False;
}

static VOID_FUNC			cmd_p(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_BR,parent);
  elt_new(self,ELT_BR,parent);
}

static VOID_FUNC			cmd_h2(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_BR,parent);
  elt_new(self,ELT_H2,parent);
}

static VOID_FUNC			cmd_no_h2(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_NO_H2,parent);
  elt_new(self,ELT_BR,parent);
}

static VOID_FUNC			cmd_h1(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_BR,parent);
  elt_new(self,ELT_H1,parent);
}

static VOID_FUNC			cmd_no_h1(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_NO_H1,parent);
  elt_new(self,ELT_BR,parent);
}

static VOID_FUNC			cmd_form(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_elt					*parent;
  char					*action;
  t_status				status;

  if ((parent = get_any_parent(self)) == NULL)
    return ;
  if ((elt = elt_new(self,ELT_FORM,parent)) == NULL)
    return ;
  elt->computable = False;
  action = "";
  VEC_FOR_FROM(args,1,char *arg)
    {
      if (!strncasecmp(arg,ACTION_STR,strlen(ACTION_STR)))
	{
	  arg += strlen(ACTION_STR);
	  action = arg;
	  continue ;
	}
    }
  VEC_ENDFOR;
  elt->action = fancy_strdup(action,"cmd_form:action");
  FANCY.current_form = elt;
}

static VOID_FUNC			cmd_no_form(self,args)
Widget					self;
t_vec					*args;
{
  if (!FANCY.current_form)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: /FORM: not in a FORM");
    }
  FANCY.current_form = NULL;
}

static VOID_FUNC			cmd_input(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_elt					*parent;
  char					*name;
  char					*value;
  t_status				status;

  if ((parent = get_parent(self)) == NULL)
    return ;
  if (!FANCY.current_form)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: INPUT not in a FORM");
      return ;
    }
  if ((elt = elt_new(self,ELT_INPUT,parent)) == NULL)
    return ;
  elt->form = FANCY.current_form;
  elt->widget = NULL;
  elt->input_type = INPUT_TYPE_DEFAULT;
  elt->name = NULL;
  elt->value = NULL;
  elt->fixed_width = 0;
  elt->displayable = True;
  elt->checked = False;
  name = "";
  value = "";
  VEC_FOR_FROM(args,1,char *arg)
    {
      if (!strncasecmp(arg,TYPE_STR,strlen(TYPE_STR)))
	{
	  arg += strlen(TYPE_STR);
	  if ((elt->input_type =
	       get_input_type(self,arg)) == INPUT_TYPE_HIDDEN)
	    {
	      elt->computable = elt->displayable = False;
	    }
	  continue ;
	}
      if (!strncasecmp(arg,WIDTH_STR,strlen(WIDTH_STR)))
	{
	  arg += strlen(WIDTH_STR);
	  elt->fixed_width = atoi(arg);
	  continue ;
	}
      if (!strncasecmp(arg,NAME_STR,strlen(NAME_STR)))
	{
	  arg += strlen(NAME_STR);
	  name = arg;
	  continue ;
	}
      if (!strncasecmp(arg,VALUE_STR,strlen(VALUE_STR)))
	{
	  arg += strlen(VALUE_STR);
	  value = arg;
	  continue ;
	}
      if (!strncasecmp(arg,CHECKED_STR,strlen(CHECKED_STR)))
	{
	  elt->checked = True;
	  continue ;
	}
    }
  VEC_ENDFOR;
  elt->name = fancy_strdup(name,"cmd_input:name");
  elt->value = fancy_strdup(value,"cmd_input:value");
}

static VOID_FUNC			cmd_select(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_status				status;
  t_elt					*parent;
  char					*name;

  if ((parent = get_parent(self)) == NULL)
    return ;
  if (!FANCY.current_form)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: SELECT: not in a FORM");
      return ;
    }
  if ((elt = elt_new(self,ELT_SELECT,parent)) == NULL)
    return ;
  elt->form = FANCY.current_form;
  elt->widget = NULL;
  elt->name = NULL;
  elt->value = NULL;
  elt->displayable = True;
  elt->current_option = NULL;
  name = "";
  if ((elt->sub_elts = FANCY_VEC_NEW(FANCY.subEltVecBase,
				     &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: FANCY_VEC_NEW %s",err_msg(status));
      exit(1);
    }
  VEC_FOR_FROM(args,1,char *arg)
    {
      if (!strncasecmp(arg,NAME_STR,strlen(NAME_STR)))
	{
	  arg += strlen(NAME_STR);
	  name = arg;
	  continue ;
	}
    }
  VEC_ENDFOR;
  elt->name = fancy_strdup(name,"cmd_input:name");
  FANCY.current_select = elt;
}

static VOID_FUNC			cmd_no_select(self,args)
Widget					self;
t_vec					*args;
{
  if (!FANCY.current_select)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: /SELECT: not in SELECT");
      return ;
    }
  FANCY.current_select = NULL;
}

static VOID_FUNC			cmd_option(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_status				status;
  char					*value;

  if (!FANCY.current_select)
    {
      if (FANCY.badHTMLWarnings)
	XmgWarning("XmgFancyWidget: not in SELECT");
      return ;
    }
  if ((elt = elt_new(self,ELT_OPTION,FANCY.current_select)) == NULL)
    return ;
  elt->value = NULL;
  elt->selected = False;
  if ((elt->sub_elts = FANCY_VEC_NEW(FANCY.subEltVecBase,
				     &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: FANCY_VEC_NEW %s",err_msg(status));
      exit(1);
    }
  value = "";
  VEC_FOR_FROM(args,1,char *arg)
    {
      if (!strncasecmp(arg,VALUE_STR,strlen(VALUE_STR)))
	{
	  arg += strlen(VALUE_STR);
	  value = arg;
	  continue ;
	}
      if (!strncasecmp(arg,SELECTED_STR,strlen(SELECTED_STR)))
	{
	  elt->selected = True;
	  continue ;
	}
    }
  VEC_ENDFOR;
  elt->value = fancy_strdup(value,"cmd_option:value");
  FANCY.current_select->current_option = elt;
}

static VOID_FUNC			cmd_b(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_B,parent);
}

static VOID_FUNC			cmd_no_b(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_NO_B,parent);
}

static VOID_FUNC			cmd_small(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_SMALL,parent);
}

static VOID_FUNC			cmd_no_small(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_NO_SMALL,parent);
}

static VOID_FUNC			cmd__tiny(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT__TINY,parent);
}

static VOID_FUNC			cmd_no__tiny(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_NO__TINY,parent);
}

static VOID_FUNC			cmd_i(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_I,parent);
}

static VOID_FUNC			cmd_no_i(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  elt_new(self,ELT_NO_I,parent);
}

static VOID_FUNC			cmd_img(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_status				status;
  t_elt					*parent;
  char					*src;

  if ((parent = get_parent(self)) == NULL)
    return ;
  if ((elt = elt_new(self,ELT_IMG,parent)) == NULL)
    return ;
  src = "";
  VEC_FOR_FROM(args,1,char *arg)
    {
      if (!strncasecmp(arg,SRC_STR,strlen(SRC_STR)))
	{
	  arg += strlen(SRC_STR);
	  src = arg;
	  continue ;
	}
    }
  VEC_ENDFOR;
  elt->src = fancy_strdup(src,"cmd_img:src");
  elt->displayable = True;
  elt->img_inited = False;
}

static VOID_FUNC			cmd_hr(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_status				status;
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  if ((elt = elt_new(self,ELT_HR,parent)) == NULL)
    return ;
  elt->displayable = True;
}

static VOID_FUNC			cmd_li(self,args)
Widget					self;
t_vec					*args;
{
  t_elt					*elt;
  t_status				status;
  t_elt					*parent;

  if ((parent = get_parent(self)) == NULL)
    return ;
  if ((elt = elt_new(self,ELT_BR,parent)) == NULL)
    return ;
  elt->displayable = True;
  if ((elt = elt_new(self,ELT__CIRCLE,parent)) == NULL)
    return ;
  elt->fixed_width = 7;
  elt->displayable = True;
}

static t_cmd				cmds[] =
{
  {"BR",				cmd_br},
  {"TABLE",				cmd_table},
  {"/TABLE",				cmd_no_table},
  {"TR",				cmd_tr},
  {"/TR",				cmd_no_tr},
  {"TH",				cmd_tr},
  {"/TH",				cmd_no_tr},
  {"TD",				cmd_td},
  {"/TD",				cmd_no_td},
  {"BODY",				cmd_body},
  {"/BODY",				cmd_nop},
  {"HTML",				cmd_html},
  {"/HTML",				cmd_no_html},
  {"HEAD",				cmd_nop},
  {"/HEAD",				cmd_nop},
  {"CODE",				cmd_code},
  {"/CODE",				cmd_no_code},
  {"A",					cmd_a},
  {"/A",				cmd_no_a},
  {"BASE",				cmd_base},
  {"TITLE",				cmd_title},
  {"/TITLE",				cmd_no_title},
  {"P",					cmd_p},
  {"H2",				cmd_h2},
  {"/H2",				cmd_no_h2},
  {"H1",				cmd_h1},
  {"/H1",				cmd_no_h1},
  {"FORM",				cmd_form},
  {"/FORM",				cmd_no_form},
  {"INPUT",				cmd_input},
  {"SELECT",				cmd_select},
  {"/SELECT",				cmd_no_select},
  {"OPTION",				cmd_option},
  {"B",					cmd_b},
  {"/B",				cmd_no_b},
  {"STRONG",				cmd_b},
  {"/STRONG",				cmd_no_b},
  {"SMALL",				cmd_small},
  {"/SMALL",				cmd_no_small},
  {"_TINY",				cmd__tiny},
  {"/_TINY",				cmd_no__tiny},
  {"I",					cmd_i},
  {"/I",				cmd_no_i},
  {"EM",				cmd_i},
  {"/EM",				cmd_no_i},
  {"META",				cmd_nop},
  {"IMG",				cmd_img},
  {"HR",				cmd_hr},
  {"LI",				cmd_li},	
};

static VOID_FUNC			do_cmd(self,args)
Widget					self;
t_vec					*args;
{
  unsigned int				numcmds;
  int					i;

  numcmds = XtNumber(cmds);
  i = 0;
  while (i < numcmds)
    {
      if (!strncmp(VEC_AT(args,0),"!--",3))
	{
	  if (FANCY.debugShowComments)
	    {
#ifdef DEBUG
	      vec_str_show(args);
#endif
	    }
	  i++;
	  return ;
	}
      if (!strcasecmp(cmds[i].name,VEC_AT(args,0)))
	{
	  if (FANCY.debugShowCmds)
	    {
#ifdef DEBUG
	      vec_str_show(args);
#endif
	    }
	  cmds[i].proc(self,args);
	  return ;
	}
      i++;
    }
  if (FANCY.badHTMLWarnings)
    XmgWarning("XmgFancyWidget: unknown cmd '%s' line %d\n",
	       VEC_AT(args,0),
	       FANCY.lineno);
}

static VOID_FUNC			state_text();

static VOID_FUNC			state_command(self,c)
Widget					self;
int					c;
{
  t_status				status;

  if (FANCY.quote)
    {
      if (c == '"')
	{
	  FANCY.quote = False;
	  return ;
	}
      else
	goto add_char;
    }
  switch (c)
    {
    case '"':
      FANCY.quote = True;
      return ;
    case ' ':
    case '\t':
      if (FANCY.buf[0] != 0)
	{
	  if ((status = vec_str_add(FANCY.args,FANCY.buf)) != 0)
	    {
	      XmgWarning("XmgFancyWidget: vec_str_add %s",err_msg(status));
	      exit(1);
	    }
	}
      FANCY.buf[0] = 0;
      return ;
    case '>':
      if (FANCY.buf[0] != 0)
	{
	  if ((status = vec_str_add(FANCY.args,FANCY.buf)) != 0)
	    {
	      XmgWarning("XmgFancyWidget: vec_str_add %s",err_msg(status));
	      exit(1);
	    }
	}
      if (VEC_COUNT(FANCY.args) > 0)
	do_cmd(self,FANCY.args);
      vec_str_destroy(FANCY.args);
      FANCY.buf[0] = 0;
      FANCY.state_proc = state_text;
      return ;
    }
add_char:
  if ((status = str_cat_char(FANCY.buf,
			     sizeof (FANCY.buf),
			     c)) != 0)
    {
      XmgWarning("XmgFancyWidget: str_cat_char %s",err_msg(status));
      exit(1);
    }
}

static VOID_FUNC			state_amp(self,c)
Widget					self;
int					c;
{
  t_status				status;

  if (c == ' ')
    {
      if (FANCY.buf[0] == 0)
	{
	  FANCY.buf[0] = 0;
	  FANCY.state_proc = state_text;
	  if ((status = str_cat_str(FANCY.buf,
				    sizeof (FANCY.buf),
				    "& ")) != 0)
	    {
	      XmgWarning("XmgFancyWidget: str_cat_str %s",err_msg(status));
	      exit(1);
	    }
	  return ;
	}
    }
  else
    if (c == ';')
      {
	if ((c = get_char_from_amp(FANCY.buf)) == 0)
	  {
	    if (FANCY.badHTMLWarnings)
	      XmgWarning("XmgFancyWidget: bad amp %s",FANCY.buf);
	    FANCY.buf[0] = 0;
	    FANCY.state_proc = state_text;
	    return ;
	  }
	else
	  {
	    FANCY.buf[0] = 0;
	    FANCY.state_proc = state_text;
	    if ((status = str_cat_char(FANCY.buf,
				       sizeof (FANCY.buf),
				       c)) != 0)
	      {
		XmgWarning("XmgFancyWidget: str_cat_char %s",err_msg(status));
		exit(1);
	      }
	    return ;
	  }
      }
  if ((status = str_cat_char(FANCY.buf,
			     sizeof (FANCY.buf),
			     c)) != 0)
    {
      XmgWarning("XmgFancyWidget: str_cat_char %s",err_msg(status));
      exit(1);
    }
}

static VOID_FUNC			elt_str_from_buf(self,parent)
Widget					self;
t_elt					*parent;
{
  t_status				status;

  if (FANCY.buf[0] != 0)
    {
      t_elt				*elt;
      
      if (FANCY.next_str_is_a_link)
	{
	  if ((elt = elt_new(self,ELT_LINK,parent)) == NULL)
	    goto done;
	  elt->href = fancy_strdup(FANCY.href,"elt_str_from_buf:href");
	}
      else
	{
	  if ((elt = elt_new(self,ELT_STR,parent)) == NULL)
	    goto done;
	}
      elt->str = fancy_strdup(FANCY.buf,"elt_str_from_buf:str");
      elt->len = strlen(elt->str);
      if (elt->title = FANCY.next_str_is_a_title)
	{
	  XmgFancyTitleCallbackStruct	cbs;

	  elt->computable = False;
	  cbs.title = elt->str;
	  XtCallCallbackList(self,FANCY.titleCallback,&cbs);
	}
      else
	{
	  elt->displayable = True;
	}
    }
done:
  FANCY.buf[0] = 0;
}

static VOID_FUNC			state_text(self,c)
Widget					self;
int					c;
{
  t_status				status;
  t_elt					*parent;

  if (c < 0)
    {
      if (parent = get_parent(self))
	elt_str_from_buf(self,parent);
      else
	FANCY.buf[0] = 0;
      return ;
    }
  else
    if (c == '<')
      {
	if (parent = get_parent(self))
	  elt_str_from_buf(self,parent);
	else
	  FANCY.buf[0] = 0;
	FANCY.quote = False;
	FANCY.state_proc = (t_state_proc)state_command;
      }
    else
      if (c == '&')
	{
	  if (parent = get_parent(self))
	    elt_str_from_buf(self,parent);
	  else
	    FANCY.buf[0] = 0;
	  FANCY.state_proc = (t_state_proc)state_amp;
	}
      else
	if (c == '\n')
	  {
	    if (FANCY.do_br_on_nl)
	      {
		if (!FANCY.current_table)
		  {
		    if (parent = get_parent(self))
		      {
			elt_str_from_buf(self,parent);
			elt_new(self,ELT_BR,parent);
		      }
		    else
		      FANCY.buf[0] = 0;
		  }
	      }
	  }
	else
	  goto add_char;
  return ;
  add_char :
    if ((status = str_cat_char(FANCY.buf,
			       sizeof (FANCY.buf),
			       c)) != 0)
      {
	XmgWarning("XmgFancyWidget: str_cat_char %s",err_msg(status));
	exit(1);
      }
}

static VOID_FUNC			elt_show(elt,recursive,nspaces)
t_elt					*elt;
t_boolean				recursive;
int					nspaces;
{
  char					spaces[STR_BUFSIZ];
  int					i;
  t_status				status;

  spaces[0] = 0;
  i = 0;
  while (i < nspaces)
    {
      if ((status = str_cat_char(spaces,
				 sizeof (spaces),
				 ' ')) != 0)
	{
	  XmgWarning("XmgFancyWidget: str_cat_char %s",err_msg(status));
	  exit(1);
	}
      i++;
    }
  fprintf(stderr,
	  "%s%s (%d) mw:%dx%d w:%dx%d b:%d r:+%d+%d a:%dx%d p:%d f:%d %s\n",
	  spaces,
	  get_type(elt->type),
	  elt->idx,
	  elt->min_width,
	  elt->min_height,
	  elt->width,
	  elt->height,
	  elt->border,
	  elt->relative_x,
	  elt->relative_y,
	  elt->x,
	  elt->y,
	  elt->percent,
	  elt->fixed_width,
	  (elt->displayable)?"D":"");
  switch (elt->type)
    {
    case ELT_TABLE:
    case ELT_ROOT:
    case ELT_ROW:
    case ELT_CELL:
      if (elt->type == ELT_TABLE)
	fprintf(stderr,"%s_name=%s %d sub elts\n",
		spaces,
		elt->_name,
		VEC_COUNT(elt->sub_elts));
      else
	fprintf(stderr,"%s%d sub elts\n",
		spaces,
		VEC_COUNT(elt->sub_elts));
      if (recursive)
	{
	  VEC_FOR(elt->sub_elts,t_elt *sub_elt)
	    {
	      elt_show(sub_elt,recursive,nspaces + 4);
	    }
	  VEC_ENDFOR;
	}
      break ;
    case ELT_STR:
    case ELT_LINK:
      fprintf(stderr,"%sstr=`%s' %s\n",
	      spaces,
	      elt->str,
	      elt->title?"title":"");
      break ;
    case ELT_INPUT:
      fprintf(stderr,"%s%s name=%s value=%s\n",
	      spaces,
	      get_input_type_str(elt->input_type),
	      elt->name,
	      elt->value);
      break ;
    }
}

static t_elt				*last_not_empty_cell(row)
t_elt					*row;
{
  t_elt					*last_not_empty;

  last_not_empty = NULL;
  VEC_FOR(row->sub_elts,t_elt *cell)
    {
      if (cell->type != ELT_EMPTY_CELL)
	last_not_empty = cell;
    }
  VEC_ENDFOR;
  return (last_not_empty);
}

static t_status				fill_form_dict(container,form,dict)
t_elt					*container;
t_elt					*form;
t_dict					*dict;
{
  t_status				status;

  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  fill_form_dict(elt,form,dict);
	  break ;
	case ELT_INPUT:
	  if (elt->form == form)
	    {
	      char		*name;
	      char		*value;

	      name = elt->name;
	      switch (elt->input_type)
		{
		case INPUT_TYPE_HIDDEN:
		  value = elt->value;
		  break ;
		case INPUT_TYPE_SUBMIT:
		case INPUT_TYPE_RESET:
		  continue ;
		case INPUT_TYPE_CHECKBOX:
		case INPUT_TYPE_RADIO:
		  {
		    Boolean			state;

		    XtVaGetValues(elt->widget,
				  XtNstate,
				  &state,
				  NULL);
		    if (state)
		      value = elt->value;
		    else
		      {
			if (elt->input_type == INPUT_TYPE_CHECKBOX)
			  value = "";
			else /* RADIO: AVOID REDEFINITION */
			  continue ;
		      }
		    break ;
		  }
		default:
		  XtVaGetValues(elt->widget,
				XtNstring,	&value,
				NULL);
		  break ;
		}
	      if ((status = dict_str_add(dict,name,value)) != 0)
		{
		  XmgWarning("XmgFancyWidget: dict_str_add %s: %s",
			     name,
			     err_msg(status));
		  return (status);
		}
	    }
	  break ;
	case ELT_SELECT:
	  if (elt->form == form)
	    {
	      char				*value;
	      
	      XtVaGetValues(elt->widget,
			    XtNlabel,	&value,
			    NULL);
	      if ((status = dict_str_add(dict,elt->name,value)) != 0)
		{
		  XmgWarning("XmgFancyWidget: dict_str_add %s: %s",
			     elt->name,
			     err_msg(status));
		  return (status);
		}
	    }
	  break ;
	}
    }
  VEC_ENDFOR;
  return (0);
}

static VOID_FUNC			command_submit(w,elt,command_cbs)
Widget					w;
t_elt					*elt;
XtPointer				command_cbs;
{
  XmgFancyFormCallbackStruct		cbs;
  t_status				status;
  Widget				self;

  self = elt->self;
  cbs.action = elt->form->action;
  if ((cbs.vars = FANCY_DICT_NEW(FANCY.varsHashBase,
				 FANCY.varsVecBase,
				 &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: FANCY_DICT_NEW: %s",err_msg(status));
      exit(1);
    }
  if ((status = fill_form_dict(FANCY.root_elt,elt->form,cbs.vars)) != 0)
    {
      XmgWarning("XmgFancyWidget: fill_form_dict: %s",err_msg(status));
      exit(1);
    }
  XtCallCallbackList(self,FANCY.formCallback,&cbs);
  dict_str_delete(cbs.vars);
}

static t_status				reset_input_values(container,form)
t_elt					*container;
t_elt					*form;
{
  t_status				status;

  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  reset_input_values(elt,form);
	  break ;
	case ELT_INPUT:
	  if (elt->form == form)
	    {
	      switch (elt->input_type)
		{
		case INPUT_TYPE_HIDDEN:
		  break ;
		case INPUT_TYPE_SUBMIT:
		case INPUT_TYPE_RESET:
		  continue ;
		case INPUT_TYPE_CHECKBOX:
		case INPUT_TYPE_RADIO:
		  {
		    XtVaSetValues(elt->widget,
				  XtNstate,
				  elt->checked,
				  NULL);
		    break ;
		  }
		default:
		  XtVaSetValues(elt->widget,
				XtNstring,	elt->value,
				NULL);
		  break ;
		}
	    }
	  break ;
	case ELT_SELECT:
	  if (elt->form == form)
	    {
	      /* TODO */
	    }
	  break ;
	}
    }
  VEC_ENDFOR;
  return (0);
}

static t_elt			*get_radio_by_name_different_from(container,
								  form,
								  name,
								  ref_radio)
t_elt				*container;
t_elt				*form;
char				*name;
t_elt				*ref_radio;
{
  t_status			status;

  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    t_elt	*radio_elt;

	    if (radio_elt = get_radio_by_name_different_from(elt,
							     form,
							     name,
							     ref_radio))
	      return (radio_elt);
	    break ;
	  }
	case ELT_INPUT:
	  if (elt->form == form)
	    {
	      if (elt->input_type == INPUT_TYPE_RADIO)
		{
		  if (!strcmp(elt->name,name) && elt != ref_radio)
		    return (elt);
		}
	    }
	  break ;
	}
    }
  VEC_ENDFOR;
  return (NULL);
}

static VOID_FUNC			command_reset(w,elt,command_cbs)
Widget					w;
t_elt					*elt;
XtPointer				command_cbs;
{
  Widget				self;

  self = elt->self;
  reset_input_values(FANCY.root_elt,elt->form);
}

static VOID_FUNC			radio_callback(w,elt,set)
Widget					w;
t_elt					*elt;
int					set;
{
  /* TODO */
}

static VOID_FUNC			layout_relative(self,
							container,
							constraint_level)
Widget					self;
t_elt					*container;
int					constraint_level;
{
  t_status				status;
  
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      elt->current_xfs = elt->xfs = container->current_xfs;
      if (!elt->computable)
	continue ;
      switch (elt->type)
	{
	case ELT_TABLE:
	  {
	    Dimension				max_width;
	    Dimension				height;
  
	    elt->cursor_x = elt->cursor_y = elt->cellspacing;
	    if (constraint_level)
	      {
		if (elt->percent > 0)
		  {
		    elt->width =
		      MY_MAX(elt->width, 
			  container->width * elt->percent / 100); 
		    elt->height = 0;
		  }
		else
		  if (elt->fixed_width != 0)
		    {
		      elt->width = 
			MY_MAX(elt->width,elt->fixed_width);
		      elt->height = 0;
		    }
		  else
		    {
		      elt->width = elt->height = 0;
		    }
	      }
	    else
	      {
		elt->height = elt->width = 0;
		elt->min_width = elt->min_height = 0;
	      }
	    layout_relative(self,elt,constraint_level);
	    max_width = height = 0;
	    VEC_FOR(elt->sub_elts,t_elt *sub_elt)
	      {
		if (sub_elt->computable)
		  {
		    max_width = MY_MAX(max_width,sub_elt->width);
		    height += sub_elt->height;
		  }
	      }
	    VEC_ENDFOR;
	    elt->width = MY_MAX(elt->width,
				max_width);
	    elt->height = 
	      MY_MAX(elt->height,
		     height +
		     (VEC_COUNT(elt->sub_elts) + 1) * elt->cellspacing);
	    elt->min_width = elt->width;
	    elt->min_height = elt->height;
	    elt->relative_x = container->cursor_x + elt->border;
	    elt->relative_y = container->cursor_y + elt->border;
#ifdef NOTDEF
	    container->cursor_x = container->cellspacing;
	    container->cursor_y += elt->height + elt->cellspacing +
	      2 * elt->border;
#else
	    container->cursor_x += elt->width + elt->cellspacing +
	      2 * elt->border;
	    container->jump = MY_MAX(container->jump,elt->height);
#endif
	    break ;
	  }
	case ELT_ROW:
	  {
	    Dimension				max_height;
	    Dimension				width;
	      
	    assert(container->type == ELT_TABLE);
	    elt->cursor_x = elt->cursor_y = 0;
	    if (constraint_level)
	      {
		elt->width =
		  MY_MAX(elt->width,container->width);
	      }
	    else
	      {
		elt->width = elt->height = 0;
		elt->min_width = elt->min_height = 0;
	      }
	    layout_relative(self,elt,constraint_level);
	    max_height = width = 0;
	    VEC_FOR(elt->sub_elts,t_elt *sub_elt)
	      {
		if (sub_elt->computable)
		  {
		    max_height = MY_MAX(max_height,
					sub_elt->height + 2 * elt->border);
		    width += sub_elt->width + 2 * elt->border;
		  }
	      }
	    VEC_ENDFOR;
	    elt->width = 
	      MY_MAX(elt->width,
		     width + 
		     (VEC_COUNT(elt->sub_elts) + 1) * elt->cellspacing);
	    elt->height = MY_MAX(elt->height,max_height);
	    elt->min_width = elt->width;
	    elt->min_height = elt->height;
	    elt->relative_x = container->cursor_x;
	    elt->relative_y = container->cursor_y;
	    container->cursor_y += elt->height + container->cellspacing; 
	    break ;
	  }
	case ELT_CELL:
	  {
	    Dimension				max_width;
	    Dimension				max_height;
	    Dimension				tmp_width;
	    Dimension				tmp_height;
	    
	    assert(container->type == ELT_ROW);
	    elt->cursor_x = elt->cursor_y = elt->cellpadding;
	    elt->jump = container->current_xfs->ascent +
	      container->current_xfs->descent;
	    if (constraint_level)
	      {
		if (elt->percent > 0)
		  {
		    elt->width = 
		      MY_MAX(elt->width,
			     container->width * elt->percent / 100);
		  }
		else
		  if (elt->fixed_width != 0)
		    {
		      elt->width = 
			MY_MAX(elt->width,
			       elt->fixed_width);
		    }
		  else
		    {
		      Dimension			span_width;
		      int			i;
		      
		      span_width = 0;
		      i = 0;
		      while (i < elt->colspan)
			{
			  t_elt			*th_cell;
			  
			  if (VEC_COUNT(container->table->th->sub_elts) <= 
			      (elt->idx + i))
			    {
			      break ;
			    }
			  th_cell = 
			    (t_elt *)(VEC_AT(container->table->th->sub_elts,
					     elt->idx + i));
			  span_width += th_cell->width;
			  i++;
			}
		      elt->width = MY_MAX(elt->width,span_width);
		    }
		if (elt == last_not_empty_cell(container))
		  elt->width = container->width - container->cursor_x;
		elt->height = container->height;
	      }
	    else
	      {
		elt->height = elt->width = 0;
		elt->min_width = elt->min_height = 0;
	      }
	    layout_relative(self,elt,constraint_level);
	    max_width = max_height = 0;
	    VEC_FOR(elt->sub_elts,t_elt *sub_elt)
	      {
		Dimension			tmp;
		
		if (sub_elt->computable)
		  {
		    if ((tmp = 
			 sub_elt->relative_x +
			 sub_elt->width + 
			 2 * sub_elt->border) >
			max_width)
		      max_width = tmp;
		    if ((tmp = 
			 sub_elt->relative_y + 
			 sub_elt->height + 
			 2 * sub_elt->border) >
			max_height)
		      max_height = tmp;
		  }
	      }
	    VEC_ENDFOR;
	    tmp_width = max_width;
	    tmp_height = max_height;
	    elt->width = MY_MAX(elt->width,tmp_width);
	    elt->height = MY_MAX(elt->height,tmp_height);
	    if (constraint_level)
	      {
		switch (elt->align)
		  {
		  case ALIGN_CENTER:
		    VEC_FOR(elt->sub_elts,t_elt *sub_elt)
		      {
			if (!sub_elt->computable)
			  return ;
			sub_elt->relative_x += (elt->width - tmp_width) / 2;
			sub_elt->relative_y += (elt->height - tmp_height) / 2;
		      }
		    VEC_ENDFOR;
		    break ;
		  }
	      }
	    elt->width += elt->cellpadding;
	    elt->height += elt->cellpadding;
	    elt->relative_x = container->cursor_x + elt->border;
	    elt->relative_y = container->cursor_y + elt->border;
	    elt->min_width = elt->width;
	    elt->min_height = elt->height;
	    container->cursor_x += elt->width + container->cellspacing + 
	      2 * elt->border;
	    break ;
	  }
	case ELT_EMPTY_CELL:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->min_width = elt->width = 
	      elt->min_height = elt->height = 0;
	    break ;
	  }
	case ELT_BR:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->cursor_x = container->cellpadding;
	    container->cursor_y += container->jump;
	    container->jump = container->current_xfs->ascent + 
	      container->current_xfs->descent;
	    break ;
	  }
	case ELT_CODE:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->prev_xfs = container->current_xfs;
	    if ((container->current_xfs =
		 get_xfs(self,FANCY.fixed_font_name)) == NULL)
	      container->current_xfs = FANCY.brokenXFS;
	    break ;
	  }
	case ELT_B:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->prev_xfs = container->current_xfs;
	    if ((container->current_xfs =
		 get_xfs(self,FANCY.bold_font_name)) == NULL)
	      container->current_xfs = FANCY.brokenXFS;
	    break ;
	  }
	case ELT_I:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->prev_xfs = container->current_xfs;
	    if ((container->current_xfs =
		 get_xfs(self,FANCY.italic_font_name)) == NULL)
	      container->current_xfs = FANCY.brokenXFS;
	    break ;
	  }
	case ELT_SMALL:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->prev_xfs = container->current_xfs;
	    if ((container->current_xfs =
		 get_xfs(self,FANCY.small_font_name)) == NULL)
	      container->current_xfs = FANCY.brokenXFS;
	    break ;
	  }
	case ELT__TINY:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->prev_xfs = container->current_xfs;
	    if ((container->current_xfs = 
		 get_xfs(self,FANCY._tiny_font_name)) == NULL)
	      container->current_xfs = FANCY.brokenXFS;
	    break ;
	  }
	case ELT_HTML:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->prev_xfs = container->current_xfs;
	    if ((container->current_xfs = 
		 get_xfs(self,FANCY.normal_font_name)) == NULL)
	      container->current_xfs = FANCY.brokenXFS;
	    break ;
	  }
	case ELT_H1:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->prev_xfs = container->current_xfs;
	    if ((container->current_xfs = 
		 get_xfs(self,FANCY.header1_font_name)) == NULL)
	      container->current_xfs = FANCY.brokenXFS;
	    break ;
	  }
	case ELT_H2:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->prev_xfs = container->current_xfs;
	    if ((container->current_xfs = 
		 get_xfs(self,FANCY.header2_font_name)) == NULL)
	      container->current_xfs = FANCY.brokenXFS;
	    break ;
	  }
	case ELT_NO_CODE:
	case ELT_NO_B:
	case ELT_NO_I:
	case ELT_NO_SMALL:
	case ELT_NO__TINY:
	case ELT_NO_H1:
	case ELT_NO_H2:
	  {
	    elt->relative_x = elt->relative_y = 0;
	    elt->width = elt->height = 0;
	    elt->min_width = elt->min_height = 0;
	    container->current_xfs = container->prev_xfs;
	    break ;
	  }
	case ELT_STR:
	  {
	    if (elt->title)
	      break ;
	    elt->width = XTextWidth(container->current_xfs,
				    elt->str,
				    strlen(elt->str));
	    elt->height = container->current_xfs->ascent +
	      container->current_xfs->descent;
	    elt->min_width = elt->width;
	    elt->min_height = elt->height;
	    elt->relative_x = container->cursor_x;
	    elt->relative_y = container->cursor_y;
	    container->cursor_x += elt->width;
	    container->jump = MY_MAX(container->jump,elt->height);
	    elt->xfs = container->current_xfs;
	    break ;
	  }
	case ELT_LINK:
	  {
	    elt->width = XTextWidth(container->current_xfs,
				    elt->str,
				    strlen(elt->str));
	    elt->height = container->current_xfs->ascent +
	      container->current_xfs->descent + 1;
	    elt->min_width = elt->width;
	    elt->min_height = elt->height;
	    elt->relative_x = container->cursor_x;
	    elt->relative_y = container->cursor_y;
	    container->cursor_x += elt->width;
	    container->jump = MY_MAX(container->jump,elt->height);
	    elt->xfs = container->current_xfs;
	    break ;
	  }
	case ELT_SELECT:
	  {
	    if (!elt->widget)
	      {
		t_vec				*vec;
		t_status			status;

		if ((vec = FANCY_VEC_NEW(VEC_BASE,&status)) == NULL)
		  {
		    XmgWarning("XmgFancyWidget: FANCY_VEC_NEW: %s",
			       err_msg(status));
		    exit(1);
		  }
		VEC_FOR(elt->sub_elts,t_elt *sub_elt)
		  {
		    char			*value;

		    if (VEC_COUNT(sub_elt->sub_elts) == 1)
		      {
			t_elt			*str_elt;

			str_elt = VEC_AT(sub_elt->sub_elts,0);
			value = str_elt->str;
		      }
		    else
		      value = sub_elt->value;
		    if ((status = vec_add(vec,value)) != 0)
		      {
			XmgWarning("XmgFancyWidget: vec_add: %s",
				   err_msg(status));
			exit(1);
		      }
		  }
		VEC_ENDFOR;
		if (VEC_COUNT(vec) == 0)
		  {
		    if (FANCY.badHTMLWarnings)
		      {
			XmgWarning("XmgFancyWidget: no OPTION in SELECT");
		      }
		    elt->displayable = False;
		    elt->computable = False;
		    vec_delete(vec);
		    break ;
		  }
		elt->widget =
		  XmgFancyCreatePulldownFromVecStr(self,
						   vec,
						   (XtCallbackProc)
						   XmgPulldownMenuCallback,
						   container->current_xfs,
						   container->bgcolor);
		elt->mapped = False;
		vec_delete(vec);
	      }
	    XtVaGetValues(elt->widget,
                          XtNwidth,		&(elt->width),
                          XtNheight,		&(elt->height),
			  XtNborderWidth,	&(elt->border),
                          NULL);
#ifdef NOTDEF
	    elt->width += 2 * elt->border;
	    elt->height += 2 * elt->border;
#endif
	    elt->relative_x = container->cursor_x;
	    elt->relative_y = container->cursor_y;
	    elt->min_width = elt->width;
	    elt->min_height = elt->height;
	    container->cursor_x += elt->width;
	    container->jump = MY_MAX(container->jump,elt->height);
	    break ;
	  }
	case ELT_INPUT:
	  {
	    if (!elt->widget)
	      {
		switch (elt->input_type)
		  {
		  case INPUT_TYPE_SUBMIT:
		    elt->widget = 
		      XtVaCreateManagedWidget("xmgFancySubmit",
					      commandWidgetClass,
					      self,
					      XtNmappedWhenManaged,
					      False,
					      XtNfont,
					      container->current_xfs,
					      XtNbackground,
					      container->bgcolor,
					      XtNlabel,
					      !strcmp(elt->value,"")?"submit":
					      elt->value,
					      NULL);
		    elt->mapped = False;
		    XtAddCallback(elt->widget,
				  XtNcallback,
				  (XtCallbackProc)command_submit,
				  elt);
		    break ;
		  case INPUT_TYPE_RESET:
		    elt->widget = 
		      XtVaCreateManagedWidget("xmgFancyReset",
					      commandWidgetClass,
					      self,
					      XtNmappedWhenManaged,
					      False,
					      XtNfont,
					      container->current_xfs,
					      XtNbackground,
					      container->bgcolor,
					      XtNlabel,
					      !strcmp(elt->value,"")?"submit":
					      elt->value,
					      NULL);
		    elt->mapped = False;
		    XtAddCallback(elt->widget,
				  XtNcallback,
				  (XtCallbackProc)command_reset,
				  elt);
		    break ;
		  case INPUT_TYPE_CHECKBOX:
		  case INPUT_TYPE_RADIO:
		    elt->widget = 
		      XtVaCreateManagedWidget("checkbox",
					      toggleWidgetClass,
					      self,
					      XtNmappedWhenManaged,
					      False,
					      XtNbackground,
					      container->bgcolor,
					      XtNstate,
					      elt->checked,
					      XtNlabel,
					      " ",
					      NULL);
		    elt->mapped = False;
		    if (elt->input_type == INPUT_TYPE_RADIO)
		      {
			t_elt		*other_radio_elt;

			if (other_radio_elt =
			    get_radio_by_name_different_from(FANCY.root_elt,
							     elt->form,
							     elt->name,
							     elt))
			  {
			    if (other_radio_elt->widget)
			      XtVaSetValues(elt->widget,
					    XtNradioGroup,
					    other_radio_elt->widget,
					    NULL);
			  }
			XtAddCallback(elt->widget,
				      XtNcallback,
				      (XtCallbackProc)radio_callback,
				      elt);
		      }
		    break ;
		  default:
		    {
		      XFontStruct		*fixed_xfs;

		      if ((fixed_xfs = 
			   get_xfs(self,FANCY.fixed_font_name)) == NULL)
			fixed_xfs = FANCY.brokenXFS;
		      elt->widget = 
			XtVaCreateManagedWidget("xmgFancyInput",
						textfieldWidgetClass,
						self,
						XtNmappedWhenManaged,
						False,
						XtNfont,
						fixed_xfs,
						XtNstring,
						elt->value,
						NULL);
		      elt->mapped = False;
		      if (elt->fixed_width != 0)
			{
			  Dimension		proportional_width;
			  
			  proportional_width = elt->fixed_width *
			    XTextWidth(fixed_xfs," ",1);
			  XtVaSetValues(elt->widget,
					XtNwidth,
					proportional_width,
					NULL);
			}
		      break ;
		    }
		  }
	      }
	    XtVaGetValues(elt->widget,
                          XtNwidth,		&(elt->width),
                          XtNheight,		&(elt->height),
			  XtNborderWidth,	&(elt->border),
                          NULL);
#ifdef NOTDEF
	    elt->width += 2 * elt->border;
	    elt->height += 2 * elt->border;
#endif
	    elt->relative_x = container->cursor_x;
	    elt->relative_y = container->cursor_y;
	    elt->min_width = elt->width;
	    elt->min_height = elt->height;
	    container->cursor_x += elt->width;
	    container->jump = MY_MAX(container->jump,elt->height);
	    break ;
	  }
	case ELT_IMG:
	  {
	    Window				root_ret;
	    int					x_ret;
	    int					y_ret;
	    unsigned int			width_ret;
	    unsigned int			height_ret;
	    unsigned int			border_ret;
	    unsigned int			depth_ret;

	    if (!(elt->img_inited))
	      {
		XtPointer			ptr;

		elt->img_inited = True;
		get_img(self,
			elt->src,
			FancyImgTypeAny,
			AnyDepth,
			&(elt->img_type),
			&ptr);
		if (elt->img_type == FancyImgTypeAny)	
		  {
		    if (FANCY.brokenPixmap == ((Pixmap)0))
		      {
			elt->displayable = False;
			elt->computable = False;
			break ;
		      }
		    else
		      {
			elt->img_type = FancyImgTypePixmap;
			elt->pixmap = FANCY.brokenPixmap;
		      }
		  }
		else
		  if (elt->img_type == FancyImgTypePixmap)
		    elt->pixmap = (Pixmap)ptr;
		  else
		    if (elt->img_type == FancyImgTypeXImage)
		      elt->ximage = (XImage *)ptr;
		    else
		      {
			XmgWarning("XmgFancyWidget: bad FancyImgType %d",
				   elt->img_type);
			exit(1);
		      }
	      }
	    if (elt->img_type == FancyImgTypePixmap)
	      XGetGeometry(XtDisplay(self),
			   elt->pixmap,
			   &root_ret,
			   &x_ret,
			   &y_ret,
			   &width_ret,
			   &height_ret,
			   &border_ret,
			   &depth_ret);
	    else /* FancyImgTypeXImage */
	      {
		width_ret = elt->ximage->width;
		height_ret = elt->ximage->height;
		border_ret = 0;
		depth_ret = elt->ximage->depth;
	      }
	    elt->relative_x = container->cursor_x;
	    elt->relative_y = container->cursor_y;
	    elt->width = width_ret;
	    elt->height = height_ret;
	    elt->border = border_ret;
	    elt->depth = depth_ret;
	    elt->min_width = elt->width;
	    elt->min_height = elt->height;
	    container->cursor_x += elt->width;
	    container->jump = MY_MAX(container->jump,elt->height);
	    break ;
	  }
	case ELT_HR:
	  {
	    elt->relative_x = container->cellpadding;
	    elt->relative_y = container->cursor_y +
	      (container->current_xfs->ascent +
	       container->current_xfs->descent) / 2;
	    elt->width = container->width;
	    elt->height = 0;
	    elt->min_width = elt->width;
	    elt->min_height = elt->height;
	    container->cursor_x = container->cellpadding;
	    container->cursor_y += container->current_xfs->ascent + 
	      container->current_xfs->descent;
	    break ;
	  }
	case ELT__CIRCLE:
	  {
	    elt->width = elt->fixed_width;
	    elt->height = elt->fixed_width;
	    elt->relative_x = container->cursor_x;
	    elt->relative_y = container->cursor_y;
	    container->cursor_x += elt->width;
	    break ;
	  }
	}
    }
  VEC_ENDFOR;
}

static VOID_FUNC			layout_from_sub_elts(self,container)
Widget					self;
t_elt					*container;
{
  t_status				status;

  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      if (!elt->computable)
	continue ;
      switch (elt->type)
	{
	case ELT_TABLE:
	  {
	    VEC_FOR(elt->sub_elts,t_elt *row)
	      {
		Dimension		proposed_width;
		
		proposed_width = 0;
		VEC_FOR(row->sub_elts,t_elt *cell)
		  {
		    layout_from_sub_elts(self,cell);
		    if (cell->percent > 0)
		      {
			proposed_width = 
			  MY_MAX(proposed_width,
				 cell->min_width * 100 / cell->percent);
		      }
		  }
		VEC_ENDFOR;
		if (proposed_width != 0)
		  if (proposed_width > row->min_width)
		    row->width = proposed_width;
	      }
	    VEC_ENDFOR;
	    break ;
	  }
	}
    }
  VEC_ENDFOR;
}

static VOID_FUNC			layout_adjust_rows(self,container)
Widget					self;
t_elt					*container;
{
  t_status				status;

  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      if (!elt->computable)
	continue ;
      switch (elt->type)
	{
	case ELT_TABLE:
	  {
	    Dimension			max_row_width;		
	    
	    max_row_width = 0;
	    VEC_FOR(elt->sub_elts,t_elt *row)
	      {
		max_row_width = MY_MAX(max_row_width,row->width);
	      }
	    VEC_ENDFOR;
	    VEC_FOR(elt->sub_elts,t_elt *row)
	      {
		row->width = max_row_width;
	      }
	    VEC_ENDFOR;
	    break ;
	  }
	}
    }
  VEC_ENDFOR;
}

static VOID_FUNC			layout_absolute(self,container)
Widget					self;
t_elt					*container;
{
  t_status				status;
  
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      if (!elt->computable)
	continue ;
      elt->x = container->x + elt->relative_x;
      elt->y = container->y + elt->relative_y;
      if (elt->type == ELT_TABLE ||
	  elt->type ==  ELT_ROW ||
	  elt->type == ELT_CELL)
	{
	  layout_absolute(self,elt);
	}
    }
  VEC_ENDFOR;
}

static VOID_FUNC			compute_root_elt_dimensions(self)
Widget					self;
{
  Dimension				max_width;
  Dimension				max_height;

  max_width = max_height = 0;
  VEC_FOR(FANCY.root_elt->sub_elts,t_elt *sub_elt)
    {
      Dimension	tmp;
      
      if (!sub_elt->computable)
	continue ;
      if ((tmp =
	   sub_elt->x +
	   sub_elt->width + 
	   2 * sub_elt->border) > max_width)
	max_width = tmp;
      if ((tmp =
	   sub_elt->y + 
	   sub_elt->height + 
	   2 * sub_elt->border) > max_height)
	max_height = tmp;
    }
  VEC_ENDFOR;
  FANCY.root_elt->width = max_width + FANCY.margin;
  FANCY.root_elt->height = max_height + FANCY.margin;
}

static GC				compute_fg_gc(self,
						      fgcolor,
						      bgcolor,
						      highlighted,
						      xfs)
Widget					self;
Pixel					fgcolor;
Pixel					bgcolor;
Boolean					highlighted;
XFontStruct				*xfs;
{
  XtGCMask				mask;
  XGCValues				xgcv;
  
  mask = GCForeground|GCBackground|GCFont;
  xgcv.foreground = highlighted?bgcolor:fgcolor;
  xgcv.background = highlighted?fgcolor:bgcolor;
  xgcv.font = xfs->fid;
  return (XtGetGC(self,mask,&xgcv));
}

static GC				compute_bg_gc(self,bgcolor)
Widget					self;
Pixel					bgcolor;
{
  XtGCMask				mask;
  XGCValues				xgcv;
  
  mask = GCForeground;
  xgcv.foreground = bgcolor;
  return (XtGetGC(self,mask,&xgcv));
}

static VOID_FUNC			draw_elt(self,elt,event,region)
Widget					self;
t_elt					*elt;
XEvent					*event; /* MIGHT BE NULL */
Region					region; /* MIGHT BE NULL */
{
  Pixel					textcolor;
  GC					fg_gc;
  GC					highlighted_fg_gc;
  GC					bg_gc;
  t_draw_string_proc			draw_string;
  XRectangle				rect;
  
  if (event)
    assert(event->type == Expose || event->type == GraphicsExpose);
  if (!elt->displayable)
    return ;
  if (region)
    {
      if (XRectInRegion(region,
			elt->x,
			elt->y,
			elt->width,
			elt->height) == RectangleOut)
	{
	  return ;
	}
    }
  if (elt->type == ELT_LINK)
    {
      if (elt == FANCY.current_link)
	{
	  if ((textcolor =
	       get_pixel(self,FANCY.v_link_color_name)) == (Pixel)-1)
	    textcolor = FANCY.brokenPixel;
	}
      else
	{
	  if ((textcolor = get_pixel(self,FANCY.link_color_name)) == (Pixel)-1)
	    textcolor = FANCY.brokenPixel;
	}
    }
  else
    {
      if ((textcolor = get_pixel(self,FANCY.text_color_name)) == (Pixel)-1)
	textcolor = FANCY.brokenPixel;
    }
  fg_gc = compute_fg_gc(self,
			textcolor,
			elt->bgcolor,
			FALSE,
			elt->xfs);
  highlighted_fg_gc = compute_fg_gc(self,
				    textcolor,
				    elt->bgcolor,
				    TRUE,
				    elt->xfs);
  bg_gc = compute_bg_gc(self,elt->bgcolor);
  if (region)
    {
      XClipBox(region,&rect);
      XSetClipRectangles(XtDisplay(self),
			 fg_gc,
			 0,
			 0,
			 &rect,
			 1,
			 Unsorted);
      XSetClipRectangles(XtDisplay(self),
			 bg_gc,
			 0,
			 0,
			 &rect,
			 1,
			 Unsorted);
    }
  switch (elt->type)
    {
    case ELT_LINK:
      XDrawLine(XtDisplay(self),
		  XtWindow(self),
		  fg_gc,
		  elt->x,
		  elt->y + elt->xfs->ascent + elt->xfs->descent,
                  elt->x + elt->width,
		  elt->y + elt->xfs->ascent + elt->xfs->descent);
    case ELT_STR:
      {
	draw_string = (t_draw_string_proc)XDrawImageString;
	if (elt->highlight_len == 0)
	  draw_string(XtDisplay(self),
		      XtWindow(self),
		      fg_gc,
		      elt->x,
		      elt->y + elt->xfs->ascent,
		      elt->str,
		      strlen(elt->str));
	else
	  if (elt->highlight_len == elt->len)
	    draw_string(XtDisplay(self),
			XtWindow(self),
			highlighted_fg_gc,
			elt->x,
			elt->y + elt->xfs->ascent,
			elt->str,
			strlen(elt->str));
	  else
	    {
	      draw_string(XtDisplay(self),
			  XtWindow(self),
			  fg_gc,
			  elt->x,
			  elt->y + elt->xfs->ascent,
			  elt->str,
			  elt->highlight_pos);
	      draw_string(XtDisplay(self),
			  XtWindow(self),
			  highlighted_fg_gc,
			  elt->x + XTextWidth(elt->xfs,
					      elt->str,
					      elt->highlight_pos),
			  elt->y + elt->xfs->ascent,
			  elt->str + elt->highlight_pos,
			  elt->highlight_len);
	      draw_string(XtDisplay(self),
			  XtWindow(self),
			  fg_gc,
			  elt->x + XTextWidth(elt->xfs,
					      elt->str,
					      elt->highlight_pos +
					      elt->highlight_len),
			  elt->y + elt->xfs->ascent,
			  elt->str + elt->highlight_pos + elt->highlight_len,
			  strlen(elt->str) - elt->highlight_pos - 
			  elt->highlight_len);
	    }
      }
      break ;
    case ELT_CELL:
      {
	XRectangle				rect;
	Region					sub_region;

#ifdef NOTDEF
	if (elt->bgcolor != get_pixel(self,FANCY.bg_color_name))
#endif
	  XFillRectangle(XtDisplay(self),
			 XtWindow(self),
			 bg_gc,
			 elt->x,
			 elt->y,
			 elt->width,
			 elt->height);
#ifdef NOTDEF
	else
	  XClearArea(XtDisplay(self),
		     XtWindow(self),
		     elt->x,
		     elt->y,
		     elt->width,
		     elt->height,
		     False);
#endif
	if (elt->border != 0)
	  {
	    XDrawRectangle(XtDisplay(self),
			   XtWindow(self),
			   FANCY.black_gc,
			   elt->x - 1,
			   elt->y - 1,
			   elt->width + 1,
			   elt->height + 1);
	    XDrawRectangle(XtDisplay(self),
			   XtWindow(self),
			   FANCY.black_gc,
			   elt->x - elt->border,
			   elt->y - elt->border,
			   elt->width + 2 * elt->border - 1,
			   elt->height + 2 * elt->border - 1);
	  }
	sub_region = XCreateRegion();
	rect.x = elt->x;
	rect.y = elt->y;
	rect.width = elt->width;
	rect.height = elt->height;
	XUnionRectWithRegion(&rect,region?region:sub_region,sub_region);
	VEC_FOR(elt->sub_elts,t_elt *sub_elt)
	  {
	    draw_elt(self,sub_elt,event,sub_region);
	  }
	VEC_ENDFOR;
	XDestroyRegion(sub_region);
	break ;
      }
    case ELT_ROW:
      {
	if (FANCY.debugDrawRowBorders)
	  if (elt->border != 0)
	    XDrawRectangle(XtDisplay(self),
			   XtWindow(self),
			   FANCY.black_gc,
			   elt->x,
			   elt->y,
			   elt->width,
			   elt->height);
	VEC_FOR(elt->sub_elts,t_elt *sub_elt)
	  {
	    draw_elt(self,sub_elt,event,region);
	  }
	VEC_ENDFOR;
	break ;
      case ELT_TABLE:
	if (elt->border != 0)
	  {
	    XDrawRectangle(XtDisplay(self),
			   XtWindow(self),
			   FANCY.black_gc,
			   elt->x - 1,
			   elt->y - 1,
			   elt->width + 1,
			   elt->height + 1);
	    XDrawRectangle(XtDisplay(self),
			   XtWindow(self),
			   FANCY.black_gc,
			   elt->x - elt->border,
			   elt->y - elt->border,
			   elt->width + 2 * elt->border - 1,
			   elt->height + 2 * elt->border - 1);
	  }
	VEC_FOR(elt->sub_elts,t_elt *sub_elt)
	  {
	    draw_elt(self,sub_elt,event,region);
	  }
	VEC_ENDFOR;
	break ;
      }
    case ELT_SELECT:
    case ELT_INPUT:
      {
	XtMoveWidget(elt->widget,
		     elt->x + elt->border,
		     elt->y + elt->border);
	if (!elt->mapped)
	  {
	    elt->mapped = True;
	    XtMapWidget(elt->widget);
	  }
	break ;
      }
    case ELT_IMG:
      {
	Region					sub_region;
	XRectangle				rect;

	sub_region = XCreateRegion();
	rect.x = elt->x;
	rect.y = elt->y;
	rect.width = elt->width;
	rect.height = elt->height;
	XUnionRectWithRegion(&rect,sub_region,sub_region);
	if (region)
	    XIntersectRegion(region,sub_region,sub_region);
	XClipBox(sub_region,&rect);
	if (elt->img_type == FancyImgTypePixmap)
	  {
	    if (elt->depth == 1)
	      XCopyPlane(XtDisplay(self),
			 elt->pixmap,
			 XtWindow(self),
			 fg_gc,
			 rect.x - elt->x,
			 rect.y - elt->y,
			 rect.width,
			 rect.height,
			 rect.x,
			 rect.y,
			 1);
	    else
	      if (elt->depth == CORE.depth)
		XCopyArea(XtDisplay(self),
			  elt->pixmap,
			  XtWindow(self),
			  fg_gc,
			  rect.x - elt->x,
			  rect.y - elt->y,
			  rect.width,
			  rect.height,
			  rect.x,
			  rect.y);
	  }
	else /* FancyImgTypeXImage */
	  {
	    XPutImage(XtDisplay(self),
		      XtWindow(self),
		      fg_gc,
		      elt->ximage,
		      rect.x - elt->x,
		      rect.y - elt->y,
		      rect.x,
		      rect.y,
		      rect.width,
		      rect.height);
	  }
	if (FANCY.debugDrawImgBorders)
	  XDrawRectangle(XtDisplay(self),
			 XtWindow(self),
			 FANCY.black_gc,
			 elt->x,
			 elt->y,
			 elt->width,
			 elt->height);
	XDestroyRegion(sub_region);
	break ;
      }
    case ELT_HR:
      {
	XDrawLine(XtDisplay(self),
		  XtWindow(self),
		  FANCY.black_gc,
		  elt->x,
		  elt->y,
		  elt->width,
		  elt->y);
	XDrawLine(XtDisplay(self),
		  XtWindow(self),
		  FANCY.white_gc,
		  elt->x,
		  elt->y + 1,
		  elt->width,
		  elt->y + 1);
	break ;
      }
    case ELT__CIRCLE:
      {
	XFillArc(XtDisplay(self),
		 XtWindow(self),
		 FANCY.black_gc,
		 elt->x,
		 elt->y,
		 elt->fixed_width,
		 elt->fixed_width,
		 0,
		 360 * 64);
#ifdef NOTDEF
	XDrawArc(XtDisplay(self),
		 XtWindow(self),
		 FANCY.black_gc,
		 elt->x,
		 elt->y,
		 elt->fixed_width,
		 elt->fixed_width,
		 0,
		 360 * 64);
#endif
	break ;
      }
    }
  XtReleaseGC(self,highlighted_fg_gc);
  XtReleaseGC(self,fg_gc);
  XtReleaseGC(self,bg_gc);
}

static VOID_FUNC			layout(self)
Widget					self;
{
  XtGeometryResult			result;
    
  if (FANCY.in_layout)
    return ;
  FANCY.in_layout = True;
  
  FANCY.root_elt->width = FANCY.root_elt->height = 2 * FANCY.margin;
  
  FANCY.root_elt->cursor_x =
    FANCY.root_elt->cursor_y = FANCY.root_elt->cellpadding;
  if ((FANCY.root_elt->current_xfs = 
       get_xfs(self,FANCY.fixed_font_name)) == NULL)
    FANCY.root_elt->current_xfs = FANCY.brokenXFS;
  FANCY.root_elt->prev_xfs = FANCY.root_elt->current_xfs;
  FANCY.root_elt->jump = FANCY.root_elt->current_xfs->ascent + 
    FANCY.root_elt->current_xfs->descent;
  layout_relative(self,FANCY.root_elt,0);
  
  layout_from_sub_elts(self,FANCY.root_elt);
  
  FANCY.root_elt->cursor_x = 
    FANCY.root_elt->cursor_y = FANCY.root_elt->cellpadding;
  if ((FANCY.root_elt->current_xfs = 
       get_xfs(self,FANCY.fixed_font_name)) == NULL)
    FANCY.root_elt->current_xfs = FANCY.brokenXFS;
  FANCY.root_elt->prev_xfs = FANCY.root_elt->current_xfs;
  FANCY.root_elt->jump = FANCY.root_elt->current_xfs->ascent + 
    FANCY.root_elt->current_xfs->descent;
  layout_relative(self,FANCY.root_elt,1);

  layout_adjust_rows(self,FANCY.root_elt);
  
  FANCY.root_elt->x = FANCY.root_elt->y = 0;
  layout_absolute(self,FANCY.root_elt);
  compute_root_elt_dimensions(self);

  FANCY.root_elt->cursor_x = 
    FANCY.root_elt->cursor_y = FANCY.root_elt->cellpadding;
  if ((FANCY.root_elt->current_xfs =
       get_xfs(self,FANCY.fixed_font_name)) == NULL)
    FANCY.root_elt->current_xfs = FANCY.brokenXFS;
  FANCY.root_elt->prev_xfs = FANCY.root_elt->current_xfs;
  FANCY.root_elt->jump = FANCY.root_elt->current_xfs->ascent + 
    FANCY.root_elt->current_xfs->descent;
  layout_relative(self,FANCY.root_elt,2);
  
  FANCY.root_elt->x = FANCY.root_elt->y = 0;
  layout_absolute(self,FANCY.root_elt);
  compute_root_elt_dimensions(self);
  
  {
    Dimension					width_ret;
    Dimension					height_ret;

    result = XtMakeResizeRequest(self,
				 FANCY.root_elt->width,
				 FANCY.root_elt->height,
				 &width_ret,
				 &height_ret);
    switch (result)
      {
      case XtGeometryDone:
	draw_elt(self,FANCY.root_elt,NULL,NULL);
	break ;
      case XtGeometryAlmost:
	XtMakeResizeRequest(self,
			    width_ret,
			    height_ret,
			    NULL,
			    NULL);
	break ;
      default:
	XtResizeWidget(self,
		       FANCY.root_elt->width,
		       FANCY.root_elt->height,
		       CORE.border_width);
	XtResizeWindow(self);
	break ;
      }
  }
  FANCY.in_layout = False;
}

static VOID_FUNC			delete_elts(self,elts,from_destroy)
Widget					self;
t_vec					*elts;
t_boolean				from_destroy;
{
  VEC_FOR(elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_LINK:
	  if (elt->href)
	    {
	      FANCY_FREE_PROC(elt->href,
			      "fancy",
			      "*:href");
	    }
	case ELT_STR:
	  {
	    FANCY_FREE_PROC(elt->str,
			    "fancy",
			    "*:str");
	    break ;
	  }
	case ELT_TABLE:
	  {
	    FANCY_FREE_PROC(elt->_name,
			    "fancy",
			    "*:_name");
	  }
	case ELT_CELL:
	case ELT_ROW:
	  {
	    delete_elts(self,elt->sub_elts,from_destroy);
	    vec_delete(elt->sub_elts);
	    break ;
	  }
	case ELT_INPUT:
	  {
	    switch (elt->input_type)
	      {
	      case INPUT_TYPE_HIDDEN:
		break ;
	      case INPUT_TYPE_SUBMIT:
	      case INPUT_TYPE_RESET:
	      case INPUT_TYPE_CHECKBOX:
	      case INPUT_TYPE_RADIO:
	      default:
		if (elt->widget && !from_destroy)
		  XtDestroyWidget(elt->widget);
	      }
	    FANCY_FREE_PROC(elt->name,
			    "fancy",
			    "*:name");
	    FANCY_FREE_PROC(elt->value,
			    "fancy",
			    "*:value");
	    break ;
	  }
	case ELT_FORM:
	  {
	    FANCY_FREE_PROC(elt->action,
			    "fancy",
			    "*:action");
	    break ;
	  }
	case ELT_SELECT:
	  {
	    delete_elts(self,elt->sub_elts,from_destroy);
	    vec_delete(elt->sub_elts);
	    if (elt->widget && !from_destroy)
	      XtDestroyWidget(elt->widget);
	    FANCY_FREE_PROC(elt->name,
			    "fancy",
			    "*:name");
	    break ;
	  }
	case ELT_OPTION:
	  {
	    delete_elts(self,elt->sub_elts,from_destroy);
	    vec_delete(elt->sub_elts);
	    FANCY_FREE_PROC(elt->value,
			    "fancy",
			    "*:value");
	    break ;
	  }
	case ELT_IMG:
	  {
#ifdef NOTDEF
	    /* DONE BY EXTERNAL LIB */
#endif
	    FANCY_FREE_PROC(elt->src,
			    "fancy",
			    "*:src");
	    break ;
	  }
	}
      FANCY_FREE_PROC(elt,
		      "fancy",
		      "*:elt");
    }
  VEC_ENDFOR;
}

static VOID_FUNC			zero_names(self)
Widget					self;
{
  FANCY.normal_font_name = NULL; 
  FANCY.small_font_name = NULL;
  FANCY._tiny_font_name = NULL;
  FANCY.italic_font_name = NULL;
  FANCY.bold_font_name = NULL;
  FANCY.header1_font_name = NULL;
  FANCY.header2_font_name = NULL;
  FANCY.fixed_font_name = NULL;
  FANCY.link_color_name = NULL;
  FANCY.v_link_color_name = NULL;
  FANCY.text_color_name = NULL;
  FANCY.fg_color_name = NULL;
  FANCY.bg_color_name = NULL;
}

static VOID_FUNC			free_names(self)
Widget					self;
{
  if (FANCY.normal_font_name)
    {
      FANCY_FREE_PROC(FANCY.normal_font_name,
		      "fancy",
		      "*:normal_font_name");
    } 
  if (FANCY.small_font_name)
    {
      FANCY_FREE_PROC(FANCY.small_font_name,
		      "fancy",
		      "*:small_font_name");
    }
  if (FANCY._tiny_font_name)
    {
      FANCY_FREE_PROC(FANCY._tiny_font_name,
		      "fancy",
		      "*:_tiny_font_name");
    }
  if (FANCY.italic_font_name)
    {
      FANCY_FREE_PROC(FANCY.italic_font_name,
		      "fancy",
		      "*:italic_font_name");
    }
  if (FANCY.bold_font_name)
    {
      FANCY_FREE_PROC(FANCY.bold_font_name,
		      "fancy",
		      "*:bold_font_name");
    }
  if (FANCY.header1_font_name)
    {
      FANCY_FREE_PROC(FANCY.header1_font_name,
		      "fancy",
		      "*:header1_font_name");
    }
  if (FANCY.header2_font_name)
    {
      FANCY_FREE_PROC(FANCY.header2_font_name,
		      "fancy",
		      "*:header2_font_name");
    }
  if (FANCY.fixed_font_name)
    {
      FANCY_FREE_PROC(FANCY.fixed_font_name,
		      "fancy",
		      "*:fixed_font_name");
    }
  if (FANCY.link_color_name)
    {
      FANCY_FREE_PROC(FANCY.link_color_name,
		      "fancy",
		      "*:link_color_name");
    }
  if (FANCY.v_link_color_name)
    {
      FANCY_FREE_PROC(FANCY.v_link_color_name,
		      "fancy",
		      "*:v_link_color_name");
    }
  if (FANCY.text_color_name)
    {
      FANCY_FREE_PROC(FANCY.text_color_name,
		      "fancy",
		      "*:text_color_name");
    }
  if (FANCY.fg_color_name)
    {
      FANCY_FREE_PROC(FANCY.fg_color_name,
		      "fancy",
		      "*:fg_color_name");
    }
  if (FANCY.bg_color_name)
    {
      FANCY_FREE_PROC(FANCY.bg_color_name,
		      "fancy",
		      "*:bg_color_name");
    }
}

static VOID_FUNC			set_names(self)
Widget					self;
{
  FANCY.normal_font_name = 
    fancy_strdup(FANCY.normalFontName,
		 "set_names:normal_font_name");
  FANCY.small_font_name =
    fancy_strdup(FANCY.smallFontName,
		 "set_names:small_font_name");
  FANCY._tiny_font_name =
    fancy_strdup(FANCY._tinyFontName,
		 "set_names:_tiny_font_name");
  FANCY.italic_font_name =
    fancy_strdup(FANCY.italicFontName,
		 "set_names:italic_font_name");
  FANCY.bold_font_name =
    fancy_strdup(FANCY.boldFontName,
		 "set_names:bold_font_name");
  FANCY.header1_font_name =
    fancy_strdup(FANCY.header1FontName,
		 "set_names:header1_font_name");
  FANCY.header2_font_name =
    fancy_strdup(FANCY.header2FontName,
		 "set_names:header2_font_name");
  FANCY.fixed_font_name =
    fancy_strdup(FANCY.fixedFontName,
		 "set_names:fixed_font_name");
  FANCY.link_color_name = fancy_strdup(FANCY.linkColorName,
				  "set_names:link_color_name");
  FANCY.v_link_color_name = fancy_strdup(FANCY.vLinkColorName,
				    "set_names:v_link_color_name");
  FANCY.text_color_name = fancy_strdup(FANCY.textColorName,
				  "set_names:text_color_name");
  FANCY.fg_color_name = fancy_strdup(FANCY.fgColorName,
				"set_names:fg_color_name");
  FANCY.bg_color_name = fancy_strdup(FANCY.bgColorName,
				"set_names:bg_color_name");
}

static XtResource			resources[] =
 {
   {XtNmargin,	XtCMargin,	XtRInt,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.margin),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.margin),	
    XtRImmediate,	(XtPointer)1 },	
   
   {XtNsubEltVecBase,	XtCSubEltVecBase,	XtRInt,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.subEltVecBase),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.subEltVecBase),	
    XtRImmediate,	(XtPointer)VEC_ONE_BASE },
   
   {XtNargsVecBase,	XtCArgsVecBase,	XtRInt,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.argsVecBase),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.argsVecBase),	
    XtRImmediate,	(XtPointer)VEC_ONE_BASE },
   
   {XtNvarsHashBase,	XtCVarsHashBase,	XtRInt,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.varsHashBase),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.varsHashBase),	
    XtRImmediate,	(XtPointer)HASH_ONE_BASE },	
   
   {XtNvarsVecBase,	XtCVarsVecBase,	XtRInt,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.varsVecBase),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.varsVecBase),	
    XtRImmediate,	(XtPointer)VEC_ONE_BASE },	
   
   {XtNformCallback,	XtCFormCallback,	XtRCallback,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.formCallback),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.formCallback),	
    XtRImmediate,	(XtPointer)NULL },	
   
   {XtNlinkCallback,	XtCLinkCallback,	XtRCallback,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.linkCallback),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.linkCallback),	
    XtRImmediate,	(XtPointer)NULL },

   {XtNtableCallback,	XtCTableCallback,	XtRCallback,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.tableCallback),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.tableCallback),	
    XtRImmediate,	(XtPointer)NULL },

   {XtNtitleCallback,	XtCTitleCallback,	XtRCallback,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.titleCallback),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.titleCallback),	
    XtRImmediate,	(XtPointer)NULL },	

   {XtNimgCallback,	XtCImgCallback,	XtRCallback,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.imgCallback),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.imgCallback),	
    XtRImmediate,	(XtPointer)NULL },	

   {XtNbadHTMLWarnings,	XtCBadHTMLWarnings,	XtRBoolean,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.badHTMLWarnings),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.badHTMLWarnings),	
    XtRImmediate,	(XtPointer)True },	

   {XtNdoCutAndPaste,	XtCDoCutAndPaste,	XtRBoolean,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.doCutAndPaste),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.doCutAndPaste),	
    XtRImmediate,	(XtPointer)False },	

#ifdef DEBUG
   {XtNdebugKeepSource,	XtCDebugKeepSource,	XtRBoolean,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.debugKeepSource),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.debugKeepSource),	
    XtRImmediate,	(XtPointer)True },	

   {XtNdebugDrawRowBorders,	XtCDebugDrawRowBorders,	XtRBoolean,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.debugDrawRowBorders),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.debugDrawRowBorders),	
    XtRImmediate,	(XtPointer)False },	

   {XtNdebugShowCmds,	XtCDebugShowCmds,	XtRBoolean,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.debugShowCmds),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.debugShowCmds),	
    XtRImmediate,	(XtPointer)False },	

   {XtNdebugShowComments,	XtCDebugShowComments,	XtRBoolean,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.debugShowComments),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.debugShowComments),	
    XtRImmediate,	(XtPointer)False },	

   {XtNforceBorder,	XtCForceBorder,	XtRDimension,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.forceBorder),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.forceBorder),	
    XtRImmediate,	(XtPointer)0 },	

   {XtNdebugCellSpacing,	XtCDebugCellSpacing,	XtRDimension,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.debugCellSpacing),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.debugCellSpacing),	
    XtRImmediate,	(XtPointer)0 },	
   
   {XtNdebugDrawImgBorders,	XtCDebugDrawImgBorders,	XtRBoolean,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.debugDrawImgBorders),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.debugDrawImgBorders),	
    XtRImmediate,	(XtPointer)False },	
#endif

   {XtNuserData,	XtCUserData,	XtRXTPointer,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.userData),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.userData),	
    XtRImmediate,	(XtPointer)NULL },	

   {XtNbrokenPixmap,	XtCBrokenPixmap,	XtRPixmap,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.brokenPixmap),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.brokenPixmap),	
    XtRImmediate,	(XtPointer)NULL },	

   {XtNbrokenXFS,	XtCBrokenXFS,	XtRFontStruct,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.brokenXFS),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.brokenXFS),	
    XtRString,	(XtPointer)"fixed"},	

   {XtNbrokenPixel,	XtCBrokenPixel,	XtRPixel,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.brokenPixel),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.brokenPixel),	
    XtRString,	(XtPointer)"black"},	

   {XtNnormalFontName,	XtCNormalFontName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.normalFontName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.normalFontName),	
    XtRImmediate,
    (XtPointer)"-adobe-times-medium-r-normal-*-14-*-*-*-*-*-*-*"},	

   {XtNsmallFontName,	XtCSmallFontName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.smallFontName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.smallFontName),	
    XtRImmediate,
    (XtPointer)"-adobe-times-medium-r-normal-*-12-*-*-*-*-*-*-*"},	

   {XtN_tinyFontName,	XtC_tinyFontName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy._tinyFontName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy._tinyFontName),	
    XtRImmediate,
    (XtPointer)"-adobe-times-medium-r-normal-*-8-*-*-*-*-*-*-*"},	

   {XtNitalicFontName,	XtCItalicFontName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.italicFontName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.italicFontName),	
    XtRImmediate,
    (XtPointer)"-adobe-times-medium-i-normal-*-14-*-*-*-*-*-*-*"},	

   {XtNboldFontName,	XtCBoldFontName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.boldFontName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.boldFontName),	
    XtRImmediate,
    (XtPointer)"-adobe-times-bold-r-normal-*-14-*-*-*-*-*-*-*"},	

   {XtNheader1FontName,	XtCHeader1FontName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.header1FontName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.header1FontName),	
    XtRImmediate,
    (XtPointer)"-adobe-times-bold-r-normal-*-24-*-*-*-*-*-*-*"},	

   {XtNheader2FontName,	XtCHeader2FontName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.header2FontName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.header2FontName),	
    XtRImmediate,
    (XtPointer)"-adobe-times-bold-r-normal-*-18-*-*-*-*-*-*-*"},	

   {XtNfixedFontName,	XtCFixedFontName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.fixedFontName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.fixedFontName),	
    XtRImmediate,
    (XtPointer)"-adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*"},

   {XtNlinkColorName,	XtCLinkColorName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.linkColorName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.linkColorName),	
    XtRImmediate,	(XtPointer)"black"},	

   {XtNvLinkColorName,	XtCVLinkColorName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.vLinkColorName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.vLinkColorName),	
    XtRImmediate,	(XtPointer)"black"},	

   {XtNtextColorName,	XtCTextColorName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.textColorName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.textColorName),	
    XtRImmediate,	(XtPointer)"black"},	

   {XtNfgColorName,	XtCFgColorName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.fgColorName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.fgColorName),	
    XtRImmediate,	(XtPointer)"black"},	

   {XtNbgColorName,	XtCBgColorName,	XtRString,	
    sizeof (((XmgFancyRec*)NULL)->xmgFancy.bgColorName),	
    XtOffsetOf(XmgFancyRec,	xmgFancy.bgColorName),	
    XtRImmediate,	(XtPointer)"white"},
};

/*
 * ACTIONS
 */

static VOID_FUNC			highlight_elts_i(self,
							 mouse_x,
							 mouse_y,
							 container,
							 wide_strip_region,
							 center_region,
						      fine_right_strip_region,
						      fine_left_strip_region,
							 center_rect)
Widget					self;
Position				mouse_x;
Position				mouse_y;
t_elt					*container;
Region					wide_strip_region;
Region					center_region;
Region					fine_right_strip_region;
Region					fine_left_strip_region;
XRectangle				*center_rect;
{
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    t_elt			*found_elt;
	    
	    highlight_elts_i(self,
			     mouse_x,
			     mouse_y,
			     elt,
			     wide_strip_region,
			     center_region,
			     fine_right_strip_region,
			     fine_left_strip_region,
			     center_rect);
	    break ;
	  }
	default:
	  if (elt->displayable &&
	      ((elt->type == ELT_STR || elt->type == ELT_LINK)))
	    {
	      int			result;
	      
	      result = XRectInRegion(wide_strip_region,
				     elt->x,
				     elt->y,
				     elt->width,
				     elt->height);
	      if (result == RectangleOut)
		{
		  if (elt->highlight_len != 0)
		    {
		      elt->highlight_len = 0;
		      draw_elt(self,elt,NULL,NULL);
		    }
		  break ;
		}
	      if (result == RectangleIn)
		{
		  t_boolean		redraw;

		  if (elt->highlight_pos != 0 ||
		      elt->highlight_len != elt->len)
		    redraw = TRUE;
		  else
		    redraw = FALSE;
		  elt->highlight_pos = 0;
		  elt->highlight_len = elt->len;
		  if (redraw)
		    draw_elt(self,elt,NULL,NULL);
		  break ;
		}
	      {
		Dimension		cumulated_str_width;
		int			i;
		int			highlight_len;
		int			highlight_pos;
		t_boolean		found;

		found = FALSE;
		cumulated_str_width = 0;
		highlight_pos = 0;
		highlight_len = 0;
		i = 0;
		while (i < elt->len)
		  {
		    Dimension		char_width;
		    int			result_right;
		    int			result_left;
		    int			result_center;
		    t_boolean		ok;
		    
		    char_width = XTextWidth(elt->xfs,
					    elt->str + i,
					    1),
		    result_right = XRectInRegion(fine_right_strip_region,
						 elt->x + cumulated_str_width,
						 elt->y,
						 char_width,
						 elt->height);
		    result_left = XRectInRegion(fine_left_strip_region,
						elt->x + cumulated_str_width,
						elt->y,
						char_width,
						elt->height);
		    if (center_rect->y > elt->y &&
			(center_rect->y + center_rect->height) < 
			(elt->y + elt->height))
		      {
			int		result_center;
			
			result_center = XRectInRegion(center_region,
						 elt->x + cumulated_str_width,
						      elt->y,
						      char_width,
						      elt->height);
			ok = result_center == RectangleIn ||
			  result_center == RectanglePart;
		      }
		    else
		      ok = result_right == RectangleIn ||
			result_right == RectanglePart ||
			result_left == RectangleIn ||
			result_left == RectanglePart;
		    if (ok)
		      {
			if (!found)
			  {
			    found = TRUE;
			    highlight_pos = i;
			  } 
			highlight_len++;
		      }
		    cumulated_str_width += char_width;
		    i++;
		  }
		if (elt->highlight_len != highlight_len ||
		    elt->highlight_pos != highlight_pos)
		  {
		    elt->highlight_pos = highlight_pos;
		    elt->highlight_len = highlight_len;
		    draw_elt(self,elt,NULL,NULL);
		  }
	      }
	    }
	  break ;
	}
    }
  VEC_ENDFOR;
}

static VOID_FUNC			highlight_elts(self,
						       mouse_x,
						       mouse_y,
						       container)
Widget					self;
Position				mouse_x;
Position				mouse_y;
t_elt					*container;
{
  XRectangle				center_rect;
  XRectangle				fine_right_strip_rect;
  XRectangle				fine_left_strip_rect;
  XRectangle				wide_strip_rect;
  Region				wide_strip_region;
  Region				center_region;
  Region				fine_right_strip_region;
  Region				fine_left_strip_region;

  center_rect.x = MY_MIN(mouse_x,FANCY.highlight_x);
  center_rect.y = MY_MIN(mouse_y,FANCY.highlight_y);
  center_rect.width = MY_MAX(mouse_x,FANCY.highlight_x) -
    center_rect.x;
  center_rect.height = MY_MAX(mouse_y,FANCY.highlight_y) -
    center_rect.y + 1;
  fine_right_strip_rect.x = 
    (mouse_y > FANCY.highlight_y)?FANCY.highlight_x:mouse_x;
  fine_right_strip_rect.y = 
    (mouse_y > FANCY.highlight_y)?FANCY.highlight_y:mouse_y;
  fine_right_strip_rect.width = CORE.width - fine_right_strip_rect.x;
  fine_right_strip_rect.height = 1;
  fine_left_strip_rect.x = 0;
  fine_left_strip_rect.y = 
    ((mouse_y > FANCY.highlight_y)?(mouse_y - 1):FANCY.highlight_y) - 1;
  fine_left_strip_rect.width = 
    (mouse_y > FANCY.highlight_y)?mouse_x:FANCY.highlight_x;
  fine_left_strip_rect.height = 1;
  wide_strip_rect.x = 0;
  wide_strip_rect.y = center_rect.y;
  wide_strip_rect.width = CORE.width;
  wide_strip_rect.height = center_rect.height;
  wide_strip_region = XCreateRegion();
  XUnionRectWithRegion(&wide_strip_rect,
		       wide_strip_region,
		       wide_strip_region);
  center_region = XCreateRegion();
  XUnionRectWithRegion(&center_rect,
		       center_region,
		       center_region);
  fine_right_strip_region = XCreateRegion();
  XUnionRectWithRegion(&fine_right_strip_rect,
		       fine_right_strip_region,
		       fine_right_strip_region);
  fine_left_strip_region = XCreateRegion();
  XUnionRectWithRegion(&fine_left_strip_rect,
		       fine_left_strip_region,
		       fine_left_strip_region);
  highlight_elts_i(self,
		   mouse_x,
		   mouse_y,
		   container,
		   wide_strip_region,
		   center_region,
		   fine_right_strip_region,
		   fine_left_strip_region,
		   &center_rect);
  XDestroyRegion(fine_left_strip_region);
  XDestroyRegion(fine_right_strip_region);
  XDestroyRegion(center_region);
  XDestroyRegion(wide_strip_region);
}

static VOID_FUNC			unhighlight_elts(self,container)
Widget					self;
t_elt					*container;
{
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    unhighlight_elts(self,elt);
	    break ;
	  }
	default:
	  if (elt->displayable)
	    {
	      if (elt->highlight_len != 0)
		{
		  elt->highlight_len = 0;
		  draw_elt(self,elt,NULL,NULL);
		}
	    }
	  break ;
	}
    }
  VEC_ENDFOR;
}

static VOID_FUNC			make_selection(self,container)
Widget					self;
t_elt					*container;
{
  VEC_FOR(container->sub_elts,t_elt *elt)
    {
      switch (elt->type)
	{
	case ELT_TABLE:
	case ELT_ROW:
	case ELT_CELL:
	  {
	    make_selection(self,elt);
	    break ;
	  }
	default:
	  if (elt->displayable &&
	      ((elt->type == ELT_STR || elt->type == ELT_LINK)))
	    {
	      if (elt->highlight_len != 0)
		{
		  t_status	status;

		  if ((status =
		       vec_str_add_with_len(FANCY.selection_vec,
					    elt->str + elt->highlight_pos,
					    elt->highlight_len)) != 0)
		    {
		      XmgWarning("XmgFancyWidget: %s",
				 err_msg(status));
		      exit(1);
		    }
		}
	    }
	  break ;
	}
    }
  VEC_ENDFOR;
}

static VOID_FUNC	xmgFancySelectLink(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  t_elt			*old;

  if (event->type != ButtonPress)
    {
      XmgWarning("XmgFancyWidget: bad X event %d for this action",event->type);
      return ;
    }
  if (FANCY.doCutAndPaste)
    {
      if (FANCY.highlight_time > 0)
	unhighlight_elts(self,
			 FANCY.root_elt);
      FANCY.highlight_x = event->xbutton.x;
      FANCY.highlight_y = event->xbutton.y;
      FANCY.highlight_time++;
      XtDisownSelection(self,
			XA_PRIMARY,
			CurrentTime);
    }
  old = FANCY.current_link;
  FANCY.current_link = get_link(self,event,FANCY.root_elt);
  if (old)
    {
      if (FANCY.current_link == old)
        return ;
      draw_elt(self,old,NULL,NULL);
    }
  if (FANCY.current_link)
    draw_elt(self,FANCY.current_link,NULL,NULL);
}

static VOID_FUNC	xmgFancySelectTable(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  t_elt			*table;

  if (event->type != ButtonPress)
    {
      XmgWarning("XmgFancyWidget: bad X event %d for this action",event->type);
      return ;
    }
  if (table = get_table(self,event,FANCY.root_elt))
    {
      XmgFancyTableCallbackStruct	cbs;
      
      cbs.name = table->_name;
      cbs.x = event->xbutton.x;
      cbs.y = event->xbutton.y;
      XtCallCallbackList(self,FANCY.tableCallback,&cbs);
    }
}

static Boolean			convert_selection(self,
						  selection,
						  target,
						  type,
						  value,
						  length,
						  format)
Widget				self;
Atom				*selection;
Atom				*target;
Atom				*type;
XtPointer			*value;
unsigned long			*length;
int				*format;
{
  XSelectionRequestEvent	*req;

  req = XtGetSelectionRequest(self,
			      *selection,
			      NULL);
  if (*target == XA_TARGETS(XtDisplay(self)))
    {
      Atom			*targetP;
      Atom			*std_targets;
      unsigned long		std_length;

      XmuConvertStandardSelection(self,
				  req->time,
				  selection,
				  target,
				  type,
				  (caddr_t *)(&std_targets),
				  &std_length,
				  format);
      *value = XtMalloc((unsigned)sizeof(Atom) * (std_length + 1));
      targetP = *(Atom **) value;
      *length = std_length + 1;
      *targetP++ = XA_STRING;
      memmove((char *)targetP,
	      (char *)std_targets,
	      sizeof (Atom) * std_length);
      XtFree((char *)std_targets);
      *type = XA_ATOM;
      *format = sizeof (Atom) * 8;
      return (True);
    }
  else 
    if (*target == XA_STRING) 
      {
	char			*nselection;

#ifdef NOTDEF
	fprintf(stderr,"convert_selection: `%s' (%d)\n",
		FANCY.selection,
		strlen(FANCY.selection));
#endif
	nselection = fancy_strdup(FANCY.selection); 
	*length = (long)strlen(FANCY.selection);
	*value = nselection;
	*type = XA_STRING;
	*format = 8;
	return (True);
      }
  return (False);
}

static VOID_FUNC	lose_selection(self,selection)
Widget			self;
Atom			*selection;
{
#ifdef NOTDEF
  fprintf(stderr,"lose selection\n");
#endif
  if (FANCY.highlight_time > 0)
    unhighlight_elts(self,
		     FANCY.root_elt);
}

static VOID_FUNC	xmgFancyCheckLink(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  t_boolean		do_link;

  do_link = TRUE;
  if (FANCY.doCutAndPaste)
    {
      t_status		status;

      assert(event->type == ButtonRelease);
      if (FANCY.selection)
	FANCY_FREE_PROC(FANCY.selection,
			"fancy_selection",
			"*:str");
      vec_str_destroy(FANCY.selection_vec);
      make_selection(self,FANCY.root_elt);
      if ((FANCY.selection = vec_str_to_str(FANCY.selection_vec,
					    &status)) == NULL)
	{
	  XmgWarning("XmgFancyWidget: %s",err_msg(status));
	  exit(1);
	}
      if (strlen(FANCY.selection) > 0)
	{
	  XtOwnSelection(self,
			 XA_PRIMARY,
			 event->xbutton.time,
			 convert_selection,
			 lose_selection,
			 NULL);
	  XChangeProperty(XtDisplay(self),
			  DefaultRootWindow(XtDisplay(self)),
			  XA_CUT_BUFFER0,
			  XA_STRING,
			  8,
			  PropModeReplace,
			  (unsigned char *)(FANCY.selection),
			  strlen(FANCY.selection));
	  do_link = FALSE;
	}
    }
  if (FANCY.current_link)
    {
      t_elt		*old;

      old = FANCY.current_link;
      FANCY.current_link = NULL;
      draw_elt(self,old,NULL,NULL);
      if (do_link)
	if (get_link(self,event,FANCY.root_elt) == old)
	  {
	    t_status			status;
	    XmgFancyLinkCallbackStruct	cbs;
	    
	    cbs.base_href = FANCY.base_href;
	    cbs.href = old->href;
	    cbs.new_window = FALSE;
	    XtCallCallbackList(self,FANCY.linkCallback,&cbs);
	  }
    }
}

static VOID_FUNC       xmgFancyCheckLinkNewWindow(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  if (FANCY.current_link)
    {
      t_elt	*old;

      old = FANCY.current_link;
      FANCY.current_link = NULL;
      draw_elt(self,old,NULL,NULL);
      if (get_link(self,event,FANCY.root_elt) == old)
	{
	  t_status			status;
	  XmgFancyLinkCallbackStruct	cbs;
	  
	  cbs.base_href = FANCY.base_href;
	  cbs.href = old->href;
	  cbs.new_window = TRUE;
	  XtCallCallbackList(self,FANCY.linkCallback,&cbs);
	}
    }
}

static VOID_FUNC	xmgFancyGrExp(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  Region		r;
  
  if (event->type != GraphicsExpose)
    return ;
  r = XCreateRegion();
  XtAddExposureToRegion(event,r);
  VEC_FOR(FANCY.root_elt->sub_elts,t_elt *elt)
    {
      draw_elt(self,elt,event,r);
    }
  VEC_ENDFOR;
  XDestroyRegion(r);
}

static VOID_FUNC	xmgFancyCut(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  if (FANCY.doCutAndPaste)
    {
      Position		mouse_x;
      Position		mouse_y;
      
      assert(event->type == ButtonPress || event->type == ButtonRelease ||
	     event->type == MotionNotify);
      if (event->type == ButtonPress ||
	  event->type == ButtonRelease)
	{
	  mouse_x = event->xbutton.x;
	  mouse_y = event->xbutton.y;
	}
      else
	if (event->type == MotionNotify)
	  {
	    mouse_x = event->xmotion.x;
	    mouse_y = event->xmotion.y;
	  }
      highlight_elts(self,
		     mouse_x,
		     mouse_y,
		     FANCY.root_elt);
    }
}

#ifdef DEBUG
static VOID_FUNC	xmgFancyViewSource(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  char			*source;
  t_status		status;
  
  if (FANCY.debugKeepSource)
    {
      Widget		shell;

      if ((source = vec_buf_str(FANCY.source_vec,&status)) == NULL)
	{
	  XmgWarning("XmgFancyWidget: vec_buf_str %s",err_msg(status));
	  exit(1);
	}
      INTERFACE(self,
		GETCHILDSHELL(shell)
		("xmgFancyViewSource",transientShellWidgetClass,
		 XtNmappedWhenManaged,	False,
		 XtNtransientFor,	self,
		 XtNallowShellResize,	True,
		 CHILD("xmgFancyViewSource",asciiTextWidgetClass,
		       XtNscrollHorizontal,
		       XawtextScrollWhenNeeded,
		       XtNscrollVertical,
		       XawtextScrollWhenNeeded,
		       XtNstring,
		       source,
		       END),
		 MANAGE,
		 END),
		ENDINTERFACE);
      XmgSetDestroyOnDelete(shell);
      XtPopup(shell,XtGrabNone);
      FANCY.source_vec->free_proc(source,
			     "fancy",
			     "*:str");
    }
  else
    XmgWarning("XmgFancyWidget: debugKeepSource is not set");
}

static VOID_FUNC	xmgFancyDoDebug(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  elt_show(FANCY.root_elt,TRUE,0);
}

static VOID_FUNC	xmgFancyRedoLayout(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  layout(self);
}

static VOID_FUNC	xmgFancyRedoParse(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  char			*source;
  t_status		status;
  
  if (FANCY.debugKeepSource)
    {
      if ((source = vec_buf_str(FANCY.source_vec,&status)) == NULL)
	{
	  XmgWarning("XmgFancyWidget: vec_buf_str %s",err_msg(status));
	  exit(1);
	}
      XmgFancyReset(self);
      XmgFancyParseBuf(self,source,strlen(source));
      FANCY.source_vec->free_proc(source,
				  "fancy",
				  "*:str");
    }
  else
    XmgWarning("XmgFancyWidget: debugKeepSource is not set");
}

static VOID_FUNC	xmgFancyDoReset(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  XmgFancyReset(self);
}

static VOID_FUNC    xmgFancyDoBordersAndRedoParse(self,event,params,num_params)
Widget		self;
XEvent		*event;
String		*params;
Cardinal	*num_params;
{
  FANCY.forceBorder = (FANCY.forceBorder + 1) % 5;
  xmgFancyRedoParse(self,event,params,num_params);
}

static VOID_FUNC	xmgFancyDoCellSpacingAndRedoParse(self,
							  event,
							  params,
							  num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  FANCY.debugCellSpacing = (FANCY.debugCellSpacing + 1) % 5;
  xmgFancyRedoParse(self,event,params,num_params);
}

static VOID_FUNC	xmgFancyDoXmgStatus(self,event,params,num_params)
Widget			self;
XEvent			*event;
String			*params;
Cardinal		*num_params;
{
  XmgStatus();
}
#endif

static XtActionsRec			actionsList[] = 
{
  {"xmgFancySelectLink",		xmgFancySelectLink},
  {"xmgFancySelectTable",		xmgFancySelectTable},
  {"xmgFancyCheckLink",			xmgFancyCheckLink},
  {"xmgFancyCheckLinkNewWindow",	xmgFancyCheckLinkNewWindow},
  {"xmgFancyGrExp",			xmgFancyGrExp},
  {"xmgFancyCut",			xmgFancyCut},
#ifdef DEBUG
  {"xmgFancyViewSource",		xmgFancyViewSource},
  {"xmgFancyDoDebug",			xmgFancyDoDebug},
  {"xmgFancyRedoLayout",		xmgFancyRedoLayout},
  {"xmgFancyRedoParse",			xmgFancyRedoParse},
  {"xmgFancyDoReset",			xmgFancyDoReset},
  {"xmgFancyDoBordersAndRedoParse",	xmgFancyDoBordersAndRedoParse},
  {"xmgFancyDoCellSpacingAndRedoParse",	xmgFancyDoCellSpacingAndRedoParse},
  {"xmgFancyDoXmgStatus",		xmgFancyDoXmgStatus},
#endif
};

#ifdef DEBUG
static char				defaultTranslations[] = "\
<Btn1Down>:				xmgFancySelectLink()\n\
<Btn1Up>:				xmgFancyCheckLink()\n\
<Btn2Down>:				xmgFancySelectLink()\n\
<Btn2Up>:				xmgFancyCheckLinkNewWindow()\n\
<GrExp>:				xmgFancyGrExp()\n\
Alt<Key>v:				xmgFancyViewSource()\n\
Alt<Key>d:				xmgFancyDoDebug()\n\
Alt<Key>l:				xmgFancyRedoLayout()\n\
Alt<Key>r:				xmgFancyRedoParse()\n\
Alt<Key>s:				xmgFancyDoReset()\n\
Alt<Key>b:				xmgFancyDoBordersAndRedoParse()\n\
Alt<Key>c:				xmgFancyDoCellSpacingAndRedoParse()\n\
Alt<Key>x:				xmgFancyDoXmgStatus()\n\
";
#else
static char				defaultTranslations[] = "\
<Btn1Down>:				xmgFancySelectLink()\n\
<Btn1Up>:				xmgFancyCheckLink()\n\
<Btn2Down>:				xmgFancySelectLink()\n\
<Btn2Up>:				xmgFancyCheckLinkNewWindow()\n\
<GrExp>:				xmgFancyGrExp()\n\
";
#endif

/*
 * METHODS
 */

static VOID_FUNC			_resolve_inheritance(class)
WidgetClass				class;
{
  XmgFancyWidgetClass			c;
  XmgFancyWidgetClass			super;
  static CompositeClassExtensionRec	extension_rec = 
  {
    NULL, NULLQUARK, XtCompositeExtensionVersion,
    sizeof(CompositeClassExtensionRec), True
  };
  CompositeClassExtensionRec		*ext;
  
  c = (XmgFancyWidgetClass)class;
  ext = (XtPointer)XtMalloc(sizeof(*ext));
  *ext = extension_rec;
  ext->next_extension = c->composite_class.extension;
  c->composite_class.extension = ext;
  if (class == xmgFancyWidgetClass) return;
  super = (XmgFancyWidgetClass)class->core_class.superclass;
}

static VOID_FUNC			change_managed(self)
Widget					self;
{
}

static XtGeometryResult			geometry_manager(child,request,reply)
Widget					child;
XtWidgetGeometry			*request;
XtWidgetGeometry			*reply;
{
  Widget				self;

  self = XtParent(child); 
  if (request->request_mode & CWWidth)
    child->core.width = request->width;
  if (request->request_mode & CWHeight)
    child->core.height = request->height;
  if (request->request_mode & CWBorderWidth)
    child->core.border_width = request->border_width;
  layout(self);
  return (XtGeometryYes);
}

static VOID_FUNC			resize(self)
Widget					self;
{
  if (XtIsRealized(self))
    {
      XClearArea(XtDisplay(self),
		 XtWindow(self),
		 0,
		 0,
		 CORE.width,
		 CORE.height,
		 True);
    }
}

static Boolean			set_values(old,request,self,args,num_args)
Widget				old;
Widget				request;
Widget				self;
ArgList				args;
Cardinal			*num_args;
{
  XmgFancyWidget		oldfancy;
  XmgFancyWidget		requestfancy;

  oldfancy = (XmgFancyWidget)old;
  requestfancy = (XmgFancyWidget)request;

#define OLD oldfancy->xmgFancy
#define REQ requestfancy->xmgFancy

  if (REQ.debugKeepSource != OLD.debugKeepSource)
    {
      XmgWarning("XmgFancyWidget: can't change debugKeepSource value");
      FANCY.debugKeepSource = OLD.debugKeepSource;
    }
  return (False);
}

static VOID_FUNC		class_initialize()
{
  
}

static VOID_FUNC		initialize(request,self,args,num_args)
Widget				request;
Widget				self;
ArgList				args;
Cardinal			*num_args;
{
  t_status			status;
  XGCValues			xgcv;
  
  xgcv.foreground = BlackPixel(XtDisplay(self),
			       DefaultScreen(XtDisplay(self)));
  FANCY.black_gc = XtGetGC(self,
			   GCForeground,
			   &xgcv);
  xgcv.foreground = WhitePixel(XtDisplay(self),
			       DefaultScreen(XtDisplay(self)));
  FANCY.white_gc = XtGetGC(self,
			   GCForeground,
			   &xgcv);
  if (FANCY.debugKeepSource)
    if ((FANCY.source_vec = FANCY_VEC_NEW(VEC_ONE_BASE,
					  &status)) == NULL)
      {
	XmgWarning("XmgFancyWidget: FANCY_VEC_NEW %s",err_msg(status));
	exit(1);
      }
  ((XmgFancyWidgetClass)self->core.widget_class)->
    core_class.compress_exposure = XtExposeCompressMaximal;
/*#ifdef NOTDEF*/
  ((XmgFancyWidgetClass)self->core.widget_class)->
    core_class.compress_motion = True;
/*#endif*/
  if ((FANCY.root_elt = XMG_ALLOC_PROC(sizeof (t_elt),
				       "fancy",
				       "initialize:root_elt",
				       &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: XMG_ALLOC_PROC %s",err_msg(status));
      exit(1);
    }
  if ((FANCY.root_elt->sub_elts = FANCY_VEC_NEW(FANCY.subEltVecBase,
						&status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: FANCY_VEC_NEW %s",err_msg(status));
      exit(1);
    }
  if ((FANCY.args = FANCY_VEC_NEW(FANCY.argsVecBase,
				  &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: FANCY_VEC_NEW %s",err_msg(status));
      exit(1);
    }
  if ((FANCY.table_stack = FANCY_VEC_NEW(VEC_ONE_BASE,
					 &status)) == NULL)
    {
      XmgWarning("XmgFancyWidget: FANCY_VEC_NEW %s",err_msg(status));
      exit(1);
    }
  FANCY.href = NULL;
  FANCY.base_href = NULL;
  FANCY.in_layout = False;
  if (FANCY.doCutAndPaste)
    {
      XtOverrideTranslations(self,
            XtParseTranslationTable("<Btn1Motion>: xmgFancyCut()"));
      if ((FANCY.selection_vec = FANCY_VEC_NEW(VEC_ONE_BASE,
					       &status)) == NULL)
	{
	  XmgWarning("XmgFancyWidget: FANCY_VEC_NEW %s",err_msg(status));
	  exit(1);
	}
      FANCY.selection = NULL;
    }
  zero_names(self);
  XmgFancyReset(self);
}

static VOID_FUNC			destroy(self)
Widget					self;
{
  if (FANCY.doCutAndPaste)
    {
      if (FANCY.selection)
	FANCY_FREE_PROC(FANCY.selection,
			"fancy_selection",
			"*:str");
      vec_str_delete(FANCY.selection_vec);
    }
  if (FANCY.debugKeepSource)
    vec_buf_delete(FANCY.source_vec);
    if (FANCY.base_href)
    {
      FANCY_FREE_PROC(FANCY.base_href,
		      "fancy",
		      "*:base_href");
    }
  if (FANCY.href)
    {
      FANCY_FREE_PROC(FANCY.href,
		      "fancy",
		      "*:href");
    }
  free_names(self);
  delete_elts(self,FANCY.root_elt->sub_elts,TRUE);
  vec_delete(FANCY.root_elt->sub_elts);
  XMG_FREE_PROC(FANCY.root_elt,
		"fancy",
		"initialize:root_elt");
  vec_str_delete(FANCY.args);
  vec_delete(FANCY.table_stack);
  XtReleaseGC(self,FANCY.white_gc);
  XtReleaseGC(self,FANCY.black_gc);
}

static VOID_FUNC			expose(self,event,region)
Widget					self;
XEvent					*event;
Region					region;
{
  Region				r;

  r = XCreateRegion();
  XtAddExposureToRegion(event,r);
  VEC_FOR(FANCY.root_elt->sub_elts,t_elt *elt)
    {
      draw_elt(self,elt,event,r);
    }
  VEC_ENDFOR;
  XDestroyRegion(r);
}

static XtGeometryResult		query_geometry(self,intended,preferred)
Widget				self;
XtWidgetGeometry		*intended;
XtWidgetGeometry		*preferred;
{
  return (XtGeometryNo);
}

XmgFancyClassRec			xmgFancyClassRec =
 {
   {
						/* core_class fields  */
     (WidgetClass) &compositeClassRec,		/* superclass         */
     "XmgFancy",				/* class_name         */
     sizeof (XmgFancyRec),			/* widget_size        */
     class_initialize,				/* class_init         */
     _resolve_inheritance,			/* class_part_init    */
     FALSE,					/* class_inited       */
     initialize,				/* initialize         */
     NULL,					/* initialize_hook    */
     XtInheritRealize,				/* realize            */
     actionsList,				/* actions            */
     XtNumber(actionsList),			/* num_actions        */
     resources,					/* resources          */
     XtNumber(resources),			/* num_resources      */
     NULLQUARK,					/* xrm_class          */
     False ,					/* compress_motion    */
     False ,					/* compress_exposure  */
     False ,					/* compress_enterleave*/
     False ,					/* visible_interest   */
     destroy,					/* destroy            */
     resize,					/* resize             */
     expose,					/* expose             */
     set_values,				/* set_values         */
     NULL,					/* set_values_hook    */
     XtInheritSetValuesAlmost,			/* set_values_almost  */
     NULL,					/* get_values_hook    */
     XtInheritAcceptFocus,			/* accept_focus       */
     XtVersion,					/* version            */
     NULL,					/* callback_private   */
     defaultTranslations,			/* tm_table           */
#ifdef NOTDEF
     XtInheritQueryGeometry,			/* query_geometry     */
#else
     query_geometry,
#endif
     XtInheritDisplayAccelerator,		/* display_accelerator*/
     NULL					/* extension          */
   },
   {						/* composite_class fields */
     geometry_manager,				/* geometry_manager    */
     change_managed,				/* change_managed      */
     XtInheritInsertChild,			/* insert_child        */
     XtInheritDeleteChild,			/* delete_child        */
     NULL					/* extension           */
   },
   {						/* XmgFancy_class part */
     0
   },
 };

WidgetClass		xmgFancyWidgetClass = (WidgetClass) &xmgFancyClassRec;

/*
 * PUBLIC ROUTINES
 */

/* parses an HTML buffer to a fancy widget.
   It is possible to do subsequent calls to this function as parsing
   state is stored in the widget. */
VOID_FUNC				XmgFancyParseBuf(self,buf,len)
Widget					self;
char					*buf;
unsigned  int				len;
{
  int					i;
  t_status				status;

  if (FANCY.debugKeepSource)
    if ((status = vec_buf_add(FANCY.source_vec,buf,len)) != 0)
      {
	XmgWarning("XmgFancyWidget: vec_buf_add %s",err_msg(status));
	exit(1);
      }
#ifdef NOTDEF
  write(2,buf,len);
#endif
  i = 0;
  while (i < len)
    {
      switch (buf[i])
	{      
	case '\n':
	  FANCY.lineno++;
	default:
	  FANCY.state_proc(self,buf[i]);
	  break ;
	}
      i++;
    }
  if (FANCY.state_proc == state_text && FANCY.buf[0] != 0)
    state_text(self,-1);
#ifdef NOTDEF
  elt_show(FANCY.root_elt,TRUE,0);
#endif
  layout(self);
}

/* resets a fancy widget.
   After this call, the widget is reusable for a new HTML page. */
VOID_FUNC				XmgFancyReset(self)
Widget					self;	/* Fancy widget */
{
  t_status				status;
  
  if (XtIsRealized(self))
    {
      XClearArea(XtDisplay(self),
		 XtWindow(self),
		 0,
		 0,
		 CORE.width,
		 CORE.height,
		 True);
    }
  free_names(self);
  set_names(self);
  CORE.width = CORE.height = 2 * FANCY.margin;
  FANCY.buf[0] = 0;
  FANCY.state_proc = (t_state_proc)state_text;
  FANCY.lineno = 1;
  FANCY.current_table = NULL;
  FANCY.current_form = NULL;
  FANCY.current_select = NULL;
  vec_destroy(FANCY.table_stack);
  if (FANCY.debugKeepSource)
    vec_buf_destroy(FANCY.source_vec);
  FANCY.root_elt->type = ELT_ROOT;
  FANCY.root_elt->cellspacing = FANCY.margin;
  FANCY.root_elt->cellpadding = FANCY.margin;
  FANCY.root_elt->border = CORE.border_width;
  if ((FANCY.root_elt->fgcolor = 
       get_pixel(self,FANCY.fg_color_name)) == ((Pixel)-1))
    FANCY.root_elt->fgcolor = FANCY.brokenPixel;
  if ((FANCY.root_elt->bgcolor = 
       get_pixel(self,FANCY.bg_color_name)) == ((Pixel)-1))
    FANCY.root_elt->bgcolor = FANCY.brokenPixel;
  XtVaSetValues(self,
		XtNbackground,	FANCY.root_elt->bgcolor,
		NULL);
  if ((FANCY.root_elt->current_xfs = 
       get_xfs(self,FANCY.fixed_font_name)) == NULL)
    FANCY.root_elt->current_xfs = FANCY.brokenXFS;
  FANCY.root_elt->prev_xfs = FANCY.root_elt->current_xfs;
  if (FANCY.base_href)
    {
      FANCY_FREE_PROC(FANCY.base_href,
		      "fancy",
		      "*:base_href");
      FANCY.base_href = NULL;
    }
  if (FANCY.href)
    {
      FANCY_FREE_PROC(FANCY.href,
		      "fancy",
		      "*:href");
      FANCY.href = NULL;
    }
  FANCY.next_str_is_a_link = False;
  FANCY.current_link = NULL;
  FANCY.next_str_is_a_title = False;
  FANCY.do_br_on_nl = True;
  delete_elts(self,FANCY.root_elt->sub_elts,FALSE);
  vec_destroy(FANCY.root_elt->sub_elts);
  FANCY.highlight_time = 0;
}

char				*XmgFancyGetTableName(self,x,y)
Widget				self;
Position			x;
Position			y;
{
  t_elt				*table;

  if (table = get_table_from_xy(self,x,y,FANCY.root_elt))
    return (table->_name);
  else
    return (NULL);
}
