text: /* 
   * tixTList.c --
   *
   *	This module implements "TList" widgets.
   *
   * Copyright (c) 1993-1999 Ioi Kim Lam.
   * Copyright (c) 2000      Tix Project Group.
   *
   * See the file "license.terms" for information on usage and redistribution
   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
   *
   * $Id: tixTList.c,v 1.6 2008/02/28 04:05:29 hobbs Exp $
   */
  
  #include <tixPort.h>
  #include <tixInt.h>
  #include <tixDef.h>
  #include <tixTList.h>
  
  #define TIX_UP		1
  #define TIX_DOWN	2
  #define TIX_LEFT	3
  #define TIX_RIGHT 	4
  
  /*
   * Information used for argv parsing.
   */
  static Tk_ConfigSpec configSpecs[] = {
      {TK_CONFIG_COLOR, "-background", "background", "Background",
         DEF_TLIST_BG_COLOR, Tk_Offset(WidgetRecord, normalBg),
         TK_CONFIG_COLOR_ONLY},
  
      {TK_CONFIG_COLOR, "-background", "background", "Background",
         DEF_TLIST_BG_MONO, Tk_Offset(WidgetRecord, normalBg),
         TK_CONFIG_MONO_ONLY},
  
      {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
         (char *) NULL, 0, 0},
  
      {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
         (char *) NULL, 0, 0},
  
      {TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground",
         "HighlightBackground",
         DEF_TLIST_BG_COLOR, Tk_Offset(WidgetRecord, border),
         TK_CONFIG_COLOR_ONLY},
  
      {TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground",
         "HighlightBackground",
         DEF_TLIST_BG_MONO, Tk_Offset(WidgetRecord, border),
         TK_CONFIG_MONO_ONLY},
  
      {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
         DEF_TLIST_BORDER_WIDTH, Tk_Offset(WidgetRecord, borderWidth), 0},
  
      {TK_CONFIG_STRING, "-browsecmd", "browseCmd", "BrowseCmd",
  	DEF_TLIST_BROWSE_COMMAND, Tk_Offset(WidgetRecord, browseCmd),
  	TK_CONFIG_NULL_OK},
  
      {TK_CONFIG_STRING, "-command", "command", "Command",
         DEF_TLIST_COMMAND, Tk_Offset(WidgetRecord, command),
         TK_CONFIG_NULL_OK},
  
      {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
         DEF_TLIST_CURSOR, Tk_Offset(WidgetRecord, cursor),
         TK_CONFIG_NULL_OK},
  
      {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
         (char *) NULL, 0, 0},
  
      {TK_CONFIG_FONT, "-font", "font", "Font",
         DEF_TLIST_FONT, Tk_Offset(WidgetRecord, font), 0},
  
      {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
         DEF_TLIST_FG_COLOR, Tk_Offset(WidgetRecord, normalFg),
         TK_CONFIG_COLOR_ONLY},
  
      {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
         DEF_TLIST_FG_MONO, Tk_Offset(WidgetRecord, normalFg),
         TK_CONFIG_MONO_ONLY},
  
      {TK_CONFIG_INT, "-height", "height", "Height",
         DEF_TLIST_HEIGHT, Tk_Offset(WidgetRecord, height), 0},
  
      {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
         DEF_TLIST_HIGHLIGHT_COLOR, Tk_Offset(WidgetRecord, highlightColorPtr),
         TK_CONFIG_COLOR_ONLY},
  
      {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
         DEF_TLIST_HIGHLIGHT_MONO, Tk_Offset(WidgetRecord, highlightColorPtr),
         TK_CONFIG_MONO_ONLY},
  
      {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
         "HighlightThickness",
         DEF_TLIST_HIGHLIGHT_WIDTH, Tk_Offset(WidgetRecord, highlightWidth), 0},
  
      {TK_CONFIG_CUSTOM, "-itemtype", "itemType", "ItemType",
         DEF_TLIST_ITEM_TYPE, Tk_Offset(WidgetRecord, diTypePtr),
         0, &tixConfigItemType},
  
      {TK_CONFIG_UID, "-orient", "orient", "Orient",
  	DEF_TLIST_ORIENT, Tk_Offset(WidgetRecord, orientUid), 0},
  
      {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
  	DEF_TLIST_PADX, Tk_Offset(WidgetRecord, padX), 0},
  
      {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
  	DEF_TLIST_PADY, Tk_Offset(WidgetRecord, padY), 0},
  
      {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
         DEF_TLIST_RELIEF, Tk_Offset(WidgetRecord, relief), 0},
  
      {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
  	DEF_TLIST_SELECT_BG_COLOR, Tk_Offset(WidgetRecord, selectBorder),
  	TK_CONFIG_COLOR_ONLY},
  
      {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
  	DEF_TLIST_SELECT_BG_MONO, Tk_Offset(WidgetRecord, selectBorder),
  	TK_CONFIG_MONO_ONLY},
  
      {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth","BorderWidth",
         DEF_TLIST_SELECT_BORDERWIDTH,Tk_Offset(WidgetRecord, selBorderWidth),0},
  
      {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
         DEF_TLIST_SELECT_FG_COLOR, Tk_Offset(WidgetRecord, selectFg),
         TK_CONFIG_COLOR_ONLY},
  
      {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
         DEF_TLIST_SELECT_FG_MONO, Tk_Offset(WidgetRecord, selectFg),
         TK_CONFIG_MONO_ONLY},
  
      {TK_CONFIG_UID, "-selectmode", "selectMode", "SelectMode",
  	DEF_TLIST_SELECT_MODE, Tk_Offset(WidgetRecord, selectMode), 0},
  
      {TK_CONFIG_UID, "-state", (char*)NULL, (char*)NULL,
         DEF_TLIST_STATE, Tk_Offset(WidgetRecord, state), 0},
  
      {TK_CONFIG_STRING, "-sizecmd", "sizeCmd", "SizeCmd",
         DEF_TLIST_SIZE_COMMAND, Tk_Offset(WidgetRecord, sizeCmd),
         TK_CONFIG_NULL_OK},
   
      {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
  	DEF_TLIST_TAKE_FOCUS, Tk_Offset(WidgetRecord, takeFocus),
  	TK_CONFIG_NULL_OK},
  
      {TK_CONFIG_INT, "-width", "width", "Width",
  	DEF_TLIST_WIDTH, Tk_Offset(WidgetRecord, width), 0},
  
      {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
         DEF_TLIST_X_SCROLL_COMMAND,
         Tk_Offset(WidgetRecord, scrollInfo[0].command),
         TK_CONFIG_NULL_OK},
  
      {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
         DEF_TLIST_Y_SCROLL_COMMAND,
         Tk_Offset(WidgetRecord, scrollInfo[1].command),
         TK_CONFIG_NULL_OK},
  
      {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
         (char *) NULL, 0, 0}
  };	
  
  #define DEF_TLISTENTRY_STATE	 "normal"
  
  static Tk_ConfigSpec entryConfigSpecs[] = {
  
      {TK_CONFIG_UID, "-state", (char*)NULL, (char*)NULL,
         DEF_TLISTENTRY_STATE, Tk_Offset(ListEntry, state), 0},
  
      {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
         (char *) NULL, 0, 0}
  };
  
  static Tix_ListInfo entListInfo = {
      Tk_Offset(ListEntry, next),
      TIX_UNDEFINED,
  };
  
  
  /*
   * Forward declarations for procedures defined later in this file:
   */
  
  	/* These are standard procedures for TK widgets
  	 * implemeted in C
  	 */
  
  static void		WidgetCmdDeletedProc _ANSI_ARGS_((
  			    ClientData clientData));
  static int		WidgetConfigure _ANSI_ARGS_((Tcl_Interp *interp,
  			    WidgetPtr wPtr, int argc, CONST84 char **argv,
  			    int flags));
  static void		WidgetDestroy _ANSI_ARGS_((ClientData clientData));
  static void		WidgetEventProc _ANSI_ARGS_((ClientData clientData,
  			    XEvent *eventPtr));
  static int		WidgetCommand _ANSI_ARGS_((ClientData clientData,
  			    Tcl_Interp *, int argc, CONST84 char **argv));
  static void		WidgetDisplay _ANSI_ARGS_((ClientData clientData));
  static void		WidgetComputeGeometry _ANSI_ARGS_((
  			    ClientData clientData));
  
  	/* Extra procedures for this widget
  	 */
  static void		CancelRedrawWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
  static void		CancelResizeWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
  static int		ConfigElement _ANSI_ARGS_((WidgetPtr wPtr,
  			    ListEntry *chPtr, int argc, CONST84 char ** argv,
  			    int flags, int forced));
  static void 		RedrawRows _ANSI_ARGS_((
  			    WidgetPtr wPtr, Drawable pixmap));
  static void		RedrawWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
  static void 		ResizeRows _ANSI_ARGS_((
  			    WidgetPtr wPtr, int winW, int winH));
  static void		ResizeWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
  static void		ResizeNow _ANSI_ARGS_((WidgetPtr wPtr));
  static void		UpdateScrollBars _ANSI_ARGS_((WidgetPtr wPtr,
  			    int sizeChanged));
  static int		Tix_TLGetFromTo _ANSI_ARGS_((
  			    Tcl_Interp *interp, WidgetPtr wPtr,
  			    int argc, CONST84 char **argv,
  			    ListEntry ** fromPtr_ret, ListEntry ** toPtr_ret));
  static void		Tix_TLDItemSizeChanged _ANSI_ARGS_((
  			    Tix_DItem *iPtr));
  static void		MakeGeomRequest _ANSI_ARGS_((
  			    WidgetPtr wPtr));
  static int		Tix_TLGetNearest _ANSI_ARGS_((
     			    WidgetPtr wPtr, int posn[2]));
  static int		Tix_TLGetAt _ANSI_ARGS_((WidgetPtr wPtr,
  			    Tcl_Interp *interp, CONST84 char * spec, int *at));
  static int		Tix_TLGetNeighbor _ANSI_ARGS_((
  			    WidgetPtr wPtr, Tcl_Interp *interp,
  			    int type, int argc, CONST84 char **argv));
  static int		Tix_TranslateIndex _ANSI_ARGS_((
  			    WidgetPtr wPtr, Tcl_Interp *interp, CONST84 char * string,
  			    int * index, int isInsert));
  static int		Tix_TLDeleteRange _ANSI_ARGS_((
  			    WidgetPtr wPtr, ListEntry * fromPtr,
  			    ListEntry *toPtr));
  static ListEntry *	AllocEntry _ANSI_ARGS_((WidgetPtr wPtr));
  static int		AddElement _ANSI_ARGS_((WidgetPtr wPtr,
  			    ListEntry * chPtr, int at));
  static void		FreeEntry _ANSI_ARGS_((WidgetPtr wPtr,
  			    ListEntry * chPtr));
  static int 		Tix_TLSpecialEntryInfo _ANSI_ARGS_((
  			    WidgetPtr wPtr, Tcl_Interp *interp,
  			    ListEntry * chPtr));
  static void		Realloc _ANSI_ARGS_((WidgetPtr wPtr,int new_size));
  
  static TIX_DECLARE_SUBCMD(Tix_TLInsert);
  static TIX_DECLARE_SUBCMD(Tix_TLCGet);
  static TIX_DECLARE_SUBCMD(Tix_TLConfig);
  static TIX_DECLARE_SUBCMD(Tix_TLDelete);
  static TIX_DECLARE_SUBCMD(Tix_TLEntryCget);
  static TIX_DECLARE_SUBCMD(Tix_TLEntryConfig);
  static TIX_DECLARE_SUBCMD(Tix_TLGeometryInfo);
  static TIX_DECLARE_SUBCMD(Tix_TLIndex);
  static TIX_DECLARE_SUBCMD(Tix_TLInfo);
  static TIX_DECLARE_SUBCMD(Tix_TLNearest);
  static TIX_DECLARE_SUBCMD(Tix_TLSee);
  static TIX_DECLARE_SUBCMD(Tix_TLSelection);
  static TIX_DECLARE_SUBCMD(Tix_TLSetSite);
  static TIX_DECLARE_SUBCMD(Tix_TLView);
  
  /*
   *--------------------------------------------------------------
   *
   * Tix_TListCmd --
   *
   *	This procedure is invoked to process the "tixTList" Tcl
   *	command.  It creates a new "TixTList" widget.
   *
   * Results:
   *	A standard Tcl result.
   *
   * Side effects:
   *	A new widget is created and configured.
   *
   *--------------------------------------------------------------
   */
  int
  Tix_TListCmd(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      Tk_Window mainwin = (Tk_Window) clientData;
      WidgetPtr wPtr;
      Tk_Window tkwin;
  
      if (argc < 2) {
  	Tcl_AppendResult(interp, "wrong # args:  should be \"",
  		argv[0], " pathName ?options?\"", (char *) NULL);
  	return TCL_ERROR;
      }
  
      tkwin = Tk_CreateWindowFromPath(interp, mainwin, argv[1], (char *) NULL);
      if (tkwin == NULL) {
  	return TCL_ERROR;
      }
  
      Tk_SetClass(tkwin, "TixTList");
  
      /*
       * Allocate and initialize the widget record.
       */
      wPtr = (WidgetPtr) ckalloc(sizeof(WidgetRecord));
      memset(wPtr, 0, sizeof(WidgetRecord));
  
      wPtr->dispData.tkwin 	= tkwin;
      wPtr->dispData.display 	= Tk_Display(tkwin);
      wPtr->dispData.interp 	= interp;
      wPtr->dispData.sizeChangedProc = Tix_TLDItemSizeChanged;
      wPtr->backgroundGC		= None;
      wPtr->selectGC		= None;
      wPtr->anchorGC		= None;
      wPtr->anchorGC2		= None;
      wPtr->highlightGC		= None;
      wPtr->relief 		= TK_RELIEF_FLAT;
      wPtr->cursor 		= None;
      wPtr->state			= tixNormalUid;
      wPtr->rows			= (ListRow*)ckalloc(sizeof(ListRow) *1);
      wPtr->numRow		= 1;
      wPtr->numRowAllocd		= 1;
  
      Tix_LinkListInit(&wPtr->entList);
      Tix_InitScrollInfo((Tix_ScrollInfo*)&wPtr->scrollInfo[0], TIX_SCROLL_INT);
      Tix_InitScrollInfo((Tix_ScrollInfo*)&wPtr->scrollInfo[1], TIX_SCROLL_INT);
  
      Tk_CreateEventHandler(wPtr->dispData.tkwin,
  	ExposureMask|StructureNotifyMask|FocusChangeMask,
  	WidgetEventProc, (ClientData) wPtr);
      wPtr->widgetCmd = Tcl_CreateCommand(interp,
  	Tk_PathName(wPtr->dispData.tkwin), WidgetCommand, (ClientData) wPtr,
  	WidgetCmdDeletedProc);
  
      if (WidgetConfigure(interp, wPtr, argc-2, argv+2, 0) != TCL_OK) {
  	Tk_DestroyWindow(wPtr->dispData.tkwin);
  	return TCL_ERROR;
      }
  
      Tcl_SetResult(interp, Tk_PathName(wPtr->dispData.tkwin), TCL_STATIC);
      return TCL_OK;
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * WidgetConfigure --
   *
   *	This procedure is called to process an argv/argc list in
   *	conjunction with the Tk option database to configure (or
   *	reconfigure) a List widget.
   *
   * Results:
   *	The return value is a standard Tcl result.  If TCL_ERROR is
   *	returned, then interp's result contains an error message.
   *
   * Side effects:
   *	Configuration information, such as colors, border width,
   *	etc. get set for wPtr;  old resources get freed,
   *	if there were any.
   *
   *----------------------------------------------------------------------
   */
  static int
  WidgetConfigure(interp, wPtr, argc, argv, flags)
      Tcl_Interp *interp;			/* Used for error reporting. */
      WidgetPtr wPtr;			/* Information about widget. */
      int argc;				/* Number of valid entries in argv. */
      CONST84 char **argv;		/* Arguments. */
      int flags;				/* Flags to pass to
  					 * Tk_ConfigureWidget. */
  {
      XGCValues gcValues;
      GC newGC;
      TixFont oldfont;
      size_t length;
      Tix_StyleTemplate stTmpl;
  
      oldfont = wPtr->font;
  
      if (Tk_ConfigureWidget(interp, wPtr->dispData.tkwin, configSpecs,
  	    argc, argv, (char *) wPtr, flags) != TCL_OK) {
  	return TCL_ERROR;
      }
  
      length = strlen(wPtr->orientUid);
      if (strncmp(wPtr->orientUid, "vertical", length) == 0) {
  	wPtr->isVertical = 1;
      } else if (strncmp(wPtr->orientUid, "horizontal", length) == 0) {
  	wPtr->isVertical = 0;
      } else {
  	Tcl_AppendResult(interp, "bad orientation \"", wPtr->orientUid,
  	    "\": must be vertical or horizontal", (char *) NULL);
  	wPtr->orientUid = Tk_GetUid("vertical");
  	wPtr->isVertical = 1;
  	return TCL_ERROR;
      }
  
      if ((wPtr->state != tixNormalUid) && (wPtr->state != tixDisabledUid)) {
  	Tcl_AppendResult(interp, "bad state value \"", wPtr->state,
  	    "\":  must be normal or disabled", (char *) NULL);
  	wPtr->state = tixNormalUid;
  	return TCL_ERROR;
      }
  
  
      if (oldfont != wPtr->font) {
  	/* Font has been changed (initialized) */
  	TixComputeTextGeometry(wPtr->font, "0", 1,
  	    0, &wPtr->scrollInfo[0].unit, &wPtr->scrollInfo[1].unit);
      }
  
      /*
       * A few options need special processing, such as setting the
       * background from a 3-D border, or filling in complicated
       * defaults that couldn't be specified to Tk_ConfigureWidget.
       */
  
      Tk_SetBackgroundFromBorder(wPtr->dispData.tkwin, wPtr->border);
  
      /*
       * Note: GraphicsExpose events are disabled in normalGC because it's
       * used to copy stuff from an off-screen pixmap onto the screen (we know
       * that there's no problem with obscured areas).
       */
  
      /* The background GC */
      gcValues.foreground 	= wPtr->normalBg->pixel;
      gcValues.graphics_exposures = False;
  
      newGC = Tk_GetGC(wPtr->dispData.tkwin,
  	GCForeground|GCGraphicsExposures, &gcValues);
      if (wPtr->backgroundGC != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->backgroundGC);
      }
      wPtr->backgroundGC = newGC;
  
      /* The selected text GC */
      gcValues.font 		= TixFontId(wPtr->font);
      gcValues.foreground 	= wPtr->selectFg->pixel;
      gcValues.background 	= Tk_3DBorderColor(wPtr->selectBorder)->pixel;
      gcValues.graphics_exposures = False;
  
      newGC = Tk_GetGC(wPtr->dispData.tkwin,
  	GCForeground|GCBackground|GCFont|GCGraphicsExposures, &gcValues);
      if (wPtr->selectGC != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->selectGC);
      }
      wPtr->selectGC = newGC;
  
      /* The dotted anchor lines (for selected item) */
      newGC = Tix_GetAnchorGC(wPtr->dispData.tkwin,
              Tk_3DBorderColor(wPtr->selectBorder));
      if (wPtr->anchorGC != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->anchorGC);
      }
      wPtr->anchorGC = newGC;
  
      /* The dotted anchor lines (for unselected item)  */
      newGC = Tix_GetAnchorGC(wPtr->dispData.tkwin, wPtr->normalBg);
      if (wPtr->anchorGC2 != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->anchorGC2);
      }
      wPtr->anchorGC2 = newGC;
  
      /* The highlight border */
      gcValues.background 	= wPtr->selectFg->pixel;
      gcValues.foreground 	= wPtr->highlightColorPtr->pixel;
      gcValues.graphics_exposures = False;
  
      newGC = Tk_GetGC(wPtr->dispData.tkwin,
  	GCForeground|GCBackground|GCGraphicsExposures, &gcValues);
      if (wPtr->highlightGC != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->highlightGC);
      }
      wPtr->highlightGC = newGC;
  
      /* We must set the options of the default styles so that
       * -- the default styles will change according to what is in
       *    stTmpl
       */
      stTmpl.font 			= wPtr->font;
      stTmpl.pad[0]  			= wPtr->padX;
      stTmpl.pad[1]  			= wPtr->padY;
      stTmpl.colors[TIX_DITEM_NORMAL].fg  = wPtr->normalFg;
      stTmpl.colors[TIX_DITEM_NORMAL].bg  = wPtr->normalBg;
      stTmpl.colors[TIX_DITEM_SELECTED].fg= wPtr->selectFg;
      stTmpl.colors[TIX_DITEM_SELECTED].bg= Tk_3DBorderColor(wPtr->selectBorder);
      stTmpl.flags = TIX_DITEM_FONT|TIX_DITEM_NORMAL_BG|
  	TIX_DITEM_SELECTED_BG|TIX_DITEM_NORMAL_FG|TIX_DITEM_SELECTED_FG |
  	TIX_DITEM_PADX|TIX_DITEM_PADY;
  
      Tix_SetDefaultStyleTemplate(wPtr->dispData.tkwin, &stTmpl);
  
      /*
       * Probably the -font or -width or -height options have changed. Let's
       * make geometry request
       */
      MakeGeomRequest(wPtr);
  
      ResizeWhenIdle(wPtr);
  
      return TCL_OK;
  }
  
  /*
   *--------------------------------------------------------------
   *
   * WidgetCommand --
   *
   *	This procedure is invoked to process the Tcl command
   *	that corresponds to a widget managed by this module.
   *	See the user documentation for details on what it does.
   *
   * Results:
   *	A standard Tcl result.
   *
   * Side effects:
   *	See the user documentation.
   *
   *--------------------------------------------------------------
   */
  
  static int
  WidgetCommand(clientData, interp, argc, argv)
      ClientData clientData;		/* Information about the widget. */
      Tcl_Interp *interp;			/* Current interpreter. */
      int argc;				/* Number of arguments. */
      CONST84 char **argv;		/* Argument strings. */
  {
      int code;
  
      static Tix_SubCmdInfo subCmdInfo[] = {
  	{TIX_DEFAULT_LEN, "active", 1, 2, Tix_TLSetSite,
  	   "option ?index?"},
  	{TIX_DEFAULT_LEN, "anchor", 1, 2, Tix_TLSetSite,
  	   "option ?index?"},
  	{TIX_DEFAULT_LEN, "cget", 1, 1, Tix_TLCGet,
  	   "option"},
  	{TIX_DEFAULT_LEN, "configure", 0, TIX_VAR_ARGS, Tix_TLConfig,
  	   "?option? ?value? ?option value ... ?"},
  	{TIX_DEFAULT_LEN, "delete", 1, 2, Tix_TLDelete,
  	   "from ?to?"},
  	{TIX_DEFAULT_LEN, "dragsite", 1, 2, Tix_TLSetSite,
  	   "option ?entryPath?"},
  	{TIX_DEFAULT_LEN, "dropsite", 1, 2, Tix_TLSetSite,
  	   "option ?entryPath?"},
  	{TIX_DEFAULT_LEN, "entrycget", 2, 2, Tix_TLEntryCget,
  	   "entryPath option"},
  	{TIX_DEFAULT_LEN, "entryconfigure", 1, TIX_VAR_ARGS, Tix_TLEntryConfig,
  	   "index ?option? ?value? ?option value ... ?"},
  	{TIX_DEFAULT_LEN, "geometryinfo", 0, 2, Tix_TLGeometryInfo,
  	   "?width height?"},
  	{TIX_DEFAULT_LEN, "index", 1, 1, Tix_TLIndex,
  	   "index"},
  	{TIX_DEFAULT_LEN, "info", 1, TIX_VAR_ARGS, Tix_TLInfo,
  	   "option ?args ...?"},
  	{TIX_DEFAULT_LEN, "insert", 1, TIX_VAR_ARGS, Tix_TLInsert,
  	   "where ?option value ..."},
  	{TIX_DEFAULT_LEN, "nearest", 2, 2, Tix_TLNearest,
  	   "x y"},
  	{TIX_DEFAULT_LEN, "see", 1, 1, Tix_TLSee,
  	   "entryPath"},
  	{TIX_DEFAULT_LEN, "selection", 1, 3, Tix_TLSelection,
  	   "option arg ?arg ...?"},
  	{TIX_DEFAULT_LEN, "xview", 0, 3, Tix_TLView,
  	   "args"},
  	{TIX_DEFAULT_LEN, "yview", 0, 3, Tix_TLView,
  	   "args"},
      };
  
      static Tix_CmdInfo cmdInfo = {
  	Tix_ArraySize(subCmdInfo), 1, TIX_VAR_ARGS, "?option? arg ?arg ...?",
      };
  
      Tk_Preserve(clientData);
      code = Tix_HandleSubCmds(&cmdInfo, subCmdInfo, clientData,
  	interp, argc, argv);
      Tk_Release(clientData);
  
      return code;
  }
  
  /*
   *--------------------------------------------------------------
   *
   * WidgetEventProc --
   *
   *	This procedure is invoked by the Tk dispatcher for various
   *	events on Lists.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	When the window gets deleted, internal structures get
   *	cleaned up.  When it gets exposed, it is redisplayed.
   *
   *--------------------------------------------------------------
   */
  static void
  WidgetEventProc(clientData, eventPtr)
      ClientData clientData;	/* Information about window. */
      XEvent *eventPtr;		/* Information about event. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
  
      switch (eventPtr->type) {
        case DestroyNotify:
  	if (wPtr->dispData.tkwin != NULL) {
  	    wPtr->dispData.tkwin = NULL;
  	    Tcl_DeleteCommand(wPtr->dispData.interp, 
  	        Tcl_GetCommandName(wPtr->dispData.interp, wPtr->widgetCmd));
  	}
  	CancelResizeWhenIdle(wPtr);
  	CancelRedrawWhenIdle(wPtr);
  	Tk_EventuallyFree((ClientData) wPtr, (Tix_FreeProc*)WidgetDestroy);
  	break;
  
        case ConfigureNotify:
  	ResizeWhenIdle(wPtr);
  	break;
  
        case Expose:
  	RedrawWhenIdle(wPtr);
  	break;
  
        case FocusIn:
  	wPtr->hasFocus = 1;
  	RedrawWhenIdle(wPtr);
  	break;
  
        case FocusOut:
  	wPtr->hasFocus = 0;
  	RedrawWhenIdle(wPtr);
  	break;
      }
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * WidgetDestroy --
   *
   *	This procedure is invoked by Tk_EventuallyFree or Tk_Release
   *	to clean up the internal structure of a List at a safe time
   *	(when no-one is using it anymore).
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	Everything associated with the List is freed up.
   *
   *----------------------------------------------------------------------
   */
  
  static void
  WidgetDestroy(clientData)
      ClientData clientData;	/* Info about my widget. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
  
  
      if (wPtr->backgroundGC != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->backgroundGC);
      }
      if (wPtr->selectGC != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->selectGC);
      }
      if (wPtr->anchorGC != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->anchorGC);
      }
      if (wPtr->anchorGC2 != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->anchorGC2);
      }
      if (wPtr->highlightGC != None) {
  	Tk_FreeGC(wPtr->dispData.display, wPtr->highlightGC);
      }
  
      if (wPtr->entList.numItems > 0) {
  	ListEntry * fromPtr=NULL, *toPtr=NULL;
  	CONST84 char * argv[2];
  	argv[0] = "0";
  	argv[1] = "end";
  
  	Tix_TLGetFromTo(wPtr->dispData.interp, wPtr, 2, argv, &fromPtr,&toPtr);
  	Tcl_ResetResult(wPtr->dispData.interp);
  
  	if (fromPtr && toPtr) {
  	    Tix_TLDeleteRange(wPtr, fromPtr, toPtr);
  	}
      }
  
      if (wPtr->rows) {
  	ckfree((char*)wPtr->rows);
      }
  
      Tk_FreeOptions(configSpecs, (char *) wPtr, wPtr->dispData.display, 0);
      ckfree((char *) wPtr);
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * WidgetCmdDeletedProc --
   *
   *	This procedure is invoked when a widget command is deleted.  If
   *	the widget isn't already in the process of being destroyed,
   *	this command destroys it.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	The widget is destroyed.
   *
   *----------------------------------------------------------------------
   */
  static void
  WidgetCmdDeletedProc(clientData)
      ClientData clientData;	/* Pointer to widget record for widget. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
  
      /*
       * This procedure could be invoked either because the window was
       * destroyed and the command was then deleted (in which case tkwin
       * is NULL) or because the command was deleted, and then this procedure
       * destroys the widget.
       */
      if (wPtr->dispData.tkwin != NULL) {
  	Tk_Window tkwin = wPtr->dispData.tkwin;
  	wPtr->dispData.tkwin = NULL;
  	Tk_DestroyWindow(tkwin);
      }
  }
  
  /*
   *--------------------------------------------------------------
   *
   * WidgetComputeGeometry --
   *
   *	This procedure is invoked to process the Tcl command
   *	that corresponds to a widget managed by this module.
   *	See the user documentation for details on what it does.
   *
   * Results:
   *	A standard Tcl result.
   *
   * Side effects:
   *	none
   *
   *--------------------------------------------------------------
   */
  static void
  WidgetComputeGeometry(clientData)
      ClientData clientData;
  {
      WidgetPtr wPtr = (WidgetPtr)clientData;
      int winW, winH;
      Tk_Window tkwin = wPtr->dispData.tkwin;
  
      wPtr->resizing = 0;
  
      winW = Tk_Width(tkwin)  - 2*wPtr->highlightWidth - 2*wPtr->borderWidth;
      winH = Tk_Height(tkwin) - 2*wPtr->highlightWidth - 2*wPtr->borderWidth;
  
      ResizeRows(wPtr, winW, winH);
      /* Update scrollbars */
      UpdateScrollBars(wPtr, 1);
  
      RedrawWhenIdle(wPtr);
  }
  
  static void
  MakeGeomRequest(wPtr)
      WidgetPtr wPtr;
  {
      int reqW, reqH;
      
      reqW = wPtr->width  * wPtr->scrollInfo[0].unit;
      reqH = wPtr->height * wPtr->scrollInfo[1].unit;
  
      Tk_GeometryRequest(wPtr->dispData.tkwin, reqW, reqH);
  }
  
  
  
  /*----------------------------------------------------------------------
   * DItemSizeChanged --
   *
   *	This is called whenever the size of one of the HList's items
   *	changes its size.
   *----------------------------------------------------------------------
   */
  static void
  Tix_TLDItemSizeChanged(iPtr)
      Tix_DItem *iPtr;
  {
      WidgetPtr wPtr = (WidgetPtr)iPtr->base.clientData;
  
      if (wPtr) {
  	/* double-check: perhaps we haven't set the clientData yet! */
  	ResizeWhenIdle(wPtr);
      }
  }
  
  /*
   *----------------------------------------------------------------------
   * ResizeWhenIdle --
   *----------------------------------------------------------------------
   */
  static void
  ResizeWhenIdle(wPtr)
      WidgetPtr wPtr;
  {
      if (wPtr->redrawing) {
  	CancelRedrawWhenIdle(wPtr);
      }
      if (!wPtr->resizing) {
  	wPtr->resizing = 1;
  	Tk_DoWhenIdle(WidgetComputeGeometry, (ClientData)wPtr);
      }
  }
  
  /*
   *----------------------------------------------------------------------
   * ResizeWhenIdle --
   *----------------------------------------------------------------------
   */
  static void
  ResizeNow(wPtr)
      WidgetPtr wPtr;
  {
      if (wPtr->resizing) {
  	Tk_CancelIdleCall(WidgetComputeGeometry, (ClientData)wPtr);
  
  	WidgetComputeGeometry((ClientData)wPtr);
  	wPtr->resizing = 0;
      }
  }
  
  /*
   *----------------------------------------------------------------------
   * CancelResizeWhenIdle --
   *----------------------------------------------------------------------
   */
  static void
  CancelResizeWhenIdle(wPtr)
      WidgetPtr wPtr;
  {
      if (wPtr->resizing) {
  	wPtr->resizing = 0;
  	Tk_CancelIdleCall(WidgetComputeGeometry, (ClientData)wPtr);
      }
  }
  
  /*
   *----------------------------------------------------------------------
   * RedrawWhenIdle --
   *----------------------------------------------------------------------
   */
  static void
  RedrawWhenIdle(wPtr)
      WidgetPtr wPtr;
  {
      if (wPtr->resizing) {
  	/*
  	 * Resize will eventually call redraw.
  	 */
  	return;
      }
      if (!wPtr->redrawing && Tk_IsMapped(wPtr->dispData.tkwin)) {
  	wPtr->redrawing = 1;
  	Tk_DoWhenIdle(WidgetDisplay, (ClientData)wPtr);
      }
  }
  
  /*
   *----------------------------------------------------------------------
   * CancelRedrawWhenIdle --
   *----------------------------------------------------------------------
   */
  static void
  CancelRedrawWhenIdle(wPtr)
      WidgetPtr wPtr;
  {
      if (wPtr->redrawing) {
  	wPtr->redrawing = 0;
  	Tk_CancelIdleCall(WidgetDisplay, (ClientData)wPtr);
      }
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * WidgetDisplay --
   *
   *	Draw the widget to the screen.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *
   *----------------------------------------------------------------------
   */
  static void
  WidgetDisplay(clientData)
      ClientData clientData;	/* Info about my widget. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      Pixmap pixmap;
      Tk_Window tkwin = wPtr->dispData.tkwin;
      int winH, winW;
      int hl = wPtr->highlightWidth;
      int bd = wPtr->borderWidth;
  
      wPtr->redrawing = 0;		/* clear the redraw flag */
      wPtr->serial ++;
  
      pixmap = Tk_GetPixmap(wPtr->dispData.display, Tk_WindowId(tkwin),
  	Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  
      /* Fill the background */
      XFillRectangle(wPtr->dispData.display, pixmap, wPtr->backgroundGC,
  	0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin));
  
      winW = Tk_Width(tkwin)  - 2*hl - 2*bd;
      winH = Tk_Height(tkwin) - 2*hl - 2*bd;
  
      if (winW > 0 && winH > 0) {
  	RedrawRows(wPtr, pixmap);
      }
  
      /* Draw the border */
      Tk_Draw3DRectangle(wPtr->dispData.tkwin, pixmap, wPtr->border,
  	    hl, hl, Tk_Width(tkwin)  - 2*hl, Tk_Height(tkwin) - 2*hl, bd,
  	    wPtr->relief);
    
      /* Draw the highlight */
      if (hl > 0) {
  	GC gc;
  
  	if (wPtr->hasFocus) {
  	    gc = wPtr->highlightGC;
  	} else {
  	    gc = Tk_3DBorderGC(wPtr->dispData.tkwin, wPtr->border, 
  		TK_3D_FLAT_GC);
  	}
  	Tk_DrawFocusHighlight(tkwin, gc, hl, pixmap);
      }
  
      /*
       * Copy the information from the off-screen pixmap onto the screen,
       * then delete the pixmap.
       */
      XCopyArea(wPtr->dispData.display, pixmap, Tk_WindowId(tkwin),
  	    wPtr->backgroundGC, 0, 0,
  	    (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin), 0, 0);
      Tk_FreePixmap(wPtr->dispData.display, pixmap);
  
  }
  
  /*----------------------------------------------------------------------
   *  AddElement  --
   *
   *	Add the element at the position indicated by "at".
   *----------------------------------------------------------------------
   */
  static int
  AddElement(wPtr, chPtr, at)
      WidgetPtr wPtr;
      ListEntry * chPtr;
      int at;
  {
      if (at >= wPtr->entList.numItems) {
  	/* The "end" position */
  	Tix_LinkListAppend(&entListInfo, &wPtr->entList, (char*)chPtr, 0);
      }
      else {
  	Tix_ListIterator li;
  	Tix_LinkListIteratorInit(&li);
  
  	for (Tix_LinkListStart(&entListInfo, &wPtr->entList, &li);
  	     !Tix_LinkListDone(&li);
  	     Tix_LinkListNext (&entListInfo, &wPtr->entList, &li)) {
  
  	    if (at == 0) {
  		Tix_LinkListInsert(&entListInfo, &wPtr->entList,
  		    (char*)chPtr, &li);
  		break;
  	    } else {
  		-- at;
  	    }
  	}
      }
  
      return TCL_OK;
  }
  
  /*----------------------------------------------------------------------
   *  AllocEntry  --
   *
   *	Allocates memory for a new entry and initializes it to a
   *	proper state.
   *----------------------------------------------------------------------
   */
  static ListEntry *
  AllocEntry(wPtr)
      WidgetPtr wPtr;
  {
      ListEntry * chPtr;
  
      chPtr = (ListEntry *)ckalloc(sizeof(ListEntry));
      chPtr->state	= NULL;
      chPtr->selected	= 0;
      chPtr->iPtr		= NULL;
  
      return chPtr;
  }
  
  /*----------------------------------------------------------------------
   *  FreeEntry  --
   *
   *	Free the entry and all resources allocated to this entry.
   *	This entry must already be deleted from the list.
   *----------------------------------------------------------------------
   */
  static void
  FreeEntry(wPtr, chPtr)
      WidgetPtr wPtr;
      ListEntry * chPtr;
  {
  
      if (wPtr->seeElemPtr == chPtr) {
  	/*
  	 * This is the element that should be visible the next time
  	 * we draw the window. Adjust the "to see element" to an element
  	 * that is close to it.
  	 */
  	if (chPtr->next != NULL) {
  	    wPtr->seeElemPtr = chPtr->next;
  	} else {
  	    ListEntry *p;
  
  	    wPtr->seeElemPtr = NULL;
  	    for (p=(ListEntry*)wPtr->entList.head; p; p=p->next) {
  		if (p->next == chPtr) {
  		    wPtr->seeElemPtr = p;
  		    break;
  		}
  	    }
  	}
      }
  
      if (wPtr->anchor == chPtr) {
  	wPtr->anchor = NULL;
      }
      if (wPtr->active == chPtr) {
  	wPtr->active = NULL;
      }
      if (wPtr->dragSite == chPtr) {
  	wPtr->dragSite = NULL;
      }
      if (wPtr->dropSite == chPtr) {
  	wPtr->dropSite = NULL;
      }
  
      if (chPtr->iPtr != NULL) {
  	if (Tix_DItemType(chPtr->iPtr) == TIX_DITEM_WINDOW) {
  #if 0
  	    Tix_WindowItemListRemove(&wPtr->mappedWindows,
  		chPtr->iPtr);
  #endif
  	}
  	Tix_DItemFree(chPtr->iPtr);
      }
  
      Tk_FreeOptions(entryConfigSpecs, (char *)chPtr,wPtr->dispData.display, 0);
      ckfree((char*)chPtr);
  }
  
  /*----------------------------------------------------------------------
   * "insert" sub command -- 
   *
   *	Insert a new item into the list
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLInsert(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      ListEntry * chPtr = NULL;
      char buff[40];
      CONST84 char * ditemType;
      int at;
      int added = 0;
      int code = TCL_OK;
  
      /*------------------------------------------------------------
       * (1) We need to determine the options:
       *     -itemtype and -at.
       *------------------------------------------------------------
       */
  
      /* (1.1) Find out where */
      if (Tix_TranslateIndex(wPtr, interp, argv[0], &at, 1) != TCL_OK) {
  	code = TCL_ERROR; goto done;
      }
  
      /* (1.2) Find out the -itemtype, if specified */
      ditemType = wPtr->diTypePtr->name;   		 /* default value */
      if (argc > 1) {
  	size_t len;
  	int i;
  	if (argc %2 != 1) {
  	    Tcl_AppendResult(interp, "value for \"", argv[argc-1],
  		"\" missing", NULL);
  	    code = TCL_ERROR; goto done;
  	}
  	for (i=1; i<argc; i+=2) {
  	    len = strlen(argv[i]);
  	    if (strncmp(argv[i], "-itemtype", len) == 0) {
  		ditemType = argv[i+1];
  	    }
  	}
      }
  
      if (Tix_GetDItemType(interp, ditemType) == NULL) {
  	code = TCL_ERROR; goto done;
      }
  
      /*
       * (2) Allocate a new entry
       */
      chPtr = AllocEntry(wPtr);
  
      /* (2.1) The Display item data */
      if ((chPtr->iPtr = Tix_DItemCreate(&wPtr->dispData, ditemType)) == NULL) {
  	code = TCL_ERROR; goto done;
      }
      chPtr->iPtr->base.clientData = (ClientData)wPtr;
      chPtr->size[0] = chPtr->iPtr->base.size[0];
      chPtr->size[1] = chPtr->iPtr->base.size[1];
  
      /*
       * (3) Add the entry into the list
       */
      if (AddElement(wPtr, chPtr, at) != TCL_OK) {
  	code = TCL_ERROR; goto done;
      } else {
  	added = 1;
      }
  
      if (ConfigElement(wPtr, chPtr, argc-1, argv+1, 0, 1) != TCL_OK) {
  	code = TCL_ERROR; goto done;
      }
  
      ResizeWhenIdle(wPtr);
  
    done:
      if (code == TCL_ERROR) {
  	if (chPtr != NULL) {
  	    if (added) {
  		Tix_LinkListFindAndDelete(&entListInfo, &wPtr->entList, 
  		    (char*)chPtr, NULL);
  	    }
  	    FreeEntry(wPtr, chPtr);
  	}
      } else {
  	sprintf(buff, "%d", at);
  	Tcl_AppendResult(interp, buff, NULL);	
      }
  
      return code;
  }
  
  static int 
  Tix_TLSpecialEntryInfo(wPtr, interp, chPtr)
      WidgetPtr wPtr;
      Tcl_Interp *interp;
      ListEntry * chPtr;
  {
      char buff[100];
  
      if (chPtr) {
  	int i;
  	Tix_ListIterator li;
  
  	Tix_LinkListIteratorInit(&li);
  
  	for (i=0,Tix_LinkListStart(&entListInfo, &wPtr->entList, &li);
  	     !Tix_LinkListDone(&li);
  	     Tix_LinkListNext(&entListInfo, &wPtr->entList, &li),i++) {
  	    if (li.curr == (char*)chPtr) {
  		break;
  	    }
  	}
  	if (li.curr != NULL) {
  	    sprintf(buff, "%d", i);
  	    Tcl_AppendResult(interp, buff, NULL);
  	} else {
  	    panic("TList list entry is invalid");
  	}
      } else {
  	Tcl_ResetResult(interp);
      }
      return TCL_OK;
  }
  
  /*----------------------------------------------------------------------
   * "index" sub command
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLIndex(clientData, interp, argc, argv)
      ClientData clientData;	/* TList widget record. */
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      int index;
      char buff[100];
  
      if (Tix_TranslateIndex(wPtr, interp, argv[0], &index, 0) != TCL_OK) {
  	return TCL_ERROR;
      }
  
      sprintf(buff, "%d", index);
      Tcl_AppendResult(interp, buff, NULL);
      return TCL_OK;
  }
  
  /*----------------------------------------------------------------------
   * "info" sub command
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLInfo(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      size_t len = strlen(argv[0]);
  
      if (strncmp(argv[0], "anchor", len)==0) {
  	return Tix_TLSpecialEntryInfo(wPtr, interp, wPtr->anchor);
      }
      else if (strncmp(argv[0], "active", len)==0) {
  	return Tix_TLSpecialEntryInfo(wPtr, interp, wPtr->active);
      }
      else if (strncmp(argv[0], "down", len)==0) {
  	return Tix_TLGetNeighbor(wPtr, interp, TIX_DOWN,  argc-1, argv+1);
      }
      else if (strncmp(argv[0], "left", len)==0) {
  	return Tix_TLGetNeighbor(wPtr, interp, TIX_LEFT,  argc-1, argv+1);
      }
      else if (strncmp(argv[0], "right", len)==0) {
  	return Tix_TLGetNeighbor(wPtr, interp, TIX_RIGHT, argc-1, argv+1);
      }
      else if (strncmp(argv[0], "selection", len)==0) {
  	ListEntry *chPtr;
  	int i;
  	char buffer[32];
  
  	for (chPtr=(ListEntry*)wPtr->entList.head, i=0;
  	     chPtr;
  	     chPtr=chPtr->next, i++) {
  	    
  	    if (chPtr->selected) {
  		if (i) {
  		    Tcl_AppendResult(interp, " ", (char *) NULL);
  		}
  		sprintf(buffer, "%d", i);
  		Tcl_AppendResult(interp, buffer, (char *) NULL);
  	    }
  	}
  	return TCL_OK;
      }
      else if (strncmp(argv[0], "size", len)==0) {
  	char buff[100];
  
  	sprintf(buff, "%d", wPtr->entList.numItems);
  	Tcl_AppendResult(interp, buff, NULL);
  
  	return TCL_OK;
      }
      else if (strncmp(argv[0], "up", len)==0) {
  	return Tix_TLGetNeighbor(wPtr, interp, TIX_UP,    argc-1, argv+1);
      }
      else {
  	Tcl_AppendResult(interp, "unknown option \"", argv[0], 
  	    "\": must be anchor or selection",
  	    NULL);
  	return TCL_ERROR;
      }
  }
  
  static int
  Tix_TranslateIndex(wPtr, interp, string, index, isInsert)
      WidgetPtr wPtr;		/* TList widget record. */
      Tcl_Interp *interp;		/* Current interpreter. */
      CONST84 char * string;	/* String representation of the index. */
      int * index;		/* Returns the index value(0 = 1st element).*/
      int isInsert;		/* Is this function called by an "insert"
  				 * operation? */
  {
      if (strcmp(string, "end") == 0) {
  	*index = wPtr->entList.numItems;
      }
      else if (Tix_TLGetAt(wPtr, interp, string, index) != TCL_OK) {
  	if (Tcl_GetInt(interp, string, index) != TCL_OK) {
  	    return TCL_ERROR;
  	}
  	else if (*index < 0) {
  	    Tcl_AppendResult(interp,"expected non-negative integer but got \"",
  	    	string, "\"", NULL);
  	    return TCL_ERROR;
  	}
      }
  
  
      /*
       * The meaning of "end" means:
       *     isInsert:wPtr->entList.numItems
       *    !isInsert:wPtr->entList.numItems-1;
       */
  
      if (isInsert) {
  	if (*index > wPtr->entList.numItems) {
  	    /*
  	     * By default add it to the end, just to follow what TK
  	     * does for the Listbox widget
  	     */
  	    *index = wPtr->entList.numItems;
  	}
      } else {
  	if (*index >= wPtr->entList.numItems) {
  	    /*
  	     * By default add it to the end, just to follow what TK
  	     * does for the Listbox widget
  	     */
  	    *index = wPtr->entList.numItems - 1;
  	}
      }
  
      if (*index < 0) {
  	*index = 0;
      }
  
      return TCL_OK;
  }
  
  static int Tix_TLGetNeighbor(wPtr, interp, type, argc, argv)
      WidgetPtr wPtr;
      Tcl_Interp *interp;		/* Current interpreter. */
      int type;
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      int index;
      int dst = 0; /* lint */
      int xStep, yStep;
      int numPerRow;
      char buff[100];
  
      if (argc != 1) {
  	Tix_ArgcError(interp, argc+3, argv-3, 3, "index");
      }
  
      if (Tix_TranslateIndex(wPtr, interp, argv[0], &index, 0) != TCL_OK) {
  	return TCL_ERROR;
      }
  
      if (wPtr->entList.numItems == 0) {
  	Tcl_ResetResult(interp);
  	return TCL_OK;
      }
  
      numPerRow = wPtr->rows[0].numEnt;
  
      if (wPtr->isVertical) {
  	xStep = numPerRow;
  	yStep = 1;
      } else {
  	xStep = 1;
  	yStep = numPerRow;
      }
  
      switch (type) {
        case TIX_UP:
  	dst = index - yStep;
  	break;
        case TIX_DOWN:
  	dst = index + yStep;
  	break;
        case TIX_LEFT:
  	dst = index - xStep;
  	break;
        case TIX_RIGHT:
  	dst = index + xStep;
  	break;
      }
  
      if (dst < 0) {
  	dst = index;
      } else if (dst >= wPtr->entList.numItems) {
  	dst = index;
      }
  
      sprintf(buff, "%d", dst);
      Tcl_AppendResult(interp, buff, NULL);	
  
      return TCL_OK;
  }
  
  
  
  /*----------------------------------------------------------------------
   * "cget" sub command --
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLCGet(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
  
      return Tk_ConfigureValue(interp, wPtr->dispData.tkwin, configSpecs,
  	(char *)wPtr, argv[0], 0);
  }
  
  /*----------------------------------------------------------------------
   * "configure" sub command
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLConfig(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
  
      if (argc == 0) {
  	return Tk_ConfigureInfo(interp, wPtr->dispData.tkwin, configSpecs,
  	    (char *) wPtr, (char *) NULL, 0);
      } else if (argc == 1) {
  	return Tk_ConfigureInfo(interp, wPtr->dispData.tkwin, configSpecs,
  	    (char *) wPtr, argv[0], 0);
      } else {
  	return WidgetConfigure(interp, wPtr, argc, argv,
  	    TK_CONFIG_ARGV_ONLY);
      }
  }
  
  /*----------------------------------------------------------------------
   * "geometryinfo" sub command
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLGeometryInfo(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      int qSize[2];
      double first[2], last[2];
      char string[40];
      int i;
  
      if (argc == 2) {
  	if (Tcl_GetInt(interp, argv[0], &qSize[0]) != TCL_OK) {
  	    return TCL_ERROR;
  	}
  	if (Tcl_GetInt(interp, argv[1], &qSize[1]) != TCL_OK) {
  	    return TCL_ERROR;
  	}
      } else {
  	qSize[0] = Tk_Width (wPtr->dispData.tkwin);
  	qSize[1] = Tk_Height(wPtr->dispData.tkwin);
      }
      qSize[0] -= 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
      qSize[1] -= 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
  
      for (i=0; i<2; i++) {
  	qSize[i] -= 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
  	Tix_GetScrollFractions((Tix_ScrollInfo*)&wPtr->scrollInfo[i],
  	    &first[i], &last[i]);
      }
  
      sprintf(string, "{%f %f} {%f %f}", first[0], last[0], first[1], last[1]);
      Tcl_AppendResult(interp, string, NULL);
  
      return TCL_OK;
  }
  
  /*----------------------------------------------------------------------
   * "delete" sub command
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLDelete(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      ListEntry * fromPtr, *toPtr;
      int code = TCL_OK;
  
      if (argc < 1 || argc > 2) {
  	Tix_ArgcError(interp, argc+2, argv-2, 2, "from ?to?");
  	code = TCL_ERROR;
  	goto done;
      }
  
      if (Tix_TLGetFromTo(interp, wPtr, argc, argv, &fromPtr, &toPtr)!= TCL_OK) {
  	code = TCL_ERROR;
  	goto done;
      }
      if (fromPtr == NULL) {
  	goto done;
      }
  
      if (Tix_TLDeleteRange(wPtr, fromPtr, toPtr)) {
  	ResizeWhenIdle(wPtr);
      }
  
    done:
      return code;
  }
  
  /* returns true if some element has been deleted */
  static int Tix_TLDeleteRange(wPtr, fromPtr, toPtr)
      WidgetPtr wPtr;
      ListEntry * fromPtr;
      ListEntry *toPtr;
  {
      int started;
      Tix_ListIterator li;
  
      Tix_LinkListIteratorInit(&li);
      started = 0;
      for (Tix_LinkListStart(&entListInfo, &wPtr->entList, &li);
  	 !Tix_LinkListDone(&li);
  	 Tix_LinkListNext (&entListInfo, &wPtr->entList, &li)) {
  
  	ListEntry * curr = (ListEntry *)li.curr;
  	if (curr == fromPtr) {
  	    started = 1;
  	}
  	if (started) {
  	    Tix_LinkListDelete(&entListInfo, &wPtr->entList, &li);
  	    FreeEntry(wPtr, curr);
  	}
  	if (curr == toPtr) {
  	    break;
  	}
      }
  
      return started;
  }
  
  
  /*----------------------------------------------------------------------
   * "entrycget" sub command
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLEntryCget(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      ListEntry * chPtr, * dummy;
  
      if (Tix_TLGetFromTo(interp, wPtr, 1, argv, &chPtr, &dummy)
  	!= TCL_OK) {
  	return TCL_ERROR;
      }
  
      if (chPtr == NULL) {
  	Tcl_AppendResult(interp, "list entry \"", argv[0],
  	    "\" does not exist", NULL);
  	return TCL_ERROR;
      }
  
      return Tix_ConfigureValue2(interp, wPtr->dispData.tkwin, (char *)chPtr,
  	entryConfigSpecs, chPtr->iPtr, argv[1], 0);
  }
  
  /*----------------------------------------------------------------------
   * "entryconfigure" sub command
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLEntryConfig(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      ListEntry * chPtr, * dummy;
  
      if (Tix_TLGetFromTo(interp, wPtr, 1, argv, &chPtr, &dummy)
  	!= TCL_OK) {
  	return TCL_ERROR;
      }
  
      if (chPtr == NULL) {
  	Tcl_AppendResult(interp, "list entry \"", argv[0],
  	    "\" does not exist", NULL);
  	return TCL_ERROR;
      }
  
      if (argc == 1) {
  	return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
  	    (char*)chPtr, entryConfigSpecs, chPtr->iPtr, (char *) NULL, 0);
      } else if (argc == 2) {
  	return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
  	    (char*)chPtr, entryConfigSpecs, chPtr->iPtr, (char *) argv[1], 0);
      } else {
  	return ConfigElement(wPtr, chPtr, argc-1, argv+1,
  	    TK_CONFIG_ARGV_ONLY, 0);
      }
  }
  
  /*----------------------------------------------------------------------
   * "nearest" sub command
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLNearest(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      int posn[2];
      int index;
      char buff[100];
  
      if (Tcl_GetInt(interp, argv[0], &posn[0]) != TCL_OK) {
  	return TCL_ERROR;
      }
      if (Tcl_GetInt(interp, argv[1], &posn[1]) != TCL_OK) {
  	return TCL_ERROR;
      }
  
      index = Tix_TLGetNearest(wPtr, posn);
      Tcl_ResetResult(interp);
  
      if (index != -1) {
  	sprintf(buff, "%d", index);
  	Tcl_AppendResult(interp, buff, NULL);
      }
      return TCL_OK;
  }
  
  static int Tix_TLGetAt(wPtr, interp, spec, at)
      WidgetPtr wPtr;
      Tcl_Interp *interp;
      CONST84 char * spec;
      int *at;
  {
      int posn[2];
      char *p, *end;
  
      if (spec[0] != '@') {
  	return TCL_ERROR;
      }
  
      p = (char *) spec+1;
      posn[0] = strtol(p, &end, 0);
      if ((end == p) || (*end != ',')) {
  	return TCL_ERROR;
      }
      p = end+1;
      posn[1] = strtol(p, &end, 0);
      if ((end == p) || (*end != 0)) {
  	return TCL_ERROR;
      }
  
      *at = Tix_TLGetNearest(wPtr, posn);
      return TCL_OK;
  }
  
  static int Tix_TLGetNearest(wPtr, posn)
      WidgetPtr wPtr;
      int posn[2];
  {
      int i, j, index;
      int maxX, maxY;
      int r, c;
  
      if (wPtr->resizing) {
  	ResizeNow(wPtr);
      }
  
      if (wPtr->entList.numItems == 0) {
  	return -1;
      }
  
      /* clip off the position with the border of the window */
  
      posn[0] -= wPtr->borderWidth + wPtr->highlightWidth;
      posn[1] -= wPtr->borderWidth + wPtr->highlightWidth;
  
      maxX = Tk_Width (wPtr->dispData.tkwin);
      maxY = Tk_Height(wPtr->dispData.tkwin);
  
      maxX -= 2*(wPtr->borderWidth + wPtr->highlightWidth);
      maxY -= 2*(wPtr->borderWidth + wPtr->highlightWidth);
  
      if (posn[0] >= maxX) {
  	posn[0] =  maxX -1;
      }
      if (posn[1] >= maxY) {
  	posn[1] =  maxY -1;
      }
      if (posn[0] < 0) {
  	posn[0] = 0;
      }
      if (posn[1] < 0) {
  	posn[1] = 0;
      }
  
      i = (wPtr->isVertical == 0);
      j = (wPtr->isVertical == 1);
  
      posn[0] += wPtr->scrollInfo[0].offset;
      posn[1] += wPtr->scrollInfo[1].offset;
  
      r = posn[i] / wPtr->maxSize[i];
      c = posn[j] / wPtr->maxSize[j];
  
      index = (r * wPtr->rows[0].numEnt) + c;
  
      if (index >= wPtr->entList.numItems) {
  	index = wPtr->entList.numItems - 1;
      }
  
      return index;
  }
  
  /*----------------------------------------------------------------------
   * "selection" sub command
   * 	Modify the selection in this HList box
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLGetFromTo(interp, wPtr, argc, argv, fromPtr_ret, toPtr_ret)
      Tcl_Interp *interp;
      WidgetPtr wPtr;
      int argc;
      CONST84 char **argv;
      ListEntry ** fromPtr_ret;
      ListEntry ** toPtr_ret;
  {
      /*
       * ToDo: make it more efficient by saving the previous from and to
       * pointers and make the list of childrens a doubly-linked list
       */
      ListEntry * fromPtr;
      ListEntry * toPtr;
      int from, to, tmp;
  
      if (Tix_TranslateIndex(wPtr, interp, argv[0], &from, 0) != TCL_OK) {
  	return TCL_ERROR;
      }
      if (argc == 2) {
  	if (Tix_TranslateIndex(wPtr, interp, argv[1], &to, 0) != TCL_OK) {
  	    return TCL_ERROR;
  	}
      } else {
  	to = from;
      }
  
      if (from > to) {
  	/* swap from and to */
  	tmp = to; to = from; from = tmp;
      }
  
      fromPtr = NULL;
      toPtr   = NULL;
  
      if (from >= wPtr->entList.numItems) {
  	fromPtr = (ListEntry *)wPtr->entList.tail;
  	toPtr   = (ListEntry *)wPtr->entList.tail;
      }
      if (to >= wPtr->entList.numItems) {
  	toPtr   = (ListEntry *)wPtr->entList.tail;
      }
  
      if (fromPtr == NULL) {
  	for (fromPtr = (ListEntry*)wPtr->entList.head;
  	     from > 0;
  	     fromPtr=fromPtr->next) {
  
  	    -- from;
  	    -- to;
  	}
      }
      if (toPtr == NULL) {
  	for (toPtr = fromPtr; to > 0; toPtr=toPtr->next) {
  	    -- to;
  	}
      }
  
      * fromPtr_ret = fromPtr;
      if (toPtr_ret) {
  	* toPtr_ret = toPtr;
      }
      return TCL_OK;
  }
  
  static int
  Tix_TLSelection(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      size_t len = strlen(argv[0]);
      int code = TCL_OK;
      int changed = 0;
      ListEntry * chPtr, * fromPtr, * toPtr;
  
      if (strncmp(argv[0], "clear", len)==0) {
  	if (argc == 1) {
  	    /*
  	     * Clear all entries
  	     */
  	    for (chPtr=(ListEntry*)wPtr->entList.head;
  		 chPtr;
  		 chPtr=chPtr->next) {
  
  		chPtr->selected = 0;
  	    }
  	    changed = 1;
  	}
  	else {
  	    if (Tix_TLGetFromTo(interp, wPtr, argc-1, argv+1, &fromPtr, &toPtr)
  		    != TCL_OK) {
  		code = TCL_ERROR;
  		goto done;
  	    }
  	    if (fromPtr == NULL) {
  		goto done;
  	    }
  	    else {
  		while (1) {
  		    fromPtr->selected = 0;
  		    if (fromPtr == toPtr) {
  			break;
  		    } else {
  			fromPtr=fromPtr->next;
  		    }
  		}
  		changed = 1;
  		goto done;
  	    }
  	}
      }
      else if (strncmp(argv[0], "includes", len)==0) {
  	if (argc != 2) {
  	    Tix_ArgcError(interp, argc+2, argv-2, 3, "index");
  	    code = TCL_ERROR;
  	    goto done;
  	}
  	if (Tix_TLGetFromTo(interp, wPtr, argc-1, argv+1, &fromPtr, &toPtr)
  		!= TCL_OK) {
  	    code = TCL_ERROR;
  	    goto done;
  	}
  	if (fromPtr->selected) {
  	    Tcl_AppendResult(interp, "1", NULL);
  	} else {
  	    Tcl_AppendResult(interp, "0", NULL);
  	}
      }
      else if (strncmp(argv[0], "set", len)==0) {
  	if (argc < 2 || argc > 3) {
  	    Tix_ArgcError(interp, argc+2, argv-2, 3, "from ?to?");
  	    code = TCL_ERROR;
  	    goto done;
  	}
  
  	if (Tix_TLGetFromTo(interp, wPtr, argc-1, argv+1, &fromPtr, &toPtr)
  		!= TCL_OK) {
  	    code = TCL_ERROR;
  	    goto done;
  	}
  	if (fromPtr == NULL) {
  	    goto done;
  	}
  	else {
  	    while (1) {
  		fromPtr->selected = 1;
  		if (fromPtr == toPtr) {
  		    break;
  		} else {
  		    fromPtr=fromPtr->next;
  		}
  	    }
  	    changed = 1;
  	    goto done;
  	}
      }
      else {
  	Tcl_AppendResult(interp, "unknown option \"", argv[0], 
  	    "\": must be anchor, clear, includes or set", NULL);
  	code = TCL_ERROR;
      }
  
    done:
      if (changed) {
  	RedrawWhenIdle(wPtr);
      }
  
      return code;
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * Tix_TLSee --
   *
   *      Implements the "see" widget subcommand -- make sure that the
   *      given entry is visible as much as possible.
   *
   *      We don't scroll the widget immediately in this function.
   *      Instead, we set the wPtr->seeElemPtr and the scrolling will be
   *      set when the widget is redrawn. This make sure that the "see"
   *      command works even before the widget's contents has been laid
   *      out.
   *
   * Results:
   *      A standard Tcl result.
   *
   * Side effects:
   *      Widget is scheduled to be redrawn.
   *
   *----------------------------------------------------------------------
   */
  
  static int
  Tix_TLSee(clientData, interp, argc, argv)
      ClientData clientData;      /* The widget data struct */
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      ListEntry * chPtr, * dummy;
  
      if (argc == 1) {
  	if (Tix_TLGetFromTo(interp, wPtr, 1, argv, &chPtr, &dummy) != TCL_OK) {
  	    return TCL_ERROR;
  	}
  	if (chPtr != NULL) {
  	    wPtr->seeElemPtr = chPtr;
  	    RedrawWhenIdle(wPtr);
  	}
      } else {
  	Tcl_AppendResult(interp, "wrong # of arguments, must be: ",
  		Tk_PathName(wPtr->dispData.tkwin), " ", argv[-1],
  		" index", NULL);
      }
  
      return TCL_OK;
  }
  
  /*----------------------------------------------------------------------
   * "anchor", "dragsite" and "dropsite" sub commands --
   *
   *	Set/remove the anchor element
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLSetSite(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      int changed = 0;
      WidgetPtr wPtr = (WidgetPtr) clientData;
      ListEntry * fromPtr;
      ListEntry * toPtr;			/* unused */
      ListEntry ** changePtr;
      size_t len;
  
      /* Determine which site should be changed (the last else clause
       * doesn't need to check the string because HandleSubCommand
       * already ensures that only the valid options can be specified.
       **/
      len = strlen(argv[-1]);
      if (strncmp(argv[-1], "anchor", len)==0) {
  	changePtr = &wPtr->anchor;
      }
      else if (strncmp(argv[-1], "active", len)==0) {
  	changePtr = &wPtr->active;
      }
      else if (strncmp(argv[-1], "dragsite", len)==0) {
  	changePtr = &wPtr->dragSite;
      }
      else {
  	changePtr = &wPtr->dropSite;
      }
  
      len = strlen(argv[0]);
      if (strncmp(argv[0], "set", len)==0) {
  	if (argc == 2) {
  	    if (Tix_TLGetFromTo(interp,wPtr, argc-1, argv+1, &fromPtr, &toPtr)
  		    != TCL_OK) {
  		return TCL_ERROR;
  	    }
  	    if (*changePtr != fromPtr) {
  		*changePtr = fromPtr;
  		changed = 1;
  	    }
  	} else {
  	    Tcl_AppendResult(interp, "wrong # of arguments, must be: ",
  		Tk_PathName(wPtr->dispData.tkwin), " ", argv[-1],
  		" set index", NULL);
  	    return TCL_ERROR;
  	}
      }
      else if (strncmp(argv[0], "clear", len)==0) {
  	if (*changePtr != NULL) {
  	    *changePtr = NULL;
  	    changed = 1;
  	}
      }
      else {
  	Tcl_AppendResult(interp, "wrong option \"", argv[0], "\", ",
  	    "must be clear or set", NULL);
  	return TCL_ERROR;
      }
  
      if (changed) {
  	RedrawWhenIdle(wPtr);
      }
  
      return TCL_OK;
  }
  
  /*----------------------------------------------------------------------
   * "xview" and "yview" sub command
   *----------------------------------------------------------------------
   */
  static int
  Tix_TLView(clientData, interp, argc, argv)
      ClientData clientData;
      Tcl_Interp *interp;		/* Current interpreter. */
      int argc;			/* Number of arguments. */
      CONST84 char **argv;	/* Argument strings. */
  {
      WidgetPtr wPtr = (WidgetPtr) clientData;
      int axis;
  
      if (argv[-1][0] == 'x') {
  	axis = 0;
      } else {
  	axis = 1;
      }
  
      if (argc == 0) {
  	char string[80];
  	double first, last;
  
  	Tix_GetScrollFractions((Tix_ScrollInfo*)&wPtr->scrollInfo[axis],
  	    &first, &last);
  
  	sprintf(string, "{%f %f}", first, last);
  	Tcl_AppendResult(interp, string, NULL);
  	return TCL_OK;
      }
      else if (Tix_SetScrollBarView(interp, 
  	(Tix_ScrollInfo*)&wPtr->scrollInfo[axis], argc, argv, 0) != TCL_OK) {
  
  	return TCL_ERROR;
      }
  
      UpdateScrollBars(wPtr, 0);
      RedrawWhenIdle(wPtr);
      return TCL_OK;
  }
  /*----------------------------------------------------------------------
   *
   *
   * 			Memory Management Section
   *
   *
   *----------------------------------------------------------------------
   */
  static int
  ConfigElement(wPtr, chPtr, argc, argv, flags, forced)
      WidgetPtr wPtr;
      ListEntry *chPtr;
      int argc;
      CONST84 char ** argv;
      int flags;
      int forced;
  {
      int sizeChanged;
  
      if (Tix_WidgetConfigure2(wPtr->dispData.interp, wPtr->dispData.tkwin,
  	(char*)chPtr, entryConfigSpecs, chPtr->iPtr, argc, argv, flags,
  	forced, &sizeChanged) != TCL_OK) {
  	return TCL_ERROR;
      }
  
      if (sizeChanged) {
  	chPtr->size[0] = chPtr->iPtr->base.size[0];
  	chPtr->size[1] = chPtr->iPtr->base.size[1];
  	ResizeWhenIdle(wPtr);
      } else {
  	RedrawWhenIdle(wPtr);
      }
      return TCL_OK;
  }
  
  static void
  Realloc(wPtr, new_size)
      WidgetPtr wPtr;
      int new_size;
  {
      if (new_size < 1) {
  	new_size = 1;
      }
      if (new_size == wPtr->numRowAllocd) {
  	return;
      }
      wPtr->rows = (ListRow*)ckrealloc( (char *)wPtr->rows,
                                        sizeof(ListRow)*new_size);
      wPtr->numRowAllocd = new_size;
  }
  
  static void ResizeRows(wPtr, winW, winH)
      WidgetPtr wPtr;
      int winW;			/* -1 == current width */
      int winH;			/* -1 == current height */
  {
      ListEntry * chPtr;
      ListEntry * rowHead;
      int n, c, r;
      int maxI;			/* max of width in the current column */
      int maxJ;			/* max of height among all elements */
      int curRow;
      int i, j;
      int sizeJ;
      int winSize[2];
  
      if (wPtr->isVertical) {
  	i = 0;		/* Column major, 0,0 -> 0,1 -> 0,2 ... -> 1,0 */
  	j = 1;
      } else {
  	i = 1;		/* Row major, 0,0 -> 1,0 -> 2,0 ... -> 0,1 */
  	j = 0;
      }
  
      if (winW == -1) {
  	winW = Tk_Width (wPtr->dispData.tkwin);
      }
      if (winH == -1) {
  	winH = Tk_Height(wPtr->dispData.tkwin);
      }
  
      winSize[0] = winW;
      winSize[1] = winH;
      
      if (wPtr->entList.numItems == 0) {
  	wPtr->rows[0].chPtr = NULL;
  	wPtr->rows[0].size[0] = 1;
  	wPtr->rows[0].size[1] = 1;
  	wPtr->rows[0].numEnt = 0;
  
  	wPtr->numRow = 1;
  	goto done;
      }
  
      /* 	    --  The following verbal description follows the "Column Major"
       *     	model. Row major are similar, just the i,j incides are swapped
       *
       * (1) (a) Search for the tallest element, use it as the height of all
       *         the elements;
       *     (b) Search for the widest element, use it as the width of all
       *         the elements;
       */
      for (maxJ=1, maxI=1, chPtr = (ListEntry*)wPtr->entList.head;
  	 chPtr;
  	 chPtr=chPtr->next) {
  
  	if (maxJ < chPtr->iPtr->base.size[j]) {
  	    maxJ = chPtr->iPtr->base.size[j];
  	}
  	if (maxI < chPtr->iPtr->base.size[i]) {
  	    maxI = chPtr->iPtr->base.size[i];
  	}
      }
      wPtr->maxSize[i] = maxI;
      wPtr->maxSize[j] = maxJ;
  
      /* (2) Calculate how many elements can be in each column
       *
       */
      n = winSize[j] / maxJ;
      if (n <=0) {
  	n = 1;
      }
  
      wPtr->numRow = 0;
      curRow = 0;
      c = 0;
      sizeJ = 0;
      rowHead = (ListEntry*)wPtr->entList.head;
      for(chPtr = (ListEntry*)wPtr->entList.head; chPtr; chPtr=chPtr->next) {
  	sizeJ += chPtr->iPtr->base.size[j];
  	++ c;
  	if (c == n || chPtr->next == NULL) {
  	    if (curRow >= wPtr->numRowAllocd) {
  		Realloc(wPtr, curRow*2);
  	    }
  	    wPtr->rows[curRow].chPtr   = rowHead;
  	    wPtr->rows[curRow].size[i] = maxI;
  	    wPtr->rows[curRow].size[j] = sizeJ;
  	    wPtr->rows[curRow].numEnt  = c;
  	    ++ curRow;
  	    ++ wPtr->numRow;
  	    c = 0;
  	    rowHead = chPtr->next;
  	    sizeJ = 0;
  	}
      }
  
    done:
      /* calculate the size of the total and visible area */
      wPtr->scrollInfo[i].total = 0;
      wPtr->scrollInfo[j].total = 0;
  
      for (r=0; r<wPtr->numRow; r++) {
  	wPtr->scrollInfo[i].total += wPtr->rows[r].size[i];
  	if (wPtr->scrollInfo[j].total < wPtr->rows[r].size[j]) {
  	    wPtr->scrollInfo[j].total = wPtr->rows[r].size[j];
  	}
      }
  
      wPtr->scrollInfo[i].window = winSize[i];
      wPtr->scrollInfo[j].window = winSize[j];
  
      if (wPtr->scrollInfo[i].total < 1) {
  	wPtr->scrollInfo[i].total = 1;
      }
      if (wPtr->scrollInfo[j].total < 1) {
  	wPtr->scrollInfo[j].total = 1;
      }
      if (wPtr->scrollInfo[i].window < 1) {
  	wPtr->scrollInfo[i].window = 1;
      }
      if (wPtr->scrollInfo[j].window < 1) {
  	wPtr->scrollInfo[j].window = 1;
      }
  
      /* If we have much fewer rows now, adjust the size of the rows list */
      if (wPtr->numRowAllocd > (2*wPtr->numRow)) {
  	Realloc(wPtr, 2*wPtr->numRow);
      }
  
      /* Update the scrollbars */
  
      UpdateScrollBars(wPtr, 1);
  }
  /*----------------------------------------------------------------------
   * RedrawRows --
   *
   *	Redraw the rows, according to the "offset" in both directions
   *----------------------------------------------------------------------
   */
  
  static void
  RedrawRows(wPtr, pixmap)
      WidgetPtr wPtr;
      Drawable pixmap;
  {
      int r, n;
      int p[2];
      ListEntry * chPtr;
      int i, j;
      int total;
      int windowSize;
  
      if (wPtr->entList.numItems == 0) {
  	return;
      }
  
      if (wPtr->isVertical) {
  	i = 0;		/* Column major, 0,0 -> 0,1 -> 0,2 ... -> 1,0 */
  	j = 1;
  	windowSize = Tk_Width(wPtr->dispData.tkwin);
      } else {
  	i = 1;		/* Row major, 0,0 -> 1,0 -> 2,0 ... -> 0,1 */
  	j = 0;
  	windowSize = Tk_Height(wPtr->dispData.tkwin);
      }
  
      p[i] = wPtr->highlightWidth + wPtr->borderWidth;
      windowSize -= 2*p[i];
  
      if (windowSize < 1) {
  	windowSize = 1;
      }
  
      if (wPtr->seeElemPtr != NULL) {
  	/*
  	 * Adjust the scrolling so that the given the entry is visible in
           * its entirty (as much as allowed by the height of the TList)
  	 */
  
  	int start = 0;		/* y1 position of the element to see. */
  	int size = 0;		/* height of the element to see. */
  	int old = wPtr->scrollInfo[i].offset;
  
  	for (r=0, n=0, chPtr=(ListEntry*)wPtr->entList.head; chPtr;
  		chPtr=chPtr->next) {
  	    if (chPtr == wPtr->seeElemPtr) {
  		size = chPtr->size[i];
  		break;
  	    }
              n++;
  	    if (n == wPtr->rows[r].numEnt) {
  		n=0;
  		r++;
  		start += wPtr->rows[r].size[i];
  	    }
  	}
  
  	if (wPtr->scrollInfo[i].offset + windowSize < start + size) {
              /*
               * Bottom of the entry is beneath the bottom edge
               */
  	    wPtr->scrollInfo[i].offset = start + size - windowSize;
  	}
  	if (wPtr->scrollInfo[i].offset > start) {
              /*
               * Top of the entry is above the top edge
               */
  	    wPtr->scrollInfo[i].offset = start;
  	}
  	if (wPtr->scrollInfo[i].offset != old) {
  	    UpdateScrollBars(wPtr, 0);
  	}
  	wPtr->seeElemPtr = NULL;
      }
  
      /*
       * Search for the first row from the top (or first column from the left)
       * that is (possibly partially) visible
       */
      total=0; r=0;
      if (wPtr->scrollInfo[i].offset != 0) {
  	for (; r<wPtr->numRow; r++) {
  	    total += wPtr->rows[r].size[i];
  
  	    if (total > wPtr->scrollInfo[i].offset) {
  		p[i] -= wPtr->scrollInfo[i].offset - 
  		        (total - wPtr->rows[r].size[i]);
  		break;
  	    }
  	    if (total == wPtr->scrollInfo[i].offset) {
  		r++;
  		break;
  	    }
  	}
      }
  
      /* Redraw all the visible rows */
      for (; r<wPtr->numRow; r++) {
  
  	p[j] = wPtr->highlightWidth + wPtr->borderWidth;
  
  	total=0; n=0; chPtr=wPtr->rows[r].chPtr;
  	if (wPtr->scrollInfo[j].offset > 0)  {
  	    /* Search for a column that is (possibly partially) visible*/
  	    for (;
  		 n<wPtr->rows[r].numEnt;
  		 n++, chPtr = chPtr->next) {
  
  		total += chPtr->iPtr->base.size[j];
  		if (total > wPtr->scrollInfo[j].offset) {
  		    /* Adjust for the shift due to partially visible elements*/
  		    p[j] -= wPtr->scrollInfo[j].offset - 
  		      (total - chPtr->iPtr->base.size[j]);
  		    break;
  		}
  		if (total == wPtr->scrollInfo[j].offset) {
  		    n++; chPtr = chPtr->next;
  		    break;
  		}
  	    }
  	}
  
  	/* Redraw all the visible columns in this row */
  	for (; n<wPtr->rows[r].numEnt; n++, chPtr = chPtr->next) {
  	    int flags = TIX_DITEM_NORMAL_FG | TIX_DITEM_NORMAL_BG;
  	    int W, H;
  
  	    if (chPtr->selected) {
  		flags |= TIX_DITEM_SELECTED_FG;
  		flags |= TIX_DITEM_SELECTED_BG;
  	    }
  
  	    if (wPtr->isVertical) {
  		W = wPtr->rows[r].size[0];
  		H = chPtr->iPtr->base.size[1];
  	    } else {
  		H = wPtr->rows[r].size[1];
  		W = chPtr->iPtr->base.size[0];
  	    }
  
              if (chPtr == wPtr->anchor && wPtr->hasFocus) {
                  flags |= TIX_DITEM_ANCHOR;
              }
  
  	    Tix_DItemDisplay(pixmap, chPtr->iPtr, p[0], p[1], W, H,
  		0, 0, flags);
  
  #if 0
  	    if (chPtr == wPtr->anchor && wPtr->hasFocus) {
                  GC ancGC;
                  if (chPtr->selected) {
                      ancGC = wPtr->anchorGC;
                  } else {
                      ancGC = wPtr->anchorGC2;
                  }
  		Tix_DrawAnchorLines(Tk_Display(wPtr->dispData.tkwin), pixmap,
  	                ancGC, p[0], p[1], W, H);
  	    }
  #endif
  	    p[j] += wPtr->maxSize[j];
  	}
  
  	/* advance to the next row */
  	p[i]+= wPtr->rows[r].size[i];
      }
  }
  
  /*----------------------------------------------------------------------
   *  UpdateScrollBars
   *----------------------------------------------------------------------
   */
  static void UpdateScrollBars(wPtr, sizeChanged)
      WidgetPtr wPtr;
      int sizeChanged;
  {
      Tix_UpdateScrollBar(wPtr->dispData.interp,
  	(Tix_ScrollInfo*)&wPtr->scrollInfo[0]);
      Tix_UpdateScrollBar(wPtr->dispData.interp,
  	(Tix_ScrollInfo*)&wPtr->scrollInfo[1]);
  
      if (wPtr->sizeCmd && sizeChanged) {
  	if (Tcl_Eval(wPtr->dispData.interp, wPtr->sizeCmd) != TCL_OK) {
  	    Tcl_AddErrorInfo(wPtr->dispData.interp,
  		"\n    (size command executed by tixTList)");
  	    Tk_BackgroundError(wPtr->dispData.interp);
  	}
      }
  }
  