/*
 * xarchie : An X browser interface to Archie
 *
 * George Ferguson, ferguson@cs.rochester.edu, 2 Nov 1991.
 * Version 2.0: 23 Apr 1993.
 * 28 Apr 1993: Change default host to "archie.sura.net(1526)".
 * 13 May 1993: Apply icon resources to realToplevel.
 *		Don't call XtMapWidget() or -iconic is ignored.
 *		Apply tilde expansion to initial value of ftpLocalDir resource.
 */

#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>	
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/Xaw/Cardinals.h>	
#include <X11/cursorfont.h>
#ifdef MULTILIST
#include <MultiList.h>
#else
#include <X11/Xaw/List.h>
#endif
#include "sysdefs.h"
#include "xarchie.h"
#include "types.h"
#include "appres.h"
#include "weight.h"
#include "db.h"
#include "actions.h"
#include "display.h"
#include "settings.h"
#include "menu.h"
#include "m-defs.h"
#include "status.h"
#include "browser.h"
#include "selection.h"
#include "file-panel.h"
#include "ftp-actions.h"
#include "about.h"
#ifdef HELP
# include "help.h"
#endif
#include "view-file.h"
#include "username.h"
#include "hostname.h"
#include "tilde.h"
#include "syntax.h"
#include "xarchie.xbm"
#include "busy.xbm"

/*	-	-	-	-	-	-	-	-	*/
/*
 * Functions defined in this file:
 */
/* main() */
void bye();
void setBusyStatus(),setIconStatus();

static void initGraphics(),initColors(),initMenus(),initWidgets();
static void initErrorHandlers(), initMisc();
static void browserCallback();
static void setWindowBusyStatus();
static void iconifyEventHandler();
#ifdef DEBUG
static void xerror();
#endif

/*
 * Global graphics data
 */
Display *display;
Screen *screen;
Window root;
Atom WM_DELETE_WINDOW,WM_PROTOCOLS,WM_STATE;

/*
 * Local graphics data
 */
static Cursor busyCursor;

/*
 * Global widget data
 */
XtAppContext appContext;
Widget toplevel,realToplevel;
Widget fileButton,settingsButton;
Widget queryButton,abortButton;
#ifdef HELP
Widget helpButton;
#endif
Widget statusText;
Widget browserForm;
Widget browserUpButton,browserDownButton;
Widget browserViewports[NUM_BROWSER_PANES];
Widget browserScrollbars[NUM_BROWSER_PANES];
Widget browserLists[NUM_BROWSER_PANES];
Widget searchText;
Widget hostText,locationText,fileText,sizeText,modesText,dateText;

/*
 * Other global data
 */
DbEntry *db;
char *program;
char *tmpDirectory;

/*
 * The application resources
 */
AppResources appResources;

/*
 * Non-widget resources obtained from resource manager
 */
static XtResource resources[] = {
    { "searchType", "SearchType", GfRSearchType, sizeof(SearchType),
      XtOffset(AppResources *,searchType), XtRImmediate, (XtPointer)GfExact },
    { "sortType", "SortType", GfRSortType, sizeof(SortType),
      XtOffset(AppResources *,sortType), XtRImmediate, (XtPointer)GfName },
    { "archieHost", "ArchieHost", XtRString, sizeof(String),
      XtOffset(AppResources *,archieHost), XtRImmediate, "archie.sura.net" },
    { "numHosts", "numHosts", XtRInt, sizeof(int),
      XtOffset(AppResources *,numHosts), XtRImmediate, (XtPointer)1 },
    { "maxHits", "MaxHits", XtRInt, sizeof(int),
      XtOffset(AppResources *,maxHits), XtRImmediate, (XtPointer)99 },
    { "offset", "Offset", XtRInt, sizeof(int),
      XtOffset(AppResources *,offset), XtRImmediate, (XtPointer)0 },
    { "timeout", "Timeout", XtRInt, sizeof(int),
      XtOffset(AppResources *,timeout), XtRImmediate, (XtPointer)0 },
    { "retries", "Retries", XtRInt, sizeof(int),
      XtOffset(AppResources *,retries), XtRImmediate, (XtPointer)0 },
    { "niceLevel", "NiceLevel", XtRInt, sizeof(int),
      XtOffset(AppResources *,niceLevel), XtRImmediate, (XtPointer)0 },
    { "ftpLocalDir", "FtpLocalDir", XtRString, sizeof(String),
      XtOffset(AppResources *,ftpLocalDir), XtRImmediate, "" },
    { "ftpType", "FtpType", XtRString, sizeof(String),
      XtOffset(AppResources *,ftpType), XtRImmediate, "binary" },
    { "ftpPrompt", "FtpPrompt", XtRBoolean, sizeof(Boolean),
      XtOffset(AppResources *,ftpPrompt), XtRImmediate, (XtPointer)False },
    { "ftpTrace", "FtpTrace", XtRBoolean, sizeof(Boolean),
      XtOffset(AppResources *,ftpTrace), XtRImmediate, (XtPointer)False },
    { "ftpStrip", "FtpStrip", XtRBoolean, sizeof(Boolean),
      XtOffset(AppResources *,ftpStrip), XtRImmediate, (XtPointer)True },
    { "ftpMailAddress", "FtpMailAddress", XtRString, sizeof(String),
      XtOffset(AppResources *,ftpMailAddress), XtRImmediate, "%s@%s" },
    { "debugLevel", "DebugLevel", XtRInt, sizeof(int),
      XtOffset(AppResources *,debugLevel), XtRImmediate, (XtPointer)0 },
    { "fileWriteOnePerLine", "FileWriteOnePerLine", XtRBoolean,sizeof(Boolean),
      XtOffset(AppResources *,fileWriteOnePerLine), XtRImmediate,
	  						(XtPointer)False },
    { "xarchieFont", "Font", XtRFontStruct, sizeof(XFontStruct*),
      XtOffset(AppResources *,xarchieFont), XtRString, XtDefaultFont },
    { "xarchieBoldFont", "Font", XtRFontStruct, sizeof(XFontStruct*),
      XtOffset(AppResources *,xarchieBoldFont), XtRString, XtDefaultFont },
    { "hostWeights", "HostWeights", XtRString, sizeof(String),
      XtOffset(AppResources *,hostWeights), XtRImmediate, NULL },
    { "autoScroll", "AutoScroll", XtRBoolean, sizeof(Boolean),
      XtOffset(AppResources *,autoScroll), XtRImmediate, (XtPointer)True },
    { "pasteBuffer", "PasteBuffer", XtRBoolean, sizeof(Boolean),
      XtOffset(AppResources *,pasteBuffer), XtRImmediate, (XtPointer)True },
    { "visualType", "VisualType", XtRString, sizeof(String),
      XtOffset(AppResources *,visualType), XtRImmediate, (XtPointer)"" },
    { "defaultIcon", "Icon", XtRBitmap, sizeof(Pixmap),
      XtOffset(AppResources *,defaultIcon), XtRImmediate, None },
    { "busyIcon", "Icon", XtRBitmap, sizeof(Pixmap),
      XtOffset(AppResources *,busyIcon), XtRImmediate, None },
};

/*
 * Non-widget resources set on command line.
 */
static XrmOptionDescRec options[] = {
    { "-search",  ".searchType", XrmoptionSepArg, (XtPointer)"exact" },
    { "-e",	  ".searchType", XrmoptionNoArg,  (XtPointer)"exact" },
    { "-s",	  ".searchType", XrmoptionNoArg,  (XtPointer)"substr" },
    { "-c",	  ".searchType", XrmoptionNoArg,  (XtPointer)"subcase" },
    { "-r",	  ".searchType", XrmoptionNoArg,  (XtPointer)"regexp" },
    { "-es",	  ".searchType", XrmoptionNoArg,  (XtPointer)"exactSubstr" },
    { "-ec",	  ".searchType", XrmoptionNoArg,  (XtPointer)"exactSubcase" },
    { "-er",	  ".searchType", XrmoptionNoArg,  (XtPointer)"exactRegexp" },
    { "-sort",	  ".sortType",	 XrmoptionSepArg, (XtPointer)"name" },
    { "-t",	  ".sortType",	 XrmoptionNoArg,  (XtPointer)"date" },
    { "-w",	  ".sortType",	 XrmoptionNoArg,  (XtPointer)"weight" },
    { "-host",	  ".archieHost", XrmoptionSepArg,
					(XtPointer)"archie.sura.ca" },
    { "-maxhits", ".maxHits",	 XrmoptionSepArg, (XtPointer)"99" },
    { "-offset",  ".offset",	 XrmoptionSepArg, (XtPointer)"0" },
    { "-nice",	  ".niceLevel",	 XrmoptionSepArg, (XtPointer)"0" },
    { "-N",	  ".niceLevel",	 XrmoptionSepArg, (XtPointer)"0" },
    { "-debug",	  ".debugLevel", XrmoptionSepArg, (XtPointer)"1" },
    { "-D",	  ".debugLevel", XrmoptionSepArg, (XtPointer)"1" },
    { "-noscroll",".autoScroll", XrmoptionNoArg,  (XtPointer)"False" },
    { "-mono",	  ".visualType", XrmoptionNoArg,  (XtPointer)"mono" },
    { "-gray",	  ".visualType", XrmoptionNoArg,  (XtPointer)"gray" },
    { "-color",	  ".visualType", XrmoptionNoArg,  (XtPointer)"color" },
};

/*
 * Widget and non-widget resources if the application defaults
 * file can't be found.
 * Generated automatically from Xarchie.ad by "ad2c".
 * Comment out the include line (but not the NULL) if you don't want
 * any resources compiled in.
 */
static String fallbackResources[] = {
#include "Xarchie.ad.h"
    NULL
};

/*	-	-	-	-	-	-	-	-	*/

main(argc,argv)
int argc;
char **argv;
{
  char *old, *new;
  program = argv[0];

  old = getenv("XFILESEARCHPATH");
  if (old) {
    new = XtMalloc((Cardinal) (strlen("XFILESEARCHPATH") +
			       strlen(old) +
			       strlen(XRESOURCES) + 3));
    (void) strcpy(new, "XFILESEARCHPATH");
    (void) strcat(new, "=");
    (void) strcat(new, old);
    (void) strcat(new, ":");
    (void) strcat(new, XRESOURCES);
    putenv(new);
  }
  else {
    new = XtMalloc((Cardinal) (strlen("XFILESEARCHPATH") +
			       strlen(XRESOURCES) + 2));
    (void) strcpy(new, "XFILESEARCHPATH");
    (void) strcat(new, "=");
    (void) strcat(new, XRESOURCES);
    putenv(new);
  }

    /* Init display and application context, other globals, parse args */
    initGraphics(&argc,argv);
    if (argc > 1) {
	syntax(argc,argv);
	bye(1);
    }
    /* Init other non-widget stuff */
    initErrorHandlers();
    initColors();
    initActions();
    initHostWeights();
    /* Then init the menus so they can be found for other widgets */
    initMenus();
    /* Then the main panel widgets */
    initWidgets();
    /* Now we realize so the toplevel window is available */
    XtRealizeWidget(realToplevel);
    /* Other initializations that need to go now */
    initSettings();
#ifdef HELP
    initHelpPanel();
#endif
    initMisc();
    /* Enable WM_DELETE_WINDOW processing */
    (void)XSetWMProtocols(display,XtWindow(realToplevel),&WM_DELETE_WINDOW,1);
    status0("Ready");
    /* Init the data structure for responses */
    db = newEntry();
    resetBrowser();
    setBrowserState(BROWSER_READY);
    /* Do it */
    XtAppMainLoop(appContext);
    /*NOTREACHED*/
}

void
bye(ret)
int ret;
{
    XtDestroyApplicationContext(appContext);
#ifdef CUTCP
    netshut();
#endif
    exit(ret);
}

/*	-	-	-	-	-	-	-	-	*/
/* Initialization routines */

static void
initGraphics(argcp,argv)
int *argcp;
char **argv;
{
    /* Some systems want (Cardinal*), others want (int*) for argcp. */
    realToplevel = toplevel =
	XtAppInitialize(&appContext,"Xarchie",options,XtNumber(options),
			(Cardinal *)argcp,argv,fallbackResources,NULL,ZERO);
    /*
     * Set graphics globals
     */
    display = XtDisplay(realToplevel);
    screen = XtScreen(realToplevel);
    root = RootWindowOfScreen(screen);
    busyCursor = XCreateFontCursor(display,XC_watch);
    WM_PROTOCOLS = XInternAtom(display,"WM_PROTOCOLS",False);
    WM_DELETE_WINDOW = XInternAtom(display,"WM_DELETE_WINDOW",False);
    WM_STATE = XInternAtom(display,"WM_STATE",False);
    /*
     * Set up the resource converters (needs globals)
     */
    initConverters(appContext);
    /*
     * Get non-widget resources
     */
    XtGetApplicationResources(realToplevel,(XtPointer)&appResources,
			      resources,XtNumber(resources),NULL,ZERO);
    /*
     * Realloc these right away so we can free/realloc them later
     */
    appResources.archieHost = XtNewString(appResources.archieHost);
    appResources.ftpLocalDir = XtNewString(appResources.ftpLocalDir);
    appResources.ftpType = XtNewString(appResources.ftpType);
    appResources.hostWeights = XtNewString(appResources.hostWeights);
    /*
     * Catch iconify/deiconify so we can do children also
     */
    XtAddEventHandler(realToplevel,PropertyChangeMask,False,
		      iconifyEventHandler,NULL);
#ifdef DEBUG
    XSetErrorHandler(xerror);
    XSynchronize(display,True);
#endif
}

/*
 * initColors: To allow resources to be specfied separately for color
 *	and mono displays, we add a dummy Form widget below realToplevel
 *	in appropriate circumstances.
 *      This means that:
 *	  - realToplevel gets realized
 *	  - toplevel gets used as parent of children
 */
#define ADDTOPLEVEL(NAME) \
	toplevel = XtCreateManagedWidget(NAME,formWidgetClass, \
					 realToplevel,NULL,0);
static void
initColors()
{
    Visual *visual;

    /* The default is no extra widget (ie. mono) */
    toplevel = realToplevel;
    /* See if the user specified a type */
    if (strcmp(appResources.visualType,"mono") == 0) {
	return;
    } else if (strcmp(appResources.visualType,"color") == 0) {
	ADDTOPLEVEL("color");
	return;
    } else if (strcmp(appResources.visualType,"gray") == 0) {
	ADDTOPLEVEL("gray");
	return;
    }
    /* Otherwise we try to figure it out */
    if ((visual=XDefaultVisualOfScreen(screen)) == NULL) {
	fprintf(stderr,"%s: can't get info about visual!\n",program);
	return;
    }
    if (visual->map_entries > 2) {
	switch (visual->class) {
	  case StaticColor:
	  case PseudoColor:
	  case TrueColor:
	  case DirectColor:
	    ADDTOPLEVEL("color");
	    break;
	  case StaticGray:
	  case GrayScale:
	    ADDTOPLEVEL("gray");
	    break;
	  default:
	    toplevel = realToplevel;
	}
    } else {
	toplevel = realToplevel;
    }
}

/*
 * initMenus: Call all the menu initialization routines
 */
static void
initMenus()
{
    initMenuCreator();		/* must be first */
    initFileMenu();
    initQueryMenu();
    initSettingsMenu();
    initFilePanelMenu();
}

/*
 * initWidgets: Initialize the widgets and set globals variables.
 */
static void
initWidgets()
{
    Widget outerPaned,buttonForm,browserPaned;
    Widget stringForm;
    char name[32];
    int i;

    outerPaned = XtCreateManagedWidget("outerPaned",panedWidgetClass,
				       toplevel,NULL,0);
    /* Button Form */
    buttonForm = XtCreateManagedWidget("buttonForm",formWidgetClass,
				       outerPaned,NULL,0);
    fileButton = XtCreateManagedWidget("fileButton",menuButtonWidgetClass,
				       buttonForm,NULL,0);
    settingsButton = XtCreateManagedWidget("settingsButton",
					   menuButtonWidgetClass,
					   buttonForm,NULL,0);
    queryButton = XtCreateManagedWidget("queryButton",
					menuButtonWidgetClass,
					buttonForm,NULL,0);
    abortButton = XtCreateManagedWidget("abortButton",
					commandWidgetClass,
					buttonForm,NULL,0);
    XtSetSensitive(abortButton,False);
#ifdef HELP
    helpButton = XtCreateManagedWidget("helpButton",commandWidgetClass,
				       buttonForm,NULL,0);
#endif
    (void)XtCreateManagedWidget("statusLabel",labelWidgetClass,
				buttonForm,NULL,0);
    statusText = XtCreateManagedWidget("statusText",asciiTextWidgetClass,
				       buttonForm,NULL,0);
    /* Browser */
    browserForm = XtCreateManagedWidget("browserForm",formWidgetClass,
					outerPaned,NULL,0);
    browserUpButton = XtCreateManagedWidget("browserUpButton",
					    commandWidgetClass,
					    browserForm,NULL,0);
    browserDownButton = XtCreateManagedWidget("browserDownButton",
					      commandWidgetClass,
					      browserForm,NULL,0);
    browserPaned = XtCreateManagedWidget("browserPaned",panedWidgetClass,
					 browserForm,NULL,0);
    for (i=0; i < NUM_BROWSER_PANES; i++) {
	sprintf(name,"browserViewport%d",i);
	browserViewports[i] = XtCreateManagedWidget(name,viewportWidgetClass,
						    browserPaned,NULL,0);
	browserScrollbars[i] = XtNameToWidget(browserViewports[i],"vertical");
	sprintf(name,"browserList%d",i);
#ifdef MULTILIST
	browserLists[i] = XtCreateManagedWidget(name,xfwfMultiListWidgetClass,
						browserViewports[i],NULL,0);
#else
	browserLists[i] = XtCreateManagedWidget(name,listWidgetClass,
						browserViewports[i],NULL,0);
#endif
	clearBrowserPane(i);
	XtAddCallback(browserLists[i],XtNcallback,
		      browserCallback,(XtPointer)i);
    }
    /* String Form */
    stringForm = XtCreateManagedWidget("stringForm",formWidgetClass,
				       outerPaned,NULL,0);
    (void)XtCreateManagedWidget("searchLabel",labelWidgetClass,
				stringForm,NULL,0);
    searchText = XtCreateManagedWidget("searchText",asciiTextWidgetClass,
				       stringForm,NULL,0);
    (void)XtCreateManagedWidget("hostLabel",labelWidgetClass,
				stringForm,NULL,0);
    hostText = XtCreateManagedWidget("hostText",asciiTextWidgetClass,
				     stringForm,NULL,0);
    (void)XtCreateManagedWidget("locationLabel",labelWidgetClass,
				stringForm,NULL,0);
    locationText = XtCreateManagedWidget("locationText",asciiTextWidgetClass,
					 stringForm,NULL,0);
    (void)XtCreateManagedWidget("fileLabel",labelWidgetClass,
				stringForm,NULL,0);
    fileText = XtCreateManagedWidget("fileText",asciiTextWidgetClass,
				     stringForm,NULL,0);
    (void)XtCreateManagedWidget("sizeLabel",labelWidgetClass,
				stringForm,NULL,0);
    sizeText = XtCreateManagedWidget("sizeText",asciiTextWidgetClass,
				     stringForm,NULL,0);
    (void)XtCreateManagedWidget("modesLabel",labelWidgetClass,
				stringForm,NULL,0);
    modesText = XtCreateManagedWidget("modesText",asciiTextWidgetClass,
				      stringForm,NULL,0);
    (void)XtCreateManagedWidget("dateLabel",labelWidgetClass,
				stringForm,NULL,0);
    dateText = XtCreateManagedWidget("dateText",asciiTextWidgetClass,
				     stringForm,NULL,0);
}

static void
initMisc()
{
    char *user,*host,*addr;

    if ((tmpDirectory=getenv("TMPDIR")) == NULL) {
	tmpDirectory = "/tmp";
    }
    user = GetUsername();
    host = GetHostname();
    addr = XtMalloc(strlen(user)+
		    strlen(host)+strlen(appResources.ftpMailAddress));
    sprintf(addr,appResources.ftpMailAddress,user,host);
    appResources.ftpMailAddress = addr;
    /* Do initial tilde expansion if needed */
    if (appResources.ftpLocalDir && *(appResources.ftpLocalDir) == '~') {
	appResources.ftpLocalDir =
	    XtNewString(tildeExpand(appResources.ftpLocalDir));
    }
    /* Use the default icons unless overridden */
    if (appResources.defaultIcon == None) {
	appResources.defaultIcon =
	    XCreateBitmapFromData(display,root,xarchie_bits,
				  xarchie_width,xarchie_height);
    }
    if (appResources.busyIcon == None) {
	appResources.busyIcon =
	    XCreateBitmapFromData(display,root,busy_bits,
				  busy_width,busy_height);
    }
    /* Tell the world about the initial icons */
    setIconStatus(0);
}

/*	-	-	-	-	-	-	-	-	*/
/* The following functions attempt to provide information in the event of
 * a crash. If you have trouble compiling them because of UNIX-isms in
 * the signal handlers, then add -DDONT_CATCH_ERRORS to the definition
 * of DEFINES in the Imakefile and re-make (or just #define it here).
 */
#ifndef DONT_CATCH_ERRORS
#include <signal.h>
static void crashHandler();
#endif /* DONT_CATCH_ERRORS */

static void
initErrorHandlers()
{
#ifndef DONT_CATCH_ERRORS
    signal(SIGBUS,crashHandler);
    signal(SIGSEGV,crashHandler);
#endif /* DONT_CATCH_ERRORS */
}

#ifndef DONT_CATCH_ERRORS
static void
crashHandler(sig)
int sig;
{
    char *s;

    switch (sig) {
	case SIGBUS: s = "SIGBUS"; break;
	case SIGSEGV: s = "SIGSEGV"; break;
	default: s = "UNKNOWN";
    }
    fprintf(stderr,"%s: caught a %s signal!\n",program,s);
    fprintf(stderr,"If you want to report an error, please indicate your hardware type,\n");
    fprintf(stderr,"operating system, compiler, and your version of X and include a\n");
    fprintf(stderr,"backtrace. Thanks.\n");
    abort();
}

#endif /* DONT_CATCH_ERRORS */

#ifdef DEBUG
/*
 * Override default X error handler to force an abort to debugger
 */
static void
xerror(display,event)
Display *display;
XErrorEvent *event;
{
    char buf[256];

    XGetErrorText(display,event->error_code,buf,256);
    printf("XERROR: %d: %s\n",event->error_code,buf);
    abort();
}
#endif

/*	-	-	-	-	-	-	-	-	*/
/* Callback procedures */

/*ARGSUSED*/
static void
browserCallback(w,client_data,call_data)
Widget w;
XtPointer client_data;	/* pane */
XtPointer call_data;	/* returnStruct */
{
    int pane = (int)client_data;
#ifdef MULTILIST
#ifdef DEBUG
    static char *actions[] = { "NOTHING","HIGHLIGHT","UNHIGHLIGHT","STATUS" };
    int i;
#endif
    XfwfMultiListReturnStruct *ret = (XfwfMultiListReturnStruct*)call_data;

#ifdef DEBUG
    printf("Callback: %s, item %d\n",actions[ret->action],ret->item);
    printf("  num_selected = %d\n",ret->num_selected);
    printf("  selected_items[] = ");
    for (i = 0; i < ret->num_selected; i++) {
	printf("%d ",ret->selected_items[i]);
    }
    if (ret->num_selected == 0) printf("None");
    printf("\n");
#endif /* DEBUG */
    switch (ret->action) {
      case XfwfMultiListActionHighlight:
	/* Anything selected? */
	if (ret->item != -1) {
	    /* If just one thing selected, then we came here from Select() */
	    if (ret->num_selected == 1)
		resetSelectionsForPane(pane);
	    selectBrowserItem(pane,ret->item);
	}
	break;
      case XfwfMultiListActionUnhighlight:
	if (ret->item == -1)
	    resetSelectionsForPane(pane);
	else
	    unselectBrowserItem(pane,ret->item);
	break;
    }
#else /* !MULTILIST */
    XawListReturnStruct *ret = (XawListReturnStruct*)call_data;

    resetSelectionsForPane(pane);
    selectBrowserItem(pane,ret->list_index);
#endif /* !MULTILIST */
}

/*	-	-	-	-	-	-	-	-	*/
/* Misc. routines */

void
setBusyStatus(state)
Boolean state;
{
    setWindowBusyStatus(XtWindow(realToplevel),state);
}

static void
setWindowBusyStatus(window,state)
Window window;
Boolean state;
{
    Window root,parent,*children;
    unsigned int numChildren;
    int i;

    /* Do the window */
    if (state)
	XDefineCursor(display,window,busyCursor);
    else
	XUndefineCursor(display,window);
    /* And all the children... */
    if (XQueryTree(display,window,&root,&parent,&children,&numChildren) != 0) {
	for (i=0; i < numChildren; i++) {
	    setWindowBusyStatus(*(children+i),state);
	}
	if (numChildren > 0)
	    XFree((char *)children);
    }
}
		
/*	-	-	-	-	-	-	-	-	*/

/*ARGSUSED*/
static void
iconifyEventHandler(w,client_data,event,cont)
Widget w;
XtPointer client_data;
XEvent *event;
Boolean *cont;
{
    int state;

    if (event->xproperty.state == PropertyNewValue &&
	event->xproperty.atom == WM_STATE) {
	Atom actual_type;
	int actual_format;
	unsigned long nitems = 0, bytes_after = 0;
	unsigned char* data = NULL;

	if (XGetWindowProperty(display,XtWindow(realToplevel),
			       WM_STATE,0,2,False,AnyPropertyType,
			       &actual_type,&actual_format,
			       &nitems,&bytes_after,&data) == Success) {
	    state = *(int *)data;
	    setSettingsShellState(state);
	    setFileShellState(state);
#ifdef HELP
	    setHelpShellState(state);
#endif
	    setAboutShellState(state);
	    setFtpTraceShellState(state);
	    XFree((char *)data);
	}
    }
}

void
setIconStatus(state)
Boolean state;
{
    Pixmap pixmap;
    char *name;
    Arg args[2];

    if (state == True) {
	pixmap = appResources.busyIcon;
	name = "xarchie:busy";
    } else {
	pixmap = appResources.defaultIcon;
	name = "xarchie";
    }
    XtSetArg(args[0],XtNiconName,name);
    XtSetArg(args[1],XtNiconPixmap,pixmap);
    XtSetValues(realToplevel,args,2);
}
