/* ************************************************************************* *
   xfsm - (C) Copyright 1993-1999 Robert Gasch (Robert_Gasch@peoplesoft.com)
	  http://www.peoplesoft.com/peoplepages/g/robert_gasch/src/

   Permission to use, copy, modify and distribute this software for any 
   purpose and without fee is hereby granted, provided that this copyright
   notice appear in all copies as well as supporting documentation. All
   work developed as a consequence of the use of this program should duly
   acknowledge such use.

   No representations are made about the suitability of this software for
   any purpose. This software is provided "as is" without express or implied 
   warranty.

   See the GNU General Public Licence for more information.
 * ************************************************************************* */



/* *************************************************************************
   This program displays a list of bar graphs for the file systems of the 
   machine you are on. The following switches are supported:

	+rv			reverse video (use to override xrdb entry) 
	+synchronous		syncronous mode (use to override xrdb entry)
	-?			help
	-A			show available space in MB
	-a			absolute display mode
	-background <arg>	backgound color 
	-b			black bars (disable gray fill)
	-bg <arg>		same as -background 
	-bordercolor <arg>	border color
	-borderwidth <arg>	border width
	-d <arg1 ... argn>      ignore these file systems
        -D <arg1 ... argn>      ignore file systems matching these patterns
	-detailgeometry <arg> 	Geometry of detail window. Only X and Y are 
					honoured
	-display		display
	-e			extend warning to ring bell when at least
					one file system is above warning level
	-fg <arg>		same as -forground
	-font <arg>		font
	-foreground <arg>	forground color (also file system bar color)
	-geometry <arg>		geometry (will override extreme window sizes to 
					apply reasonable settings)
	-help			help
	-i <arg>		interval at which stats are updated(default=60s)
	-iconic			iconic
	-it <arg1 ... argn>     ignore file systems of this type (*)
	-m			minimize window size
	-mb			draw menu borders
	-mnl			minimize window size so that the longest file 
					system name fits
	-name <arg>		run xfsm under this name
	-ot <arg>               show only file systems of this type (*)
	-oi			override ignore
	-p			don't display percentages
	-pu			popup alarm flag 
	-r			display space with respect to root
	-rootdf			show df % values when running in root mode
	-rs <arg>		specify the amount of space reserved for root
	-rv 			reverse video
	-s <arg1 ... argn>	show only these file systems
	-S <arg1 ... argn>	select only file systems matching these patterns
	-sb			show biggest file system size in lower right 
	-sort			sort file systems according to name 
	-synchronous		synchronous mode
	-title			title for main window
	-v			verbose
	-w <arg>		display warning when usage reaches <arg> %
	-wl0c			color for all entries below first warning level
	-wl1 <arg>		threshold for first warning level
	-wl1c <arg>		color for first warning level
	-wl2 <arg>		threshold for second warning level
	-wl2c <arg>		color for second warning level
	-wl3 <arg>		threshold for third warning level
	-wl3c <arg>		color for third warning level
	-xrm			set an entry in the resource database for this
					execution only
	help			help



   Version History:
	24-03-93: 1.00 
	29-03-93: 1.01 
			Added support for gray filling of graphs
	10-04-93: 1.10 
			Added resize support, detail window title,
			fixed interval handling in msleep delay loop,
			added -m, -p and -s option
	12-04-93: 1.11
			Fixed resize bug which resulted in graph
			heights being too small
	14-04-93: 1.20
			Fixed percent display placement, added -t flag 
			and toggle handling
	16-04-93: 1.21
			Added MB line for detail window
	18-04-93: 1.22
			Fixed overflow problem for MB line (detail window)
			for very large file systems, adapted sleep 
			handling to allow larger scaling of sleep time
	19-04-93: 1.23
			Added LINUX ifdefs
	22-04-93: 1.24
			Added close on direct mouse button in detail window
	23-04-93: 1.30
			Fixed Expose event handling problem which resulted
			in too may redraws upon resizing, corrected the
			handling of get_fs_stat, fixed problem where in a 
			small window percentages get overwritten by long
			file system names and added some cosmetic
			changes to the code.
	25-04-93: 1.31
			Fixed file system truncation for corrent handling 
			of percent option.
	26-04-93: 1.32
			Fixed AIX handling, added HPUX #defines and fixed some
			problems which resulted in warnings and errors on
			stringent compilers.
	29-04-93: 1.40
			Added OSF1, DYNIX, SOLARIS and ULTRIX #ifdefs, fixed 
			expose event handling problems, added warning pixmap 
			and bell options, fixed potential problem for command 
			line options handling for flags which require arguments,
			added automount handling and -l flag, added window
			resize code for changing number of FS, changed 
			workings of -d option in conjuction with -l option
	05-05-93: 1.41
			Added -v optionm, added -mb option, fixed bugs in 
			autmount resize code.
	06-05-93: 1.42
			Moved warning pixmap to right of percent display, 
			made 'q' global quit key, made 'c' close key for 
			detail window , added -D flag 
	19-05-93: 1.43	
			changed structure handling to #defines in main.h to 
			avoid all the porting exceptions messing up the code. 
	22-05-93: 1.50	
			changed popen() to actual system calls (*much* more 
			efficient), removed -l flag made the continoual
			rechecking default (and only) mode, added device 
			name to detail window, added stat() check for 
			updating mounted FS list. 
	25-05-93: 1.51	
			Added "+" warning to device name string on length 
			overflow
	01-06-93: 1.52
			Standardized and fixed -d and -D options, fixed 
			update for OSF1, fixed some *nasty* bugs for AIX
	02-06-93: 1.53
			Added check for file system of type ignore,
			fixed pointer to integer comarisons for strcmp()
	03-06-93: 1.54	
			Added -mnl flag, fixed some redraw inefficiencies
	07-06-93: 1.55	
			Fixed bug for -mnl option resizing, added ULTRIX &&
			DYNIX patches, added strstr for DYNIX
	10-06-93: 1.56
			Added dynamic resizing for detail window.
	10-06-93: 1.60
			Added XResource handling, colors, fixed core 
			dump for AIX, added missing AIX ifdef, ifndefed 
			caluclations unsuitable for TOS
	23-07-93: 1.61
			Changed AIX getfsent to mntctl, fixed some resize 
			problems, extended -geometry option to include size.
	04-08-93: 1.62
			Removed f_bavail for HPUX, fix core causing bug in 
			call to fix_fs_win_width(), started wondering about 
			portability of catlist(), removed display of f_favail
			for AIX, DYNIX and HPUX.
	13-08-93: 1.63
			Fixed problem for bar/percentage association when 				file systems are umounted (this is a rather quick 
			and dirty fix but it should not be a problem even 
			though it requires 2 extra redraws), improved 
			protability for catlist().
	17-08-93: 1.64
			Applied some OSF1 patches, fixed resize bug, 
			finally got warning levels correctly working, 
			added automatic disabling of gray fill upon use 
			of -fg, added -rs flag. 
	20-08-93: 1.65
			fixed initialization of main window size in 
			conjunction with file system of size 0, cleaned
			up old, outdated code ...
	06-09-93: 1.66
			fixed inconsistency with HPUX && SYSV #define,
			made getBoolResource case insensitive, made 
			detail window resize font independent ...
	10-09-93: 1.70
			removed TOS support, added mount type and 
			option info, changed MOUNT_FILE for SOLARIS
	14-09-93: 1.71
			added SCO support, cleaned up some more code, 
			accounted for ULTRIX fixed block size (1K) 
	21-09-93: 1.72
			added -sort option, changed warning levels
			default to -1, added -fsb option  
	19-10-93: 1.73
			added indexing scheme to make sort more efficient
			and flexible, changed some data structures 
	11-02-94: 1.74
			finished SCO support, added support for multiple
			block sizes
	14-02-94: 1.75
			changed SCO stuff to use popen (), fixed some misspelled
			OSF1 lables, fixed comparison in write_percent()

	15-02-94: 1.76
			changed comparison with warn<x>val to fix bug in 
			assigning warning colors, changes SYSV ifdefs back to
			SVR4 to solve inconsistencies

	17-02-94: 1.77
			Fixed ULTRIX core dump, added FreeBSD #ifdefs,
			changed AIX buffer to 128K, added NFS bounds 
			checking for AIX, 
	18-02-94: 1.78
			changed AIX buffer size to #define BUFFERSIZE, added
			-it and -ot options, ifndefed some more stuff for SCO

	22-02-94: 1.79
			added AUX support

	04-03-94: 1.80
			fixed -mnl option core dump under SunOS and -mnl
			problems under other machines

	10-03-94: 1.81
			changed file structure to allow code sharing with
			xofm
	04-08-94: 1.82
			changed Imakefile, APP_DEFAULTS_DIR handling and 
			the format of the call the DefaultDepth which 
			broke some preprocessors.
	09-09-94: 1.83
			added check for resrouce file. Xfsm will now look 
			first in XAPPLRESDIR. If that turns up empty, we
			look in  APP_DEFAULTS_DIR (which is the global 
			preferences stuff). Also fixed the problem with 
			system which don't allow the stat() shortcut where 
			file systems of size 0 are reported on each update 
			in verbose mode.
	21-10-94: 1.84
			fixed -fb flag message 
	11-11-94: 1.85
			added SGI ifdefs
	31-03-95: 1.86
			Fixed handling of any file system type containing the 
                        string "msdos": no reserved space is assumed now,
			fixed potential core dump when checking non-existant
                        XAPPLRESDIR, reduced SCO detail window size, added 
			-sb flag, fixed unitialized msg in process_databases().

	04-05-95: 1.87
			Added -A, -s, -S flag, allowed SOLARIS to ignore 
			file systems via MNTOPT_IGNORE/MNTTYPE_IGNORE, 
			fixed slight resource problems, fixed man page. 
	28-03-96: 1.88
			Changed address to Robert_Gasch@peoplesoft.com, 
			fixed some warnings gcc -Wall showed
	07-07-96: 1.89
			Fixed MS-DOS free system calculation, fixed 
			-e flag problems
	14-10-96: 1.90
			Changed LINUX default for reserverd space to 
			5% since this is the default for ext2. 
	20-01-97: 1.91  
			Added -wl0c argument to set a color for all file
			systems below the wl1 warning level, added
			-title argument which can override hostname in 
			Main window title (useful when monitoring other
			system's NFS-mounted file systems -- you can put
			the other host's name in the title bar). Also
			added a port for DG/UX. (patch supplied by Eric 
			H. Raskin (ehr@internetmci.com))
	01-02-97: 1.92
			Added some minor fixes, most noticably whenever
			you specify a other than -bg the gray fill pattern 
			will be turned off, fixed -w bug. 
	04-02-97: 1.93
			Added -oi (override ignore) to keep file systems
			which are marked ignore. 

	15-07-97: 1.94
			Patch to fix minor SGI problem 
	10-08-97: 1.95
			Not sure anymore, something minor
	02-12-97: 1.96
			added BSDI ifdefs 
	12-05-98: 1.97
			added -rootdf flag, fixed round error for percentace 
			calculation. 
	07-02-98: 1.98
			fixes for SGI and added -ab (alwaysbeep) flag 
	15-02-98: 1.99
			added -n32 to SGI flags in Makefile.std

  ************************************************************************* */


#include "xfsm.h"

Display			*mydisplay;
char*			myname;		/* Name we hunt resources with */
char*			title=NULL;	/* Title to put on main window */
XrmDatabase		resourceDB;		/* X resources. */
WinType			main_win,		/* main window */
			menu[MENU_ITEMS],	/* menu items */
			fs_win[MAXFS],		/* FS graphs */
			detail_win,		/* detail window */
			global_win;		/* compatability in util.c */
XGCValues		gray_gc_val;		/* GC values for gray fill */
XEvent			myevent;		/* event */
unsigned long		fg, bg;			/* forgrund, background */
unsigned long		warncols[4];		/* warning level colors */
XSizeHints		mainwin_hint,		/* main Window size hints */
			szhint;			/* detail Window size hints */ 
Pixmap			warn_pix,		/* Warning Pixmap */
			popup_pix;		/* Popup Pixmap */
int 			show_use=TRUE,		/* do we show user or root */
			upd_interval=60,	/* when do we update stats */
			NFS=0,			/* number of file systems */
			detail_open=NOGOOD,	/* which detail_wind is open */
			detail_share_color = FALSE, /* */
			minimize=FALSE,		/* minimize dimensions */
			menu_border=FALSE,	/* menu border */
			fs_border=1,		/* file system border */
			percent=TRUE,		/* show percent */
			absolute=FALSE,		/* make bar size relative */
			available=FALSE,	/* show available MB */
			bell=FALSE,		/* ring bell for warning */
			alwaysbeep=FALSE,	/* aways ring bell (or just first time) */
			popup=FALSE,		/* activate popup */
			fs_level[MAXFS],        /* warn level for FS */
			fs_warn[MAXFS],         /* warn this time? (per FS) */
			fs_bell[MAXFS],         /* sound bell this time? (per FS) */
			verbose=FALSE,		/* verbose mode */
			sort=FALSE,		/* do we sort by name? */
			gray,			/* use gray fill */
			override_ignore,	/* do we keep FSs marked ignore? */
			rootdf=FALSE,		/* show df % output when running in root mode */
			idx[MAXFS],		/* index to use when sorting */
			show_blocks,		/* compatability in util.c */
			show_biggest=FALSE,	/* show biggest size */
#ifdef SCO
			root=TRUE;		/* root or non-root */
#else
			root=FALSE;		/* root or non-root */
#endif /* SCO */
double			b_blocks=0,		/* biggest # of blocks */
			b_bsize=0,		/* biggest block size */
			b_bytes,		/*for compatability in util.c */
			o_b_blocks,		/* old biggest blocks */
			o_b_bsize,		/* old biggest block size */
			o_b_bytes,		/*for compatability in util.c */
			b_disk,			/* biggest disk */
			o_b_disk;		/* old biggest disk */
unsigned long		turns=0;		/* how many turns */
float			fs_perc[MAXFS],		/* percentage for FS */
			res_space,		/* % space reserved for root */
			warnvals[4],		/* warn val level 3 */
			warn_val=0;		/* waring threshold used
						   for "!" after FS name */
StringInfo		strinfo[MAXFS];		/* all system static strings */
MyString		hname;			/* hostname */
struct statfs 		stats[MAXFS];		/* FS stats structure */


/* *** get the gray bitmap and define our warning bitmap *** */
#include <X11/bitmaps/gray1>
static char warn_bits[] = {
   0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06};

static char popup_bits[] = {
   0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18}; 

static XrmOptionDescRec opTable[] = {
		/* KEEP THIS SORTED BY THE FIRST ARGUMENT! */
/* the char * should be XPointer but many systems don't support it */
{"+rv",		"*reverseVideo", XrmoptionNoArg,	(char *) "off"},
{"+synchronous","*synchronous",	XrmoptionNoArg,		(char *) "off"},
{"-?",		".help",	XrmoptionNoArg,		(char *) "on"},
{"-A",		".available",	XrmoptionNoArg,		(char *) "on"},
{"-a",		".absolute",	XrmoptionNoArg,		(char *) "on"},
{"-ab",		".alwaysbeep",	XrmoptionNoArg,		(char *) "off"},
{"-background",	"*background",	XrmoptionSepArg,	(char *) NULL},
{"-b",		".gray",	XrmoptionNoArg,		(char *) "off"},
{"-bg",		"*background",	XrmoptionSepArg,	(char *) NULL},
{"-bordercolor","*borderColor",	XrmoptionSepArg,	(char *) NULL},
{"-borderwidth",".borderWidth",	XrmoptionSepArg,	(char *) NULL},
{"-detailgeometry", "*detailWin.geometry", XrmoptionSepArg,	(char *) NULL},
{"-display",	".display",     XrmoptionSepArg,	(char *) NULL},
{"-e",		".bell",	XrmoptionNoArg,		(char *) "on"},
{"-f",		".used",	XrmoptionNoArg,		(char *) "off"},
{"-fg",		"*foreground",	XrmoptionSepArg,	(char *) NULL},
{"-font",	"*font",	XrmoptionSepArg,	(char *) NULL},
{"-foreground",	"*foreground",	XrmoptionSepArg,	(char *) NULL},
{"-fsb",	".fs_border",	XrmoptionNoArg,		(char *) "off"},
{"-geometry",	"*mainWin.geometry",	XrmoptionSepArg,(char *) NULL},
{"-help",	".help",	XrmoptionNoArg,		(char *) "on"},
{"-i",		".updInterval",	XrmoptionSepArg,	(char *) NULL},
{"-iconic",	".iconic",	XrmoptionNoArg,		(char *) "on"},
{"-m",		".minimize",	XrmoptionNoArg,		(char *) "1"},
{"-mb",		".menuborder",	XrmoptionNoArg,		(char *) "on"},
{"-mnl",	".minimize",	XrmoptionNoArg,		(char *) "2"},
{"-name",	".name",	XrmoptionSepArg,	(char *) NULL},
{"-oi",		".override_ignore",XrmoptionNoArg, 	(char *) "on"},
{"-p",		".percent",	XrmoptionNoArg,		(char *) "off"},
{"-pu",		".popup",	XrmoptionNoArg,		(char *) "on"},
#ifndef SCO
{"-r",		".root",	XrmoptionNoArg,		(char *) "on"},
{"-rootdf",	".rootdf",	XrmoptionNoArg,		(char *) "on"},
#endif
{"-rs",		".reserved_space",XrmoptionSepArg,	(char *) "NULL"},
{"-rv",		"*reverseVideo", XrmoptionNoArg,	(char *) "on"},
{"-sb",		".showbiggest" , XrmoptionNoArg,	(char *) "on"},
{"-sort",	".sort",	XrmoptionNoArg,		(char *) "on"},
{"-synchronous","*synchronous",	XrmoptionNoArg,		(char *) "on"},
{"-title",	".title",	XrmoptionSepArg,	(char *) NULL},
{"-v",		".verbose",	XrmoptionNoArg,		(char *) "on"},
{"-w",		".warnval",     XrmoptionSepArg,	(char *) NULL},
{"-wl0c",	".warn0col",	XrmoptionSepArg,	(char *) NULL},
{"-wl1",	".warn1val",    XrmoptionSepArg,	(char *) NULL},
{"-wl1c",	".warn1col",    XrmoptionSepArg,	(char *) NULL},
{"-wl2",	".warn2val",    XrmoptionSepArg,	(char *) NULL},
{"-wl2c",	".warn2col",    XrmoptionSepArg,	(char *) NULL},
{"-wl3",	".warn3val",    XrmoptionSepArg,	(char *) NULL},
{"-wl3c",	".warn3col",    XrmoptionSepArg,	(char *) NULL},
{"-xrm",	NULL,		XrmoptionResArg,	(char *) NULL},
{"help",	".help",	XrmoptionNoArg,		(char *) "on"},
};


int main (argc, argv)
int argc;
char **argv;
{
	int 		i=0;
	XrmDatabase 	commandlineDB=NULL;
	char* 		myDisplayName = NULL;
	XrmString 	str_type;
	XrmValue 	value;

	/* *** Try and work out the name the application will run under *** */
	/* *** This needed for finding the correct resources. *** */
	{
	char** ptr = &argv[1];

	for (; *ptr != NULL; ptr++)
	if (strcmp(*ptr, "-name") == 0 && *(ptr + 1) != NULL) 
		{
		myname = *(ptr + 1);
		break;
		}

	if (*ptr == NULL) 
		{
		char* ptr1 = rindex(argv[0], '/');
		if (ptr1)
			myname = ++ptr1;
		else
			myname = argv[0];
		}
	}

	XrmInitialize();
	XrmParseCommand(&commandlineDB, opTable, 
		sizeof(opTable) / sizeof(opTable[0]), myname, &argc, argv);
	if (XrmGetResource(commandlineDB, 
		catlist(myname, ".name", (char*) NULL), "Xfsm.Name", 
		&str_type, &value))
			myname = value.addr;

	if (XrmGetResource(commandlineDB, 
		catlist(myname, ".title", (char*) NULL), "Xfsm.Title", 
		&str_type, &value))
                        title = value.addr;

	if (XrmGetResource(commandlineDB, 
		catlist(myname, ".display", (char*) NULL), "Xfsm.Display", 
		&str_type, &value))
			myDisplayName = value.addr;

	/* *** connect to X Server and assign screen *** */
	if ((mydisplay = XOpenDisplay(myDisplayName)) == NULL) 
		{
		fprintf (stderr, "Error Opening Display ... Exiting\n");
		exit (1);
		}

	/* *** process arguments and the resource database *** */
	process_databases (argc, argv, commandlineDB);

	/* *** Turn on X server synchronization if the user wants it. *** */
	XSynchronize(mydisplay, getBoolResource(resourceDB,
		catlist(myname, ".synchronous", (char*) NULL),
		"Xfsm.Synchronous", False));

	/* *** get hostname *** */
	if (!(gethostname (hname, STRLENGTH))) 
		{
		if (verbose)
			printf ("Hostname = %s\n", hname);
		} 
	else
		fprintf (stderr, "Can't read hostname ...\n");

	/* *** initialize index *** */
	for (i=0; i<MAXFS; i++)
		{
		idx[i]=i;
		fs_level[i]=0;
		fs_bell[i]=0;
		fs_warn[i]=FALSE;
		}

	/* *** get the file system statistics *** */
	/* *** this also handles getting the  *** */
	/* *** info from mount                *** */
	if (minimize == MNL)
		main_win.font_info = getFontResource (resourceDB,
			catlist(myname, ".mainWin.font", (char*) NULL),
			"Xfsm.MainWin.Font",
			XLoadQueryFont(mydisplay, DEFAULT_FONT));
	get_fs_stat();
	if (verbose) 
		{
		for (i = 0; i < NFS; i++)
			printf ("%s\n", FsName);
		printf ("%d valid file systems found ...\n", NFS);
		}

	init_all_windows();

	/* *** Check to see of the user wants the colors reversed. *** */
	if (getBoolResource(resourceDB, 
		catlist(myname, ".reverseVideo", (char*) NULL),
		"Xfsm.ReverseVideo", False)) 
		{
		long temp;
		temp = fg; 
		fg = bg ; 
		bg = temp;
		}

	/* *** create Main Program Window and set up the properties. *** */
	{
	XClassHint clshint;
	XWMHints wmhints;

	mainwin_hint.min_width = MIN_WIN_X;
	mainwin_hint.min_height = ((MIN_INTERVAL(main_win) * NFS) +
		BEGIN_NFS(main_win));
	mainwin_hint.width = main_win.width;
	mainwin_hint.height = main_win.height;
	mainwin_hint.x = main_win.x;
	mainwin_hint.y = main_win.y;
	mainwin_hint.flags = main_win.flags | PMinSize | PSize;

	clshint.res_name  = myname;
	clshint.res_class = CLASS_NAME;

	wmhints.input = True;
	wmhints.initial_state = (getBoolResource(resourceDB,
		catlist(myname, ".iconic", (char*) NULL), 
		"Xfsm.Iconic", False))
      		? IconicState : NormalState;
	wmhints.window_group = main_win.win;
	wmhints.flags = InputHint | StateHint | WindowGroupHint;

	create_window (DefaultRootWindow(mydisplay), &main_win, fg, bg);
	XSetStandardProperties (mydisplay, main_win.win, main_win.text,
		main_win.text, None, argv, argc, &mainwin_hint);
	XSetClassHint(mydisplay, main_win.win, &clshint);
	XSetWMHints(mydisplay, main_win.win, &wmhints);
	}

	/* ** Create the pixmap of the gray background. ** */
	gray_gc_val.stipple = XCreatePixmapFromBitmapData(mydisplay,
		DefaultRootWindow(mydisplay), gray1_bits, gray1_width, 
		gray1_height, fg, bg, 1);

	if (!gray_gc_val.stipple) 
		{
		fprintf (stderr, 
		   "Couldn't create gray tile ... escaping to black fill.\n");
		gray = FALSE;
		} 
	else
		gray_gc_val.fill_style = FillOpaqueStippled;

	/* *** create all the buttons using child windows *** */
	for (i = 0; i < MENU_ITEMS ; ++i) 
		create_window (main_win.win, &menu[i], fg, bg); 
	for (i = 0; i < NFS; i++) 
		{
		fix_fs_win_width(i); 
		create_window (main_win.win, &fs_win[i],
			getColorResource(resourceDB, 
			catlist(myname, ".", FsName,
			".foreground", (char*)NULL),
			"Xfsm.FileSystem.Foreground", fg),
			getColorResource(resourceDB, 
			catlist(myname, ".", FsName,
			".background", (char*)NULL), 
			"Xfsm.FileSystem.Background", bg));

	if (gray)
		XChangeGC (mydisplay, fs_win[i].gc, GCFillStyle | GCStipple,
		&gray_gc_val);
		}

	/* *** create warning pixmap *** */
	if (!(warn_pix = XCreatePixmapFromBitmapData (mydisplay, main_win.win,
		warn_bits, warn_width, warn_height, fg, bg, 
		DefaultDepth (mydisplay, DefaultScreen (mydisplay))))) 
		{
		fprintf (stderr,
			"Couldn't create Warning pixmap ... \
ignoring specified threshold.\n");
		warn_val = FALSE;
		}

	/* *** create popup pixmap *** */
	if (!(popup_pix = XCreatePixmapFromBitmapData (mydisplay, main_win.win,
		popup_bits, popup_width, popup_height, fg, bg, 
		DefaultDepth (mydisplay, DefaultScreen (mydisplay))))) 
		{
		fprintf (stderr,
                        "Couldn't create Popup pixmap ... \
ignoring Popup request.\n");
		popup = FALSE;
		}

	/* *** Map window definitions onto screen *** */
	XMapSubwindows (mydisplay, main_win.win);
	XMapRaised (mydisplay, main_win.win);

	if (popup) 
		redraw_main_win();

#ifdef DEBUG
	fprintf (stdout, "Setup is Done!\n");
#endif 

/* ************************************************************ */
/* ************** setup is done - main event loop ************* */
/* ************************************************************ */

	do_event_loop (argc, argv);

	/* *** we are done - destroy all the windows *** */
	if (detail_open != NOGOOD) 
		{
		XFreeGC (mydisplay, detail_win.gc);
		XDestroyWindow (mydisplay, detail_win.win);
		}

	destroy_menu (menu, MENU_ITEMS);
	destroy_menu (fs_win, NFS);
	XFreeGC (mydisplay, main_win.gc);
	XDestroyWindow (mydisplay, main_win.win);
	XCloseDisplay (mydisplay);
	exit (0);
}



/* *** This is the main event loop. Here we handle events and deal *** */
/* ***                 with all the user inputs we get             *** */
void do_event_loop (argc, argv)
int argc;
char **argv;
{
	XEvent	tevent;
	int	count, cont, this_item, i, ppnfs, OFS, done=FALSE; 
	long	target = time(NULL) + upd_interval;
	char	text[10];

    while (!done)	
	{
	/* *** here we wait while there are no events *** */
	/* *** and count out down our interval.       *** */
	while (XPending (mydisplay) == 0) 
		{
		struct timeval  sleept;
		fd_set reads;

		FD_ZERO(&reads);
		FD_SET(ConnectionNumber(mydisplay), &reads);
		sleept.tv_sec = target - time(NULL);
		sleept.tv_usec = 0; 
#ifdef HPUX
		select(ConnectionNumber(mydisplay) + 1, (int *) &reads, NULL, 
			NULL, &sleept);
#else
		select(ConnectionNumber(mydisplay) + 1, &reads, NULL, NULL, 
			&sleept);
#endif

		if ((time(NULL)) >= target) 
			{
			OFS = NFS;
			o_b_blocks = b_blocks;
			o_b_bsize = b_bsize;
			o_b_disk = b_disk;
			ppnfs = ((main_win.height - BEGIN_NFS(main_win)) / NFS);
			get_fs_stat ();
			/* XClearWindow (mydisplay, main_win.win); */
			main_win.height = (BEGIN_NFS(main_win) + (ppnfs * NFS));
			handle_NFS_change (ppnfs, OFS);
			if (detail_open != NOGOOD)
				write_detail (detail_open);
			target = target + upd_interval;
			}
		}

	/* *** read the next event *** */
	XNextEvent (mydisplay, &myevent);

	switch (myevent.type) 
	{
	/* *** expose event -> redraw the window *** */
	 case Expose:
	/* ********************************************* *
	 *  since a window can generate multiple expose  *
	 *  events we can collapse these into one redraw *
	 * ********************************************* */
		count=0;
		do 
			{
			if (XPending (mydisplay) == 0)
				break;
			XPeekEvent (mydisplay, &tevent);
			if (tevent.xexpose.window ==  myevent.xexpose.window) 
				{
				XNextEvent (mydisplay, &myevent);
				count++;
				}
			} 
		while(tevent.xexpose.window==myevent.xexpose.window);

#ifdef DEBUG
		if (!count)
			fprintf(stdout, "got expose event in window: %d\n",
			myevent.xexpose.window);
		else
			fprintf(stdout, 
			"Compressed %d expose events into 1 in window: %d\n",
			count, myevent.xexpose.window);
#endif 

		/* ******************************************* *
		 * ** now deal with the actual expose event ** *
		 * ******************************************* */
		if (myevent.xexpose.window == main_win.win &&
		    myevent.xexpose.count == 0) 
			{
			redraw_main_win ();
			break;
			} 
		else
		if (myevent.xexpose.window == detail_win.win)
			write_detail (detail_open);

		cont = TRUE;
		cont = expose_win (menu, MENU_ITEMS);
		if (!cont) break;
			for (i = 0; i < NFS; i++)
		if (myevent.xexpose.window == fs_win[i].win) 
			{
			redraw_fs_win (i);
			i = NFS;
			}
		break;

	/* *** change work window if main window changes *** */
	case ConfigureNotify:
#ifdef DEBUG
		fprintf(stdout, "got configure notify event in window: %d\n",
			myevent.xconfigure.window);
#endif
		/* *** we don't allow changes in the detail window *** */
		if (myevent.xconfigure.window != main_win.win)
			break;

		/* *** size stays the same -> nothing to do *** */
		if (myevent.xconfigure.width == main_win.width &&
		    myevent.xconfigure.height == main_win.height)
			break;

		/* *** figure out how many points per nfs we have *** */
		ppnfs = ((myevent.xconfigure.height - 
			BEGIN_NFS(main_win)) / NFS);
#ifdef DEBUG
	fprintf (stdout,
	       "got resize event - new interval = %d\nwidth = %d height = %d\n",
	       ppnfs, myevent.xconfigure.width, myevent.xconfigure.height);
#endif

		XClearWindow (mydisplay, main_win.win);
		main_win.width = myevent.xconfigure.width;
		main_win.height = myevent.xconfigure.height;
		XResizeWindow (mydisplay, main_win.win, main_win.width, 
			main_win.height);
		redraw_main_win ();
		fix_menu_pos (myevent.xconfigure.width);

		for (i = 0; i < NFS; i++) 
			{
			set_fs_win_size (i, ppnfs);
			XClearWindow (mydisplay, fs_win[i].win);
			XMoveResizeWindow (mydisplay, fs_win[i].win, OFF_X, 
				fs_win[i].y, fs_win[i].width, fs_win[i].height);
			/* XClearWindow (mydisplay, main_win.win); */
			if (fs_perc[i] != NOGOOD)
				redraw_fs_win (i);
			} 

		XClearWindow (mydisplay, main_win.win);
		break;

	/* *** process keyboard mapping changes *** */
	case MappingNotify:
#ifdef DEBUG
	fprintf(stdout, "got mapping notify event in window: %d\n",
		myevent.xexpose.window);
#endif

		XRefreshKeyboardMapping ((XMappingEvent *) &myevent );
		break;

      /* *** drag in work window *** */
	case MotionNotify:
#ifdef DEBUG
	fprintf(stdout, "got motion notify event in window: %d\n",
		myevent.xbutton.window);
#endif
	break;

	/* *** mouse enters a window *** */
	case EnterNotify:
		this_item = highlight_menu (menu, MENU_ITEMS, TRUE);
		break;

	/* *** Mouse Leaves a window *** */
	case LeaveNotify:
		this_item = highlight_menu (menu, MENU_ITEMS, FALSE);
		break;

	/* *** process mouse-button presses *** */
	case ButtonPress:
#ifdef DEBUG
	fprintf(stdout, "button press (%d) in window: %d\n",
		myevent.xbutton.button, myevent.xbutton.window);
#endif

	if (myevent.xbutton.button == 1 || myevent.xbutton.button == 2) 
		{
		this_item = which_button_pressed (menu, MENU_ITEMS);

		if (this_item == UPDATE) 
			{
			clear_fs_warn_flags();
			OFS = NFS;
			o_b_blocks = b_blocks;
			o_b_bsize = b_bsize;
			o_b_disk = b_disk;
			ppnfs = ((main_win.height - BEGIN_NFS(main_win)) / NFS);
			get_fs_stat ();
			main_win.height = (BEGIN_NFS(main_win) + (ppnfs * NFS));
			handle_NFS_change (ppnfs, OFS);
			if (detail_open != NOGOOD)
				write_detail (detail_open);
			redraw_main_win ();
			target = time(NULL) + upd_interval;
			break;
			} 
		else if (this_item == QUIT) 
			{
			done = TRUE;
			break;
			}

	/* *** see if btnpress was in detail window *** */
	if (myevent.xbutton.window == detail_win.win) 
		{
		XFreeGC (mydisplay, detail_win.gc);
		XDestroyWindow (mydisplay, detail_win.win);
		detail_open = NOGOOD;
		break;
		}

	/* *** see if btnpress was in a graph window *** */
		this_item = which_button_pressed (fs_win, NFS);
		if (this_item == NOGOOD)
			break;

	/* *** open a detail window *** */
	if (detail_open == NOGOOD) 
		{
		open_detail_win (argc, argv);
		detail_open = this_item;
		if (detail_share_color) 
			{
			XSetBackground (mydisplay, detail_win.gc, 
				fs_win[this_item].bg);
			XSetForeground (mydisplay, detail_win.gc, 
				fs_win[this_item].fg);
			XSetWindowBackground(mydisplay, detail_win.win, 
				fs_win[this_item].bg);
			}
		}

	/* *** det_win for this graph open - close it *** */
	else 
	if (detail_open == this_item) 
		{
		XFreeGC (mydisplay, detail_win.gc);
		XDestroyWindow (mydisplay, detail_win.win);
		detail_open = NOGOOD;
		} 
	else 
		{
		if (detail_share_color) 
			{
			XSetBackground (mydisplay, detail_win.gc, 
				fs_win[this_item].bg);
			XSetForeground (mydisplay, detail_win.gc, 
				fs_win[this_item].fg);
			XSetWindowBackground(mydisplay, detail_win.win, 
				fs_win[this_item].bg);
			}
		detail_open = this_item;
		write_detail (this_item);
		}
	}
	/* *** Button 3 pressed *** */
	else
		toggle_mode();
	break;

	/* *** process mouse-button release *** */
	case ButtonRelease:
#ifdef DEBUG
		fprintf(stdout, "button release in window: %d\n", 
			myevent.xbutton.window);
#endif
	break;

	/* *** process Resize *** */
	case ResizeRequest:
#ifdef DEBUG
		fprintf (stdout, "got resize event \n");
#endif
	break;

	/* *** process keyboard input *** */
	case KeyPress:
#ifdef DEBUG
		fprintf (stdout, "got keypress event in window: %d\n", 
			myevent.xkey.window);
#endif
		i = XLookupString ((XKeyEvent *)&myevent, text, 10, NULL, 0 );

		if (text[0] == UPDATE_KEY) 
			{
			clear_fs_warn_flags();
			OFS = NFS;
			o_b_blocks = b_blocks;
			o_b_bsize = o_b_bsize;
			o_b_disk = b_disk;
			ppnfs = ((main_win.height - BEGIN_NFS(main_win)) / NFS);
			get_fs_stat ();
			main_win.height = (BEGIN_NFS(main_win) + (ppnfs * NFS));
			handle_NFS_change (ppnfs, OFS);
			if (detail_open != NOGOOD)
				write_detail (detail_open);
			redraw_main_win ();
			target = time(NULL) + upd_interval;
			break;
			}
		else 
		if (text[0] == QUIT_KEY) 
			{
			done = TRUE;
			break;
			}
		else 
		if (text[0] == CLOSE_KEY) 
			{
			if (detail_open != NOGOOD) 
				{
				XFreeGC (mydisplay, detail_win.gc);
				XDestroyWindow (mydisplay, detail_win.win);
				detail_open = NOGOOD;
				break;
				}
			} 
		else 
		if (text[0] == TOGGLE_KEY) 
			{
			toggle_mode ();
			break;
			}
		break;
	} /* switch (myevent.type) */
    } /* while (done == 0) */
}


syntax highlighted by Code2HTML, v. 0.9.1