/* panel.c
   make and handle callbacks for the main Xgopher panel */

     /*---------------------------------------------------------------*/
     /* Xgopher        version 1.2     20 November 1991               */
     /*                version 1.1     20 April 1991                  */
     /*                version 1.0     04 March 1991                  */
     /* X window system client for the University of Minnesota        */
     /*                                Internet Gopher System.        */
     /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
     /*                Computing and Communications Services Office   */
     /* Copyright 1992 by                                             */
     /*           the Board of Trustees of the University of Illinois */
     /* Permission is granted to freely copy and redistribute this    */
     /* software with the copyright notice intact.                    */
     /*---------------------------------------------------------------*/


#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/Xaw/Simple.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SmeBSB.h>


#include "gopher.h"
#include "panel.h"
#include "compatR4.h"
#include "item.h"
#include "itemList.h"
#include "dirList.h"
#include "dir.h"
#include "markList.h"
#include "misc.h"
#include "util.h"
#include "options.h"
#include "help.h"
#include "bkmkfile.h"
#include "appres.h"
#include "xglobals.h"
#include "globals.h"


static Widget	dirLabel, dirList,
		markLabel, markList,
		unmarkButton, infoButton,
		markButton,
		upButton, fetchButton,
		copyButton, saveButton, loadButton, unmarkAllButton,
		statusLabel,
		gopherPanel,
		topLevel;

static char	*emptyList[] = {"<none>", NULL};
static	int	selectedDir = XAW_LIST_NONE, selectedMark = XAW_LIST_NONE;


static void     WaitForAllPendingEvents();
static void 	fetchProc();
static void	restartProc();



#define STATE_OF(w, button, condition) \
	if ((condition)) {			  \
	    if (!(currentState & (button))) {	  \
		XtSetValues((w), &sensitive, 1);	  \
		currentState |= (button);	  \
	    }					  \
	} else {				  \
	    if (currentState & button) {	  \
		XtSetValues((w), &insensitive, 1);  \
		currentState &= ~(button);	  \
	    }					  \
	}

#define ANYTHING_SELECTED	((selectedDir  != XAW_LIST_NONE) || \
				 (selectedMark != XAW_LIST_NONE))

#define MARK_SELECTED		(selectedMark != XAW_LIST_NONE)
#define NONMARK_SELECTED	(selectedDir != XAW_LIST_NONE)

static buttonSet	currentState = BS_all | LS_items;

static Arg		infoItemLabelArg = {"label", (XtArgVal) NULL},
			infoDirLabelArg  = {"label", (XtArgVal) NULL},
			markItemLabelArg = {"label", (XtArgVal) NULL},
			markDirLabelArg  = {"label", (XtArgVal) NULL};

void
checkButtonState(which)
buttonSet	which;
{
	static Arg
		sensitive	 = {"sensitive", TRUE},
		insensitive	 = {"sensitive", FALSE};

	if (which & BS_fetch) {
		STATE_OF(fetchButton, BS_fetch, ANYTHING_SELECTED);
	}

	if (which & BS_previous) {
		STATE_OF(upButton, BS_previous,
			(previousDir(getCurrentDir()) != NULL));
	}

	if (which & BS_unmark) {
		STATE_OF(unmarkButton, BS_unmark,
			MARK_SELECTED);
	}


	/* condition could include test to see if file is copy-able */

	if (which & BS_copy) {
		STATE_OF(copyButton, BS_copy, (ANYTHING_SELECTED));
	}


	/* the sensitivity of the mark list tracks the state of unmarkAll */

	if (which & BS_unmarkAll) {
		if (markListLength() != 0) {
		    if (!(currentState & BS_unmarkAll)) {
			XtSetValues(unmarkAllButton, &sensitive, 1);
			XtSetValues(markList, &sensitive, 1);
			currentState |= (BS_unmarkAll);
		    }
		} else {
		    if (currentState & BS_unmarkAll) {
			XtSetValues(unmarkAllButton, &insensitive, 1);
			XtSetValues(markList, &insensitive, 1);
			currentState &= ~(BS_unmarkAll);
		    }
		}
	}


	if (which & BS_loadMarks) {
		STATE_OF(loadButton, BS_loadMarks,
			(appResources->bookmarkFile != NULL &&
			 *(appResources->bookmarkFile) != '\0'));
	}


	if (which & BS_saveMarks) {
		STATE_OF(saveButton, BS_saveMarks,
			((appResources->allowBookmarkSave) &&
		 	 (appResources->bookmarkFile != NULL) &&
			 *(appResources->bookmarkFile) != '\0' &&
		 	 (markListLength() != 0)));
	}


	if (which & BS_info) {

		if (ANYTHING_SELECTED  ||  (getCurrentDir() != NULL)) {
		    if (!(currentState & BS_info)) {
			XtSetValues(infoButton, &sensitive, 1);
			currentState |= (BS_info);
		    }
		    if (ANYTHING_SELECTED) {
			if (!(currentState & LS_infoItem)) {
			    XtSetValues (infoButton, &infoItemLabelArg, 1);
			    currentState |= (LS_infoItem);
			}
		    } else {
			if (currentState & LS_infoItem) {
			    XtSetValues (infoButton, &infoDirLabelArg, 1);
			    currentState &= ~(LS_infoItem);
			}
		    }
		} else {
		    if (currentState & BS_info) {
			XtSetValues(infoButton, &insensitive, 1);
			currentState &= ~(BS_info);
		    }
		}
	}


	if (which & BS_mark) {

		if (NONMARK_SELECTED || (getCurrentDir() != NULL)) {
		    if (!(currentState & (BS_mark))) {
			XtSetValues(markButton, &sensitive, 1);
			currentState |= (BS_mark);
		    }
		    if (NONMARK_SELECTED) {
			if (!(currentState & LS_markItem)) {
			    XtSetValues (markButton, &markItemLabelArg, 1);
			    currentState |= (LS_markItem);
			}
		    } else {
			if (currentState & LS_markItem) {
			    XtSetValues (markButton, &markDirLabelArg, 1);
			    currentState &= ~(LS_markItem);
			}
		    }
		} else {
		    if (currentState & BS_mark) {
			XtSetValues(markButton, &insensitive, 1);
			currentState &= ~(BS_mark);
		    }
		}
	}
}


/* unselectAllProc
   unselect everything in the directory or bookmark lists. */

void
unselectAllProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XawListUnhighlight(dirList);
	selectedDir = XAW_LIST_NONE;

	XawListUnhighlight(markList);
	selectedMark = XAW_LIST_NONE;

	checkButtonState(BS_changeSelected);
}


/* dirSelectProc
   callback for a directory selection */

void
dirSelectProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XawListReturnStruct	*val = (XawListReturnStruct *) call_data;
	gopherItemP		gi;

	if (selectedMark != XAW_LIST_NONE) {
		XawListUnhighlight(markList);
		selectedMark = XAW_LIST_NONE;
	}

	if (appResources->doubleClick  &&  selectedDir == val->list_index) {
		fetchProc(fetchButton, FALSE, NULL);
	} else {
		selectedDir = val->list_index;
		checkButtonState(BS_changeSelected);
	}

	return;
}


/* markSelectProc
   callback for a bookmark selection */

void
markSelectProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XawListReturnStruct	*val = (XawListReturnStruct *) call_data;
	gopherItemP		gi;

	if (selectedDir != XAW_LIST_NONE) {
		XawListUnhighlight(dirList);
		selectedDir = XAW_LIST_NONE;
	}

	if (appResources->doubleClick  &&  selectedMark == val->list_index) {
		fetchProc(fetchButton, FALSE, NULL);
	} else {
		selectedMark = val->list_index;
		checkButtonState(BS_changeSelected);
	}

	return;
}


/* fetchProc
   callback to go to a bookmark or directory item */

static void
fetchProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	gopherItemP	gi;
	BOOLEAN		pushed = (BOOLEAN) client_data;
	BOOLEAN		copy   = (w != fetchButton);

	if (selectedDir != XAW_LIST_NONE) {
		gi = getItemN(getDirContents(getCurrentDir()), selectedDir);
		selectedDir = XAW_LIST_NONE;
		XawListUnhighlight(dirList);
		if (gi != NULL) {
			if (!pushed) XtCallActionProc(fetchButton,
						"set", NULL, NULL, 0);
			copy ? copySelectionToFile(gi) : processSelection(gi);
			if (!pushed) XtCallActionProc(fetchButton,
						"unset", NULL, NULL, 0);
			checkButtonState(BS_changeSelected | BS_previous);
		}
	} else if (selectedMark != XAW_LIST_NONE) {
		gi = getMarkN(selectedMark);
		selectedMark = XAW_LIST_NONE;
		XawListUnhighlight(markList);
		if (gi != NULL) {
			if (!pushed) XtCallActionProc(fetchButton,
						"set", NULL, NULL, 0);
			copy ? copySelectionToFile(gi) : processSelection(gi);
			if (!pushed) XtCallActionProc(fetchButton,
						"unset", NULL, NULL, 0);
			checkButtonState(BS_changeSelected | BS_previous);
		}
	} else {
		/* nothing selected */

		showError( copy ?
			"Something must be selected before it can be copied"
		:
			"Something must be selected before it can be fetched");
	}
}


/* infoProc
   callback to get the raw gopher info or gopher+ info for an item
   and display it */

void
infoProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	gopherItemP	gi;
	gopherDirP	gd;

	if (selectedDir != XAW_LIST_NONE) {
		gi = getItemN(getDirContents(getCurrentDir()), selectedDir);

	} else if (selectedMark != XAW_LIST_NONE) {
		gi = getMarkN(selectedMark);
	
	} else {
		if ((gd = getCurrentDir()) != NULL) {
			gi = gd->selectorItem;
		} else {
			gi = NULL;
		}
	}

	showItemInfo(gi);
}


/* quitProc
   exit callback.  The client_data provided to the callback
   determines if the callback was called by the quit button (action) or
   the restart button (action).  TRUE for QUIT, FALSE for RESTART. */

void
quitProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	BOOLEAN	reallyQuit = (BOOLEAN) client_data;

	reallyQuit  = reallyQuit ^ appResources->swapRestartAndQuit;
	
	if (reallyQuit) {
		cleanUpTextProc();

		if (appResources->allowBookmarkSave) bkmkSave();

		exit(0);
	} else {
		restartProc(w, client_data, call_data);
	}
}


/* helpProc
   help callback. */

void
helpProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{

	showHelp("xgopher help");
}


/* markLoadProc
   load bookmarks callback. */

void
markLoadProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{

	selectedMark = XAW_LIST_NONE;
	bkmkLoad();
	displayBookmarks();
	checkButtonState(BS_all);
}


/* markSaveProc
   save bookmarks callback. */

void
markSaveProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{

	if (appResources->allowBookmarkSave) bkmkSave();
}


/* optionsProc
   options callback. */

void
optionsProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{

	showOptionsPanel();
}


/* oneItemProc
   single custom gopher item callback. */

void
oneItemProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	showSinglePanel();
}


/* versionProc
   version callback. */

void
versionProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{

	displayVersionPanel(topLevel);
}


/* markProc
   callback to set a bookmark at the current directory */

void
markProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	gopherDirP	gd = getCurrentDir();
	gopherItemP	gi;

	if (selectedDir != XAW_LIST_NONE) {
		gi = copyItem( getItemN(getDirContents(gd),
					selectedDir));
	} else if (gd != NULL) {
		gi = copyItem(gd->selectorItem);
	} else {
		gi = NULL;
	}

	if (gi != NULL) {
		markItem(gi);
		selectedMark = XAW_LIST_NONE;
		displayBookmarks();
		checkButtonState(BS_unmark | BS_unmarkAll | BS_saveMarks);
	}
}


/* unmarkProc
   callback to delete a bookmark */

void
unmarkProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XawListReturnStruct	*val;

	val = XawListShowCurrent(markList);
	if (val->list_index != XAW_LIST_NONE) {
		selectedDir = selectedMark = XAW_LIST_NONE;
		unmarkItemN(val->list_index);
		displayBookmarks();
		checkButtonState(BS_unmark | BS_unmarkAll |
				BS_saveMarks | BS_changeSelected);
	}
}


/* unmarkAllProc
   callback to delete all bookmarks */

void
unmarkAllProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	selectedMark = XAW_LIST_NONE;
	unmarkAllItems();
	displayBookmarks();
	checkButtonState(BS_unmark | BS_unmarkAll |
			BS_saveMarks | BS_changeSelected);
}


/* upProc
   callback to go up a level */

void
upProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	selectedDir = selectedMark = XAW_LIST_NONE;
	XawListUnhighlight(markList);
	clearDirWhenOld(previousDir(getCurrentDir()));
	popCurrentDir();
	displayCurrent();
	checkButtonState(BS_changeSelected | BS_previous);
}


/* restartProc
   restart callback. */

static void
restartProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	/* for restart:
	   . undo any current selections
	   . get rid of any displayed text windows,
	   . get rid of any temp files
	   . get rid of name server panel
	   . get rid of sound being played
	   . remove options panel
	   . reset options that the user may have changed on the option panel
	   . unmark all directories
	   . clear directory stack
	   . process initial gopher item
	   . process bookmarks if requested
	   X (can't get rid of telnet/tn3270/??? since we don't
	     really have a handle on them (e.g., PID)
	*/

	gopherItemP	mainItem;
	char		errorString[MESSAGE_STRING_LEN];

	LOG (logFP, "Restart Xgopher\n");

	if (appResources->allowBookmarkSave) bkmkSave();
	
	unselectAllProc(NULL, NULL, NULL);

	removeAllText();
	cleanUpTextProc();

	removeCsoPanel();
	killSound();
	
	removeOptionsPanel();

	unmarkAllProc(NULL, NULL, NULL);

	clearDirStack();
	displayCurrent();

	if (appResources->resetOptions) {
		restoreChangableResources(appResources);
	}

	mainItem = makeItem(A_DIRECTORY,
			appResources->mainTitle, appResources->rootPath,
			appResources->rootServer, appResources->rootPort,
			FALSE);


	if (processSelection(mainItem)) {
		if (appResources->markRoot) {
			markCurrentDirectory();
		}

		if (appResources->loadBookmarks) {
			loadMarks();
		}

	} else {
		sprintf(errorString,
"Unrecoverable error: cannot access the main %s directory at\nhost: %s port %d",
			GOPHER, appResources->rootServer,
			appResources->rootPort);
		showFatalError(errorString);

	}

	checkButtonState(BS_all);
}


/* changeDirLabel
   change the directory list label */

void
changeDirLabel(newLabel)
char	*newLabel;
{
	Arg		args[2];
	Cardinal	n = 0;
	
	XtSetArg(args[n], XtNlabel, (String) newLabel);  n++;
	XtSetValues(dirLabel, args, n);
}


/* changeStatusLabel
   change the status label */

void
changeStatusLabel(newLabel, statType)
char	*newLabel;
int	statType;
{
	Arg		args[2];
	Cardinal	n = 0;
	Display		*dpy;
	static BOOLEAN  waitDefined  = FALSE;
	static		Window	waitWindow;

	dpy = XtDisplay(gopherPanel);
	

	/* Change cursors to show a long wait maybe */

	if (! waitDefined) {
		/* following is from the FAQ file in comp.windows.x */

		unsigned long valuemask;
		XSetWindowAttributes attributes;

		waitDefined = TRUE;

		/* Ignore device events while the busy cursor is displayed. */

		valuemask = CWDontPropagate | CWCursor;
		attributes.do_not_propagate_mask =
			(KeyPressMask | KeyReleaseMask |
			ButtonPressMask | ButtonReleaseMask |
			PointerMotionMask);
		attributes.cursor =
			XCreateFontCursor(XtDisplay(topLevel), XC_watch);

		/* The window will be as big as the display screen,
		   and clipped by its own parent window, so we never
		   have to worry about resizing */

		waitWindow = 
			XCreateWindow(dpy, XtWindow(topLevel),
				0, 0,
				(unsigned int) SERVER_MAX_WINDOW_WIDTH,
				(unsigned int) SERVER_MAX_WINDOW_HEIGHT,
				(unsigned int) 0,
				CopyFromParent, InputOnly, CopyFromParent,
				valuemask, &attributes);
	}
	if (statType == GSTAT_WAIT) {
		XMapWindow(dpy, waitWindow);
		XRaiseWindow(dpy, waitWindow);
	} else {
		XUnmapWindow(dpy, waitWindow);
	}

	n=0;
	XtSetArg(args[n], XtNlabel, (String) newLabel);  n++;
	XtSetValues(statusLabel, args, n);
	WaitForAllPendingEvents(XtDisplay(statusLabel));
}


static void
WaitForAllPendingEvents(dpy)
Display		*dpy;
{
	static XEvent	event;

	XSync(dpy, False);
	while( XtAppPending (appcon) ) {
		XtAppNextEvent(appcon, &event);
		XtDispatchEvent (&event);
	}

}


/* changeDirList
   change the directory list contents */

void
changeDirList(list)
char	*list[];
{
	if (list == NULL  ||  list[0] == NULL) 
		XawListChange(dirList, emptyList, 0, 0, True);	
	else
		XawListChange(dirList, list, 0, 0, True);	
}


/* changeMarkList
   change the bookmark list contents */

void
changeMarkList(list)
char	*list[];
{
	if (list == NULL  ||  list[0] == NULL)
		XawListChange(markList, emptyList, 0, 0, True);	
	else
		XawListChange(markList, list, 0, 0, True);	
}


/* unselectAllActionProc
   implement the unselectAll action */

void
unselectAllActionProc(w, event, params, numParams)
Widget		w[];
XEvent		*event;
String		*params;
Cardinal	*numParams;
{
	unselectAllProc(NULL, NULL, NULL);
}



/* upActionProc
   implement the up action */

void
upActionProc(w, event, params, numParams)
Widget		w[];
XEvent		*event;
String		*params;
Cardinal	*numParams;
{
	if (! atFirstDir()) upProc(upButton, NULL, NULL);
}


#ifdef NOT_NEEDED

/* otherProc
   callback for anything that has no other callback proc. */

void
otherProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	char	errString[256];

	sprintf(errString, "Unsupported command:\n%s", client_data);
	showError(errString);
}

#endif /* NOT_NEEDED */


#define N_OTHERS 8
typedef struct {
	char		*name;
	XtCallbackProc	callback;
	XtPointer	clientData;
} otherMenuItemStruct;

static otherMenuItemStruct otherItems[] = {
			{"copy", fetchProc, (XtPointer) TRUE},
			{"unmarkAll", unmarkAllProc, NULL},
			{"loadMarks", markLoadProc, NULL},
			{"saveMarks", markSaveProc, NULL},
			{"options", optionsProc, NULL},
			{"oneItem", oneItemProc, NULL},
			{"version", versionProc, NULL},
			{"restart", quitProc, (XtPointer) FALSE}};



/* makeGopherPanel
   create the elements of the main gopher panel */

void
makeGopherPanel(top)
Widget	top;
{
	Widget		quitButton, helpButton,
			spacer,
			dirForm, dirView,
			markForm, markView ;
	Widget		statusForm, goBox;
	Widget		otherMenuShell, otherMenuItem[N_OTHERS], otherButton;

	int		i;
	Arg		args[10];
	Cardinal	n;

	static XtActionsRec	actionsTable[] = {
			{"up",           (XtActionProc) upActionProc},
			{"unselectAll",  (XtActionProc) unselectAllActionProc}
		};
	/*
	static char		defaultTranslations[] = "<Key>u:  up()";
	XtTranslations	transTable;
	*/



	topLevel = top;

	XtAppAddActions(appcon, actionsTable, XtNumber(actionsTable));

	makeXThings();


	/* create main gopher panel */
	gopherPanel = XtCreateManagedWidget("gopherPanel", panedWidgetClass,
					topLevel, NULL, (Cardinal) 0);
		/*
		XtAugmentTranslations(gopherPanel, transTable);
		*/

	/* create STATUS form */
	statusForm = XtCreateManagedWidget("statusForm", formWidgetClass,
					gopherPanel, NULL, (Cardinal) 0);


	/* create DIRECTORY FORM */
	dirForm = XtCreateManagedWidget("directoryForm", formWidgetClass,
					gopherPanel, NULL, (Cardinal) 0);

	/* create GO box */
	goBox = XtCreateManagedWidget("goBox", boxWidgetClass,
					gopherPanel, NULL, (Cardinal) 0);


	/* create BOOKMARK FORM */
	markForm = XtCreateManagedWidget("bookmarkForm", formWidgetClass,
					gopherPanel, NULL, (Cardinal) 0);

	/* create QUIT button */

	quitButton = XtCreateManagedWidget("quit", commandWidgetClass,
					statusForm, NULL, (Cardinal) 0);
		XtAddCallback(quitButton, XtNcallback,
				quitProc, (XtPointer) TRUE);


	/* create OTHER ACTIONS button */

		n = 0;
		XtSetArg(args[n], XtNmenuName, "otherActionsMenu");  n++;
#ifndef XGOPHER_X11R4
		XtSetArg(args[n], XtNleftBitmap, pulldownPixmap);  n++;
#endif /* XGOPHER_X11R4 */
	otherButton = XtCreateManagedWidget("other", menuButtonWidgetClass,
					statusForm, args, n);


        /* create OTHER ACTIONS MENU holder */

                n=0;
        otherMenuShell = XtCreatePopupShell("otherActionsMenu",
                                simpleMenuWidgetClass,
				otherButton, args, n);


        /* create OTHER ACTIONS MENU ENTRIES */

        for (i=0; i<N_OTHERS; i++) {
                        n=0;
		/* some items shouldn't be shown in the menu */

		if (strcmp(otherItems[i].name, "copy") == 0  &&
		    ! appResources->allowCopy) continue;
		if (strcmp(otherItems[i].name, "saveMarks") == 0  &&
		    ! appResources->allowBookmarkSave) continue;
		if (strcmp(otherItems[i].name, "options") == 0  &&
		    ! appResources->optionsButton) continue;
		if (strcmp(otherItems[i].name, "restart") == 0  &&
		    ! appResources->restartButton) continue;

                otherMenuItem[i] = XtCreateManagedWidget(otherItems[i].name,
                                        smeBSBObjectClass,
                                        otherMenuShell, args, n);
                        XtAddCallback(otherMenuItem[i], XtNcallback,
						otherItems[i].callback,
						otherItems[i].clientData);

		/* save pointers to some items so they can be turned on/off */

		if (strcmp(otherItems[i].name, "copy") == 0)
			copyButton = otherMenuItem[i];
		if (strcmp(otherItems[i].name, "saveMarks") == 0)
			saveButton = otherMenuItem[i];
		if (strcmp(otherItems[i].name, "loadMarks") == 0)
			loadButton = otherMenuItem[i];
		if (strcmp(otherItems[i].name, "unmarkAll") == 0)
			unmarkAllButton = otherMenuItem[i];
        }
		    

	/* create HELP button */

	helpButton = XtCreateManagedWidget("help", commandWidgetClass,
					statusForm, NULL, (Cardinal) 0);
		XtAddCallback(helpButton, XtNcallback, helpProc, NULL);


	/* create STATUS label */

		n=0;
		/* XtSetArg(args[n], XtNbackgroundPixmap, gray);  n++; */
	statusLabel = XtCreateManagedWidget("status", labelWidgetClass,
					statusForm, args, n);


	/* create GOTO button */

	fetchButton = XtCreateManagedWidget("fetch", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(fetchButton, XtNcallback,
						fetchProc, (XtPointer)TRUE);

	/* create INFO button */

	infoButton = XtCreateManagedWidget("info", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(infoButton, XtNcallback, infoProc,NULL);

		{
		     String temp;
		     XtSetArg(args[0], XtNlabel, &temp);
		     XtGetValues(infoButton, args, 1);
		     infoItemLabel = XtMalloc(sizeof(char) * strlen(temp) + 1);
		     strcpy(infoItemLabel, temp);
	        }
		
		infoItemLabelArg.value  = (XtArgVal) infoItemLabel;
		infoDirLabelArg.value   = (XtArgVal) infoDirLabel;


	/* create UP button */

	upButton = XtCreateManagedWidget("up", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(upButton, XtNcallback, upProc, NULL);


	/* create some space */

	spacer = XtCreateManagedWidget("spacer", simpleWidgetClass,
					goBox, NULL, (Cardinal) 0);

	/* create MARK button */

	markButton = XtCreateManagedWidget("mark", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(markButton, XtNcallback, markProc, NULL);
		
		{
		     String temp;
		     XtSetArg(args[0], XtNlabel, &temp);
		     XtGetValues(markButton, args, 1);
		     markItemLabel = XtMalloc(sizeof(char) * strlen(temp) + 1);
		     strcpy(markItemLabel, temp);
	        }
		
		markItemLabelArg.value  = (XtArgVal) markItemLabel;
		markDirLabelArg.value   = (XtArgVal) markDirLabel;

	/* create UNMARK button */

	unmarkButton = XtCreateManagedWidget("unmark", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(unmarkButton, XtNcallback, unmarkProc, NULL);



	/* ============ DIRECTORY PANEL =========== */

	/* the directory panel will have this heirarchy:
	      directoryForm
		 directoryTitle
		 directoryView
		     directory
		     (scrollbar: automatic)
	*/

	/* create DIRECTORY TITLE label */

		n=0;
		/*
		XtSetArg(args[n], XtNborderWidth, 0);  n++;
		*/
	dirLabel = XtCreateManagedWidget("directoryTitle", labelWidgetClass,
					dirForm, args, n);

	/* create DIRECTORY VIEWPORT */

		n = 0;
		XtSetArg(args[n], XtNfromVert, dirLabel);  n++;
		XtSetArg(args[n], XtNallowVert, True);  n++;
	dirView = XtCreateManagedWidget("directoryView", viewportWidgetClass,
					dirForm, args, n);

	/* create CURRENT DIRECTORY LIST display */

		n = 0;
		XtSetArg(args[n], XtNforceColumns, True);  n++;
		XtSetArg(args[n], XtNdefaultColumns, 1);  n++;
		XtSetArg(args[n], XtNlist, emptyList);  n++;
		XtSetArg(args[n], XtNhorizDistance, 0);  n++;
	dirList = XtCreateManagedWidget("directory", listWidgetClass,
					dirView, args, n);
		XtAddCallback(dirList, XtNcallback, dirSelectProc,NULL);

	/* ============ BOOKMARK PANEL =========== */

	/* the bookmark panel will have this heirarchy:
	      bookmarkForm
		 bookmarkTitle
		 bookmarkView
		     bookmark
		     (scrollbar: automatic)
	*/

	/* create BOOKMARK TITLE label */

		n=0;
		/*
		XtSetArg(args[n], XtNborderWidth, 0);  n++;
		*/
	markLabel = XtCreateManagedWidget("bookmarkTitle", labelWidgetClass,
					markForm, args, n);

	/* create BOOKMARK VIEWPORT */

		n=0;
		XtSetArg(args[n], XtNfromVert, markLabel);  n++;
		XtSetArg(args[n], XtNallowVert, True);  n++;
	markView = XtCreateManagedWidget("bookmarkView", viewportWidgetClass,
					markForm, args, n);

	/* create BOOKMARK LIST display */

		n = 0;
		XtSetArg(args[n], XtNforceColumns, True);  n++;
		XtSetArg(args[n], XtNdefaultColumns, 1);  n++;
		XtSetArg(args[n], XtNlist, emptyList);  n++;
		XtSetArg(args[n], XtNhorizDistance, 0);  n++;
	markList = XtCreateManagedWidget("bookmark", listWidgetClass,
					markView, args, n);
		XtAddCallback(markList, XtNcallback, markSelectProc,NULL);

	checkButtonState(BS_all);

	return;
}

