/* ************************************************************************* *
   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.
 * ************************************************************************* */


#include "xfsm.h"

#ifdef ULTRIX
/* *** This defines the gt_names string which means that we have to *** */
/* ***        include it here to avoid multiple definitions         *** */
#include <sys/fs_types.h>
#endif


extern Display			*mydisplay;
extern char*			myname;
extern char*			title;
extern XrmDatabase		resourceDB;
extern WinType			main_win,
				menu[MENU_ITEMS],
				fs_win[MAXFS],
				detail_win;
extern XGCValues		gray_gc_val;
extern XEvent			myevent;
extern unsigned long		fg, bg,
				warncols[];
extern XWindowAttributes  	attribs;
extern XSizeHints		mainwin_hint,
				szhint;
extern Pixmap			warn_pix,
				popup_pix;
extern int 			show_use,
				upd_interval,
				NFS,
				detail_open,
				detail_share_color,
				minimize,
				menu_border,
				show_biggest,
				fs_border,
				percent,
				absolute,
				available,
				bell,
				alwaysbeep,
				popup,
				fs_level[],
				fs_warn[],
				fs_bell[],
				verbose,
				gray,
				idx[],		/* for compatability - xfsm */
				root,		/* for compatability - xfsm */
				show_blocks;	/* for compatability - xofm */
extern double			b_blocks,
				b_bytes,
				b_disk,
				b_bsize,
				o_b_blocks,
				o_b_bsize,
				o_b_bytes,
				o_b_disk;
extern unsigned long		turns;
extern float			fs_perc[],
				res_space,
				warnvals[],
				warn_val;
extern MyString			hname; 
#ifdef XOFM
extern Stats 			stats[];
#else /* xfsm */
extern struct statfs		stats[];
extern StringInfo		strinfo[];
#endif 




/* *** variables accessed only in util.c - make them static to make sure *** */
static char 	*Menu_Text[MENU_ITEMS]={
			" Update Now ",
			"    Quit    "};

static int	percent_width,
		lname;




/* ************************************************************************ */
/* **** Here we adjust the main window if we add or loose an automount **** */
/* ****** file system. We also create or destroy any fs_win we need ******* */
/* ************************************************************************ */
void handle_NFS_change (ppnfs, OFS)
int ppnfs, OFS;
{
	int i;

	/* *** add a file system *** */
	if (NFS > OFS)
		for (i = OFS; i < NFS; i++) 
			{
			set_fs_win_size (i, ppnfs);
			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);

			XMapRaised (mydisplay, fs_win[i].win);
#ifdef DEBUG
			printf("LEVEL: clearing level info for new FS %d\n",i);
#endif
			fs_level[i] = 0;
			fs_bell[i] = 0;
			fs_warn[i] = FALSE;
			}

	/* *** remove a file system *** */
	else 
	if (NFS < OFS)
		for (i = NFS; i < OFS; i++) 
			{
			XFreeGC (mydisplay, fs_win[i].gc);
			XDestroyWindow (mydisplay, fs_win[i].win);
			fs_level[i] = 0;
			fs_bell[i] = 0;
			fs_warn[i] = FALSE;
			}

	/* *** did the number of file systems change *** */
	if (NFS != OFS) 
		{
		/* *** quick and dirty fix to force redisplaying *** */
		/* *** of bars which may otherwise be associated *** */
		/* *** with the wrong file system. On a decent   *** */
		/* *** machine this should be barley noticabel   *** */
		toggle_mode ();
		toggle_mode ();
		XResizeWindow (mydisplay, main_win.win, main_win.width, 
			main_win.height);
		mainwin_hint.min_height = ((MIN_INTERVAL(main_win) * NFS) +
			BEGIN_NFS(main_win));
		XSetNormalHints (mydisplay, main_win.win, &mainwin_hint);
		}

	/* *** check if the biggest file system changed *** */
	if (HAS_BIGGEST_CHANGED) 
		for (i = 0; i < NFS; i++) 
			{
			set_fs_win_size (i, ppnfs);
			XResizeWindow (mydisplay, fs_win[i].win, 
				fs_win[i].width, fs_win[i].height);
			XClearWindow (mydisplay, fs_win[i].win);
			redraw_fs_win (i);
			}

	redraw_main_win ();
	for (i = 0; i < NFS; i++)
		redraw_fs_win (i);
}



/* ************************************************************************ */
/* ************************ set the menu's position *********************** */
/* ************************************************************************ */
void fix_menu_pos (width)
int width;
{
	int i;

	for (i=0; i<MENU_ITEMS; i++) 
		{
		menu[i].x = ((width - SM_MENU_WIDTH(menu[i])) / 2);
		if (turns)
			XMoveWindow (mydisplay,menu[i].win,menu[i].x,menu[i].y);
		}
}



/* ************************************************************************ */
/* ******************* this sets the window's dimensions ****************** */
/* ************************************************************************ */
void set_fs_win_size (i, ppnfs)
int i, ppnfs;
{
	fs_win[i].x = OFF_X;
	fs_win[i].y = (BEGIN_NFS(fs_win[i]) + (ppnfs * i));
	fs_win[i].width = main_win.width - OFF_X * 2;
	if (turns)
		fix_fs_win_width (i);
 	fs_win[i].height = ppnfs - LETTER_SPACE(fs_win[i]);

#ifdef DEBUG
  printf ("%d %d %d %d\n", fs_win[i].x, fs_win[i].y, fs_win[i].width,
	  fs_win[i].height);
#endif
}



/* *********************************************************************** */
/* ********* toggle the display mode and update the windows ************** */
/* *********************************************************************** */
void toggle_mode ()
{
	int i;

	if (absolute)
		absolute=FALSE;
	else
		absolute=TRUE;
	for (i=0; i<NFS; i++)
		{
		fs_win[i].width=main_win.width-OFF_X*2;
		if (!absolute)
			fix_fs_win_width (i);
		XResizeWindow (mydisplay,fs_win[i].win, fs_win[i].width,
			fs_win[i].height);
		redraw_fs_win (i);
		}

}



/* *********************************************************************** */
/* *********************** redraw the main window ************************ */
/* *********************************************************************** */
void redraw_main_win ()
{
	int 		i, should_bell = FALSE, posx, posy;
	int		should_raise=FALSE;
	int 		text_width = main_win.width-(OFF_X+OFF_X+
				percent_width*(percent|available));
	char		s[10];
	unsigned long	color;

	if (show_biggest)
		{
		if (b_disk > GB)
			sprintf (s, "%.1fGB ", b_disk/GB);
		else
			sprintf (s, "%.1fMB ", b_disk/MB);
		posx = main_win.width-XTextWidth(main_win.font_info, 
			s, strlen (s));
		posy = main_win.height-MENU_HEIGHT(menu[0]);
		XDrawImageString (mydisplay, main_win.win, main_win.gc,
			posx, posy, s, strlen (s));
		}
	for (i = 0; i < NFS; i++) 
		{
		if (minimize == MNL)
			XDrawImageString (mydisplay, main_win.win, main_win.gc, 
				OFF_X+2, fs_win[i].y-2, FsName,
				strlen(FsName));
		else 
			{
			int n = strlen(FsName);

			/* *** find how much of the name we can write *** */
			while (XTextWidth(main_win.font_info, FsName, n) > 
				text_width)
					n--; 
			XDrawImageString (mydisplay, main_win.win, 
				main_win.gc, OFF_X + 2,
				fs_win[i].y - 2, FsName, n);
			}

		/* *** handle the exclamation mark after the FS name *** */
		if (warn_val > 0) 
			{
			if (fs_perc[i] >= warn_val)
				{
				if (bell && !fs_bell[i])
					{
					should_bell=TRUE;
					if (!alwaysbeep)
						fs_bell[i] = 1;
					}
				XCopyArea (mydisplay, warn_pix, main_win.win, 
					main_win.gc, 0, 0, warn_width, 
					warn_height, 
					(main_win.width-OFF_X)+2,
		   			fs_win[i].y-LETTER_HEIGHT(main_win));
				}
			else
				{
#ifdef DEBUG
				printf("LEVEL: clearing Warning Area %d - Warn_Val > 0\n",i);
#endif
				fs_bell[i] = 0;
				XClearArea (mydisplay, main_win.win, 
					(main_win.width - OFF_X) + 2, 
					fs_win[i].y - LETTER_HEIGHT(main_win), 
					warn_width, warn_height, FALSE);
				}
			}

		/* ** handle the color warning levels *** */
		/*
		 * EHR begin patch -- 1) warncols[0] as default color for bars 
		 *  		      2) enable popup when level changes 
		 *		      3) change to table rep of warn levels &
		 *			 bar colors
		 *		      4) change to have status set up in
		 *			 get_fs_stat. This section just
		 *			 sets up the screen as necessary.
		 */

		/*
		 * Get Appropriate color.  Note that fs_level is set in
		 * the get_fs_stat routine.
		 */
		color=warncols[fs_level[i]];
#ifdef DEBUG
		printf("LEVEL: color set to %d\n", color);
#endif

		/* 
		 * Set up the warning/popup.  Note that fs_warn is set in
		 * the get_fs_stat routine.
		 */
		if (popup && fs_warn[i]) 
			{
#ifdef DEBUG
			printf("LEVEL: popup processed for fs %d\n",i);
#endif
			if (bell && !fs_bell[i]) 
				{
				should_bell = TRUE;
				if (!alwaysbeep)
					fs_bell[i] = 1;
				}
			should_raise = TRUE;
			XCopyArea (mydisplay, popup_pix, main_win.win, 
				main_win.gc, 0, 0, popup_width, 
				popup_height, (main_win.width-OFF_X)+2,
		   		fs_win[i].y-LETTER_HEIGHT(main_win));
			} 
		else 
		if (warn_val <= 0)
			{
			fs_bell[i] = 0;
#ifdef DEBUG
			printf("LEVEL: clearing popup warning area %d\n",i);
#endif
			XClearArea (mydisplay, main_win.win, 
				(main_win.width - OFF_X) + 2, 
				fs_win[i].y - LETTER_HEIGHT(main_win), 
				popup_width, popup_height, FALSE);
			}

		XSetForeground (mydisplay, fs_win[i].gc, color);

		if (percent)
			write_percent (i);
		if (available)
			write_available (i);
		}

	/* *** make sure window is raised when should_raise==TRUE *** */
	if (should_raise) 
		{
		XWMHints wmhints;
		wmhints.initial_state = NormalState;
		wmhints.flags = StateHint;
		XSetWMHints(mydisplay, main_win.win, &wmhints);
		XMapRaised(mydisplay, main_win.win);
		}

	if (should_bell)
		XBell (mydisplay, 0);
} 



/* *********************************************************************** */
/* *************************** redraw the bars *************************** */
/* *********************************************************************** */
void redraw_fs_win(i)
int i;
{
	/* *** now draw bar *** */
	/* XClearWindow (mydisplay, fs_win[i].win); */
	XFillRectangle (mydisplay, fs_win[i].win, fs_win[i].gc, 0, 0,
		(int)(fs_perc[i]*fs_win[i].width), fs_win[i].height);
	XClearArea(mydisplay, fs_win[i].win,
		(int)(fs_perc[i] * fs_win[i].width), 0, 0, 0, False);
}



/* *********************************************************************** */
/* ************************* write available space *********************** */
/* *********************************************************************** */
void write_available(i)
int i;
{
	char	s[30];
	long	bsize=stats[i].f_bsize;

	sprintf (s, "%5.2f", 
#ifdef SCO
		((double)(bsize)/(float)(MB))*(double)(stats[i].f_bfree));
#else
		((double)(bsize)/(float)(MB))*(double)(stats[i].f_bavail));
#endif /* SCO */
	XDrawImageString (mydisplay, main_win.win, main_win.gc, 
		(main_win.width - OFF_Y -
		XTextWidth(main_win.font_info, s, strlen(s))),
 		fs_win[i].y - 2, s, strlen (s));
}



/* *********************************************************************** */
/* ************************* write the percentage ************************ */
/* *********************************************************************** */
void write_percent(i)
int i;
{
	char 	s[30];

	if (fs_perc[i] < 0 )
		strcpy (s, "N.A.");
	else 
		sprintf (s, "%3d%%", (int)(fs_perc[i]*100 + 0.5));
	XDrawImageString (mydisplay, main_win.win, main_win.gc, 
		(main_win.width - OFF_Y -
		XTextWidth(main_win.font_info, s, strlen(s))),
 		fs_win[i].y - 2, s, strlen (s));
}



/* *********************************************************************** */
/* ************************* write the percentage ************************ */
/* *********************************************************************** */
void open_detail_win (argc, argv)
int	argc;
char 	**argv;
{
	XSizeHints szhint;
	XClassHint clshint;
	XWMHints wmhints;
	  
	szhint.min_width  = DETAIL_X;
	szhint.min_height = DETAIL_Y;
	szhint.max_width  = szhint.min_width;
	szhint.max_height = szhint.min_height;
	szhint.x = detail_win.x;
	szhint.y = detail_win.y;
	szhint.width = detail_win.width;
	szhint.height = detail_win.height;
	szhint.flags = detail_win.flags | PMinSize | PMaxSize | PSize;

	clshint.res_name  = "detailWin";
	clshint.res_class = CLASS_NAME;

	wmhints.input = True;
	wmhints.initial_state = NormalState;
	wmhints.window_group = main_win.win;
	wmhints.flags = InputHint | StateHint | WindowGroupHint;

	create_window(DefaultRootWindow(mydisplay), &detail_win,
		getColorResource(resourceDB,
		catlist(myname, ".detailWin.foreground",
		(char*) NULL), "Xofm.DetailWin.Foreground", fg),
		getColorResource(resourceDB, catlist(myname,
			".detailWin.background", (char*) NULL),
			"Xofm.DetailWin.Background", bg));

	/* *** set up the properties for the window. *** */
	XSetStandardProperties (mydisplay, detail_win.win, 
		detail_win.text, detail_win.text, None, argv, argc, 
		&szhint);
	XSetClassHint(mydisplay, detail_win.win, &clshint);
	XSetWMHints(mydisplay, detail_win.win, &wmhints);

	XMapRaised (mydisplay, detail_win.win);
}



/* *********************************************************************** */
/* *********************** create a single window ************************ */
/* *********************************************************************** */
void create_window (parent_win, this_win, foreg, backg)
Window	parent_win; 
WinTypePtr this_win;
unsigned long foreg, backg;
{
	/* *** Create Actual Window *** */
	this_win->win = XCreateSimpleWindow (mydisplay, parent_win, this_win->x,
		this_win->y, this_win->width, this_win->height, 
		this_win->line_thick, foreg, backg);

	if (!this_win->win) 
		{
		fprintf (stderr,
			"Error creating Simple Window %s ... Exiting.\n",
			this_win->text);
		exit (1);
		}

#ifdef DEBUG
	fprintf (stdout, "Created Simple Window %s (%d) %d %d %d %d\n", 
		this_win->text, this_win->win, this_win->x, this_win->y,
		this_win->width, this_win->height, this_win->line_thick);
#endif

	/* *** set Graphics Content creation and initialize *** */
	this_win->gc = XCreateGC (mydisplay, this_win->win, 0, 0);

	if (! this_win->gc) 
		{
		fprintf (stderr, "Error creating GC for  %s ... Exiting.\n",
			this_win->text);
		exit (1);
		}

#ifdef DEBUG
	fprintf (stdout, "Created GC %d\n", this_win->gc);
#endif

	XSetBackground (mydisplay, this_win->gc, backg);
	XSetForeground (mydisplay, this_win->gc, foreg);

	if (this_win->font_info != 0)
		XSetFont(mydisplay, this_win->gc, this_win->font_info->fid);

	this_win->fg = foreg;
	this_win->bg = backg;

	/* *** specify which input we want this window to process *** */
	XSelectInput (mydisplay, this_win->win, this_win->event_mask);
}




/* *********************************************************************** */
/* highlight menu item (window) in response to a mouse entering or leaving */
/* *********************************************************************** */
int highlight_menu (menu, menu_num,highlight)
WinType menu[];
int	menu_num;
int	highlight;
{
	int i, state=NOGOOD;

	/* *** figure out which menu *** */
	for (i = 0; i < menu_num; i++) 
		if (myevent.xcrossing.window == menu[i].win) 
			{
			state = i;
			i = menu_num;
			}

	/* *** check if menu is valid and change fg & bg *** */
	if (state >= 0 && state < menu_num) 
		{
		if (highlight) 
			{
#ifdef DEBUG
			fprintf(stdout, "Enter state in button %s\n", 
				menu[state].text);
#endif
		XSetBackground (mydisplay, menu[state].gc, fg);
		XSetForeground (mydisplay, menu[state].gc, bg);
			} 
		else 
			{
#ifdef DEBUG
			fprintf (stdout, "Exit state in button %s\n", 
				menu[state].text);
#endif
			XSetBackground (mydisplay, menu[state].gc, bg);
			XSetForeground (mydisplay, menu[state].gc, fg);
			}

		for (i = 0; i < menu_num; ++i)
			XDrawImageString (mydisplay, menu[i].win, menu[i].gc, 1,
			LETTER_ASCENT(menu[i]), menu[i].text, 
			strlen(menu[i].text)); 
		return (state);
	} 
	else
		return (NOGOOD);
}

/* *********************************************************************** */
/* ************** redraw the string in an exposed window ***************** */
/* *********************************************************************** */
int expose_win (menu, menu_num)
WinType	menu[];
int	menu_num;
{
	int i;

	for (i = 0; i < menu_num; i++) 
		{
		if (myevent.xexpose.window == menu[i].win) 
			{
			XDrawImageString (mydisplay, menu[i].win, menu[i].gc, 1,
				LETTER_ASCENT(menu[i]), menu[i].text,
				strlen(menu[i].text));
			return (FALSE);
			}
		}

	return (TRUE);
}




/* *********************************************************************** */
/* *********************** destroy an entire menu  *********************** */
/* *********************************************************************** */
void destroy_menu (menu, menu_num)
WinType	menu[];
int	menu_num;
{
	int i;

	for (i=0; i<menu_num; i++)
		{
		XDestroyWindow (mydisplay, menu[i].win);
#ifdef DEBUG
		fprintf (stdout, "Destroyed menu: %s\n", menu[i].text);
#endif
		XFreeGC (mydisplay, menu[i].gc);
#ifdef DEBUG
		fprintf (stdout, "Destroyed GC: %d\n", menu[i].gc);
#endif
		}
}




/* *********************************************************************** */
/* *************** return the number of the button pressed *************** */
/* *********************************************************************** */
int which_button_pressed (menu, menu_num)
WinType	menu[];
int	menu_num;
{
	int i;

	for (i=0; i<menu_num; i++)
		if (myevent.xbutton.window == menu[i].win)
			return (i);
	return (NOGOOD);
}



/* ***************************************************************** */
/* ********** this basically inits the window definitions ********** */
/* ***************************************************************** */
void init_all_windows ()
{
	int i, x, y, flags, geom_used=FALSE, ppnfs;
	unsigned long small_event_mask, big_event_mask, fs_mask;
	unsigned int width, height;
#ifdef XOFM
	static char* bytes_or_blocks [] = {"bytes", "blocks"};
#else
	static char* userroot[] = {"user", "root"};
#endif
	static char* freeused[] = {"free", "used"};
	unsigned int border_width =
		getIntResource(resourceDB, catlist(myname, ".borderWidth", 
			(char*) NULL), "Xfsm.BorderWidth", DEF_BORDER_WIDTH);
	XFontStruct* def_font = XLoadQueryFont(mydisplay, DEFAULT_FONT);
	XrmString str_type;
	XrmValue value;
	small_event_mask = ButtonPressMask | StructureNotifyMask | 
		ExposureMask| KeyPressMask | EnterWindowMask | LeaveWindowMask;
	big_event_mask = ButtonPressMask | ExposureMask | EnterWindowMask |
		LeaveWindowMask;
	fs_mask = ButtonPressMask | ExposureMask;

	if (def_font == NULL) 
		{
		fprintf(stderr, "Could not load default font \"%s\".\n", 
			DEFAULT_FONT);
		exit(1);
		}

#ifdef XOFM
	sprintf (main_win.text, "%s %s %s", hname, 
		bytes_or_blocks [show_blocks!=0], freeused[show_use != 0]);
#else /* xfsm */
	if (title != NULL)
		sprintf (main_win.text, "%s %s %s", title, userroot[root != 0],
               		freeused[show_use != 0]);
	else
		sprintf (main_win.text, "%s %s %s", hname, userroot[root != 0],
			freeused[show_use != 0]);

#endif 

	main_win.x = WIN_X;
	main_win.y = WIN_Y;
	main_win.font_info = getFontResource (resourceDB, 
		catlist(myname, ".mainWin.font", (char*) NULL),
		"Xfsm.MainWin.Font", def_font);
	if (minimize)	
		{
		if (minimize == MNL)
			{
			main_win.width = OFF_X + OFF_X + lname + percent_width;
			if (main_win.width < MIN_WIN_X)
				main_win.width = MIN_WIN_X;
			}
		else
			main_win.width = MIN_WIN_X;
		main_win.height = ((MIN_INTERVAL(main_win) * NFS) + 
			BEGIN_NFS(main_win));
		} 
	else 
		{
		main_win.width = WIN_X;
		main_win.height = ((INTERVAL(main_win) * NFS) + 
			BEGIN_NFS(main_win));
		}
	main_win.line_thick = border_width;
	main_win.event_mask = small_event_mask;
	main_win.flags = PPosition;

	if (XrmGetResource(resourceDB, catlist(myname, ".mainWin.geometry", 
		(char*) NULL), "Xfsm.MainWin.Geometry", &str_type, &value)) 
		{
		flags = XParseGeometry(value.addr, &x, &y, &width, &height);
		if (XValue & flags) 
			{
			if (XNegative & flags)
			   x = DisplayWidth(mydisplay, 
				DefaultScreen(mydisplay)) + x -
				main_win.width - 2 * main_win.line_thick;
			main_win.x = x;
			main_win.flags = USPosition;
			}

		if (YValue & flags) 
			{
			if (YNegative & flags)
			   y = DisplayHeight(mydisplay, 
				DefaultScreen(mydisplay)) + y -
				main_win.height - 2 * main_win.line_thick;
			main_win.y = y;
			main_win.flags = USPosition;
			}
		if (WidthValue & flags)
			{
			if (width < MIN_WIN_X)
				{
				width = MIN_WIN_X;
				if (verbose)
					fprintf (stderr, "Specified width too \
small ... adjusting to minimum size\n");
				}
			else
			if (width > 
			    DisplayWidth(mydisplay, DefaultScreen(mydisplay)))
				{
				width = DisplayWidth(mydisplay, 
					DefaultScreen(mydisplay))-1;
				if (verbose)
					fprintf (stderr, "Specified width too \
large ... adjusting to maximum size\n");
				}
			main_win.width = width;
			main_win.flags = USPosition;
			geom_used=TRUE;
			}
		if (HeightValue & flags)
			{
			if (height < 
			    ((MIN_INTERVAL(main_win)*NFS)+BEGIN_NFS(main_win)))
				{
				height = ((MIN_INTERVAL(main_win)*NFS)+
					BEGIN_NFS(main_win));
				if (verbose)
					fprintf (stderr, "Specified height too \
small ... adjusting to minimum size\n");
				}
			else
			if (height > 
			    DisplayHeight(mydisplay, DefaultScreen(mydisplay)))
				{
				height = DisplayHeight(mydisplay,
					DefaultScreen(mydisplay))-1;
				if (verbose)
					fprintf (stderr, "Specified height too \
large ... adjusting to maximum size\n");
				}
			main_win.height = height;
			main_win.flags = USPosition;
			geom_used=TRUE;
			}
		}

	for (i = 0; i < MENU_ITEMS; i++) 
		{
		strcpy(menu[i].text, Menu_Text[i]);
		menu[i].font_info = main_win.font_info;
		menu[i].width = SM_MENU_WIDTH(menu[i]);
		menu[i].height = MENU_HEIGHT(menu[i]);
		menu[i].x = ((main_win.width - menu[i].width) / 2);
		menu[i].y = MENU_Y + MENU_HEIGHT(menu[i]) * i;
		if (menu_border)
			menu[i].line_thick = 1;
		else
			menu[i].line_thick = 0;
		menu[i].event_mask = big_event_mask;
		}

	for (i = 0; i < MAXFS; i++) 
		{
		fs_win[i].font_info = main_win.font_info;
		fs_win[i].line_thick = fs_border;
		fs_win[i].event_mask = fs_mask;
		}

	for (i = 0; i < NFS; i++) 
		{
		fs_win[i].x = OFF_X;
		if (geom_used)
			{
			ppnfs = ((main_win.height-BEGIN_NFS(main_win)) / NFS);
			set_fs_win_size (i, ppnfs);
			}
		else
		if (minimize) 
			{
			fs_win[i].y = ((MIN_INTERVAL(fs_win[i]) * i) + 
				BEGIN_NFS(fs_win[i]));
			fs_win[i].height = MIN_MENU_HEIGHT;
			} 
		else 
			{
			fs_win[i].y = ((INTERVAL(fs_win[i]) * i) + 
				BEGIN_NFS(fs_win[i]));
			fs_win[i].height = MENU_HEIGHT(fs_win[i]);
			}
		fs_win[i].width = main_win.width - OFF_X * 2; 
		}
	sprintf (detail_win.text, "%s detail", hname);
	detail_win.x = OFF_X;
	detail_win.y = OFF_Y;
	detail_win.font_info = getFontResource(resourceDB, 
		catlist(myname, ".detailWin.font", (char*) NULL),
		"Xfsm.DetailWin.Font", def_font);
	detail_win.width = DETAIL_X;
	detail_win.height = DETAIL_Y;
	detail_win.line_thick = border_width;
	detail_win.event_mask = small_event_mask;
	detail_win.flags = PPosition;
	if (XrmGetResource(resourceDB,
		catlist(myname, ".detailWin.geometry", (char*) NULL),
		"Xfsm.DetailWin.Geometry", &str_type, &value)) 
		{
		flags = XParseGeometry(value.addr, &x, &y, &width, &height);
		if (XValue & flags) 
			{
 			if (XNegative & flags)
			   x  = DisplayWidth(mydisplay, 
				DefaultScreen(mydisplay)) + x -
				detail_win.width - 2 * detail_win.line_thick;
			detail_win.x = x;
			detail_win.flags = USPosition;
			}
		if (YValue & flags) 
			{
			if (YNegative & flags)
			   y = DisplayHeight(mydisplay, 
				DefaultScreen(mydisplay)) + y -
				detail_win.height - 2 * detail_win.line_thick;
			detail_win.y = y;
			detail_win.flags = USPosition;
			}
		}

	/* *** 4 spaces (3 digits + 1 %) + 1 space *** */
	percent_width = XTextWidth(main_win.font_info, "9999%", 5);
}



/* ***************************************************************** */
/* ********** Returns the value of the given bool resource ********** */
/* ***************************************************************** */
Bool getBoolResource(db, str_name, str_class, deflt)
XrmDatabase db;
char* str_name;
char* str_class;
Bool deflt;
{
	XrmString str_type;
	XrmValue value;

	if (XrmGetResource(db, str_name, str_class, &str_type, &value)) 
		{
		return ((!strcmp(value.addr, "true")) || 
			(!strcmp(value.addr, "True")) ||
			(!strcmp(value.addr, "TRUE")) ||
			(!strcmp(value.addr, "yes")) ||
			(!strcmp(value.addr, "Yes")) ||
			(!strcmp(value.addr, "YES")) ||
			(!strcmp(value.addr, "on")) || 
			(!strcmp(value.addr, "On")) || 
			(!strcmp(value.addr, "ON")) || 
			(!strcmp(value.addr, "1")));
		} 
	else
		return (deflt);
}



/* ***************************************************************** */
/* ********** Returns the value of the given int resource ********** */
/* ***************************************************************** */
int getIntResource(db, str_name, str_class, deflt)
XrmDatabase db;
char* str_name;
char* str_class;
int deflt;
{
	XrmString str_type;
	XrmValue value;

	if (XrmGetResource(db, str_name, str_class, &str_type, &value))
		return (atoi(value.addr));
	else
		return (deflt);
}



/* ***************************************************************** */
/* ********** Returns the value of the given Font resource ********* */
/* ***************************************************************** */
XFontStruct* getFontResource(db, str_name, str_class, deflt)
XrmDatabase db;
char* str_name;
char* str_class;
XFontStruct* deflt;
{
	XrmString str_type;
	XrmValue value;

	if (XrmGetResource(db, str_name, str_class, &str_type, &value)) 
		{
		XFontStruct* font = XLoadQueryFont(mydisplay, value.addr);
		if (font == NULL) 
			{
			fprintf(stderr, 
				"Could not load font \"%s\".\n", value.addr);
			return (deflt);
			} 
		else
			return (font);
  		} 
	else
		return (deflt);
}



/* ***************************************************************** */
/* ********** Returns the value of the given color resource ******** */
/* ***************************************************************** */
unsigned long getColorResource(db, str_name, str_class, deflt)
XrmDatabase db;
char* str_name;
char* str_class;
unsigned long deflt;
{
	XrmString str_type;
	XrmValue value;

	if (XrmGetResource(db, str_name, str_class, &str_type, &value)) 
		{
		XColor screen_def;
		if (XParseColor(mydisplay, DefaultColormapOfScreen
			(DefaultScreenOfDisplay(mydisplay)), value.addr, 
			&screen_def) == 0 
		    ||
		    XAllocColor(mydisplay, DefaultColormapOfScreen
			(DefaultScreenOfDisplay(mydisplay)), &screen_def) == 0)
			{
			fprintf(stderr, 
			   "Color specification \"%s\" invalid.\n", value.addr);
			return (deflt);
			} 
		else
 			return (screen_def.pixel);
		} 
	else
		return (deflt);
}



/* ***************************************************************** */
/* ********** Returns the concatenation of the NULL       ********** */
/* ********** terminated list of strings.		  ********** */
/* ***************************************************************** */
#ifdef __STDC__
#if NeedFunctionPrototypes
char* catlist(char *str1, ...)
#else
char* catlist(str1)
char* str1;
#endif /* NeedFunctionPrototypes */
{
	static char blocks[2][64];
	static int current = 0;
	va_list ap;
	char* c;

	strcpy(blocks[current], str1);
	va_start(ap, str1);
	while ((c = va_arg(ap, char*)) != NULL)
		strcat(blocks[current], c);
	va_end(ap);
	c = blocks[current];
	current = (current + 1) % 2;
	return c;
}
#else
char* catlist(va_alist)
va_dcl
{
	static char blocks[2][64];
	static int current = 0;
	va_list ap;
	char* c;

	va_start(ap);
	blocks[current][0] = '\0';
	while ((c = va_arg(ap, char*)) != NULL)
		strcat(blocks[current], c);
	va_end(ap);
	c = blocks[current];
	current = (current + 1) % 2;
	return c;
}
#endif /* __STDC__ */


#if defined (DYNIX) || defined (MACH)
/* *** for some reason DYNIX does not have strstr *** */
/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. */
/* This file is part of the GNU C Library.                 */
/* Return the first ocurrence of NEEDLE in HAYSTACK.       */
#ifdef __STDC__
char *strstr (const char* haystack, const char* needle)
#else
char *strstr (haystack, needle)
char *haystack, *needle;
#endif
{
	char 	*needle_end = strchr(needle, '\0');
	char 	*haystack_end = strchr(haystack, '\0');
	size_t needle_len = needle_end - needle;
	size_t needle_last = needle_len - 1;
	char 	*begin;

	if (needle_len == 0)
 		return (char *) haystack_end;
	if ((size_t) (haystack_end - haystack) < needle_len)
		return NULL;

	for (begin = &haystack[needle_last]; begin < haystack_end; ++begin)
		{
 		char *n = &needle[needle_last];
		char *h = begin;

		do
		if (*h != *n)
			goto loop;		/* continue for loop */
		while (--n >= needle && --h >= haystack);

		return (char *) h;

		loop:;
    		}

	return NULL;
}
#endif /* DYNIX || MACH */


/*  This routine clears the fs_warn[] flags for all of the currently active
 *  file systems.  This is done in a separate routine so that popup warnings
 *  stay active until the "Update Now" button is pressed.  Otherwise, every
 *  update pass (default is 1 per minute) will clear the popup warning field.
 *  When that happens, you can't tell what caused the popup if you've left it
 *  on overnight!!  So, we now only clear the popup warning field when pressing
 *  the "Update Now" button.
 */

void clear_fs_warn_flags()
{
	int i;

	for (i=0; i<NFS; i++) 
		{
		fs_warn[i] = FALSE;
		fs_bell[i] = 0;
		}
}



syntax highlighted by Code2HTML, v. 0.9.1