/****** Watcher *************************************************************
*
*   NAME
*       Watcher -- Memory & disk watch utility (V37)
*
*   PURPOSE
*       A universal watch program that can do everything, ie. watch memory,
*       date, time, free disk space. The System List Browser is implemented as
*       an additional utility. It can display all system lists available
*       through ExecBase. Commodity, Locale, DataType support etc. etc.
*
*   NOTES
*
*   AUTHOR
*       Franz Hemmer
*
*   SEE ALSO
*
*****************************************************************************
*     __
*  __///
*  \XX/ й1993 by Hemsoft Developments
*
*----------------------------------------------------------------------------
*
* Author:		Franz Hemmer
* Written:		30.08.92
* System Req.:	KS 2.04 or higher.
* Notes:
*
*/

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                           I N C L U D E S										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
#include <exec/types.h>								// For UBYTE etc.
#include <exec/execbase.h>							// For calculating CPU consumption.
#include <exec/memory.h>							// For memory allocations.
#include <clib/alib_protos.h>						// Protos for CreateExtIO() etc.
#include <clib/amigaguide_protos.h>				// Protos for OpenAmigaGuideA() etc.
#include <clib/commodities_protos.h>			// For CxBroker() etc.
#include <clib/diskfont_protos.h>				// protos for AvailFonts() etc.
#include <clib/dos_protos.h>						// Protos for Lock() etc.
#include <clib/exec_protos.h>						// Protos for FindTask() etc.
#include <clib/gadtools_protos.h>				// Protos for LayoutMenus() etc.
#include <clib/graphics_protos.h>				// Protos for SetRast() etc.
#include <clib/icon_protos.h>						// Protos for GetDiskObject() etc.
#include <clib/intuition_protos.h>				// Protos for CloseScreen() etc.
#include <clib/locale_protos.h>					// Protos for GetCatalogStr() etc.
#include <clib/utility_protos.h>					// Protos for Stricmp() etc.
#include <clib/wb_protos.h>						// Protos for AddAppIconA() etc.
#include <ctype.h>									// For isalnum() etc.
#include <devices/timer.h>							// For the timer.device.
#include <diskfont/diskfont.h>					// For struct AvailFontsHeader etc.
#include <dos/dos.h>									// #define's for RETURN_FAIL etc.
#include <intuition/gadgetclass.h>				// For the GA_TopBorder defines etc.
#include <intuition/imageclass.h>				// For the IA_Height defines etc.
#include <intuition/screens.h>					// For struct PubScreenNode etc.
#include <libraries/amigaguide.h>				// Structures and defines for amigaguide.
#include <libraries/gadtools.h>					// For struct NewGadget.
#include <libraries/locale.h>						// For OC_BuiltinLanguage tag etc.
#include <pragmas/amigaguide_pragmas.h>		// Pragmas for amigaguide.librar.
#include <pragmas/commodities_pragmas.h>		// Pragmas for commodities.library.
#include <pragmas/diskfont_pragmas.h>			// Pragmas for diskfont.library.
#include <pragmas/dos_pragmas.h>					// Pragmas for dos.library.
#include <pragmas/exec_pragmas.h>				// Pragmas for exec.library.
#include <pragmas/gadtools_pragmas.h>			// Pragmas for gadtools.library.
#include <pragmas/graphics_pragmas.h>			// Pragmas for graphics.library.
#include <pragmas/icon_pragmas.h>				// Pragmas for icon.library.
#include <pragmas/intuition_pragmas.h>			// Pragmas for intuition.library.
#include <pragmas/locale_pragmas.h>				// Pragmas for locale.library.
#include <pragmas/utility_pragmas.h>			// Pragmas for utility.library.
#include <pragmas/wb_pragmas.h>					// Pragmas for workbench.library.
#include <rexx/rxslib.h>							// ARexx library structure - RxsLib.
#include <rexx/storage.h>							// ARexx data structures.
#include <rexx/simplerexx.h>						// Simple ARexx interface by Mike Sinz.
#include <stdio.h>									// For BUFSIZ.
#include <stdlib.h>									// Proto type for exit().
#include <string.h>									// Proto for strcat() etc.
#include <workbench/startup.h>					// For struct WBArg etc.

#include "Watcher.h"									// Revision header.
UBYTE *VersionTag = VERSTAG;						// Version tag.

#include "/include/Catalog.h"						// V37 compatible locale.
#include "/include/Nodes.h"						// My node definitions.
#include "/include/Defines.h"						// Watcher defines.
#include "/include/Prefs.h"						// WPrefs structure etc.
#include "/include/AppImage.h"					// App Info imagery.
#define CATCOMP_ARRAY
#include "/include/Watcher_strings.h"			// All strings used in Watcher.

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                            G L O B A L S										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*------------*/
/* Libraries: */
/*------------*/
BOOL								V39 = FALSE;				// Checks for V39.
extern struct ExecBase		*SysBase;					// supplied by startup module.
extern struct DosLibrary	*DOSBase;					// do.
struct Library					*AmigaGuideBase= NULL;	// amigaguide.library.
struct Library					*AslBase			= NULL;	// asl.library.
struct Library					*CxBase			= NULL;	// commodities.library.
struct Library					*DataTypesBase	= NULL;	// datatypes.library.
struct Library					*DiskfontBase	= NULL;	// diskfont.library.
struct Library					*GadToolsBase	= NULL;	// gadtools.library.
struct Library					*GfxBase			= NULL;	// graphics.library.
struct Library					*IconBase		= NULL;	// icon.library.
struct Library					*IFFParseBase	= NULL;	// iffparse.library.
struct IntuitionBase			*IntuitionBase = NULL;	// intuition.library.
struct Library					*LocaleBase		= NULL;	// locale.library.
struct Library					*UtilityBase	= NULL;	// utility.library.
struct Library					*WorkbenchBase	= NULL;	// workbench.library.

/*--------------*/
/* Preferences: */
/*--------------*/
struct WPrefs					*WPrefs			= NULL;	// Watcher preferences.

/*---------*/
/* Memory: */
/*---------*/
APTR								mem_pool			= NULL;	// Watcher's memory pool.
BOOL								mem_pool_ok		= FALSE;	// Can we use puddles ? :-)

/*----------*/
/* Parsing: */
/*----------*/
BOOL								VolAlertOk [20];			// Volume alert handler.
LONG								VolFreeSpace [20];		// Volume free space buffer.
UWORD								VolSizeChanged [20];		// Volume changed switch buffer.
LONG								VolCount = 0;				// For indexing in Volxxx arrays.

/*------*/
/* GUI: */
/*------*/
ULONG								idcmpSignals;				// idcmpSignals for Win.
																	// Hardcoded font for SLB. (so far).
struct TextAttr				topaz8 = { (STRPTR) "topaz.font", 8, 0x00, 0x01 };
struct Screen					*PubScr			= NULL;	// Public screen.
struct Screen					*NextPubScr		= NULL;	// Next public screen.
UBYTE								PubScrBuf [MAXPUBSCREENNAME + 1];
struct DrawInfo				*drinfo			= NULL;	// Needed by NewObject().
struct Window					*Win				= NULL;	// Watcher window.
struct Window					*SLBWin			= NULL;	// System List Browser window.
struct Process					*p					= NULL;	// Returned by FindTask().
struct Window					*WindowPtr		= NULL;	// Our cli window.
struct VisualInfo				*VisualInfo		= NULL;	// For menu.
struct Menu						*Menus			= NULL;	// do.
struct Menu						*SLBMenus		= NULL;	// Menu for SLB.
struct Gadget					*GList			= NULL;	// List of gadgets.
struct Gadget					*SLBGList		= NULL;	// List of gadgets.
struct Gadget					*SLBGads [GADMAX];		// Gadget pointer array.
struct Gadget					*tmpgad			= NULL;	// Temporary gadget.
struct Gadget					*JumpScrGad		= NULL;	// JumpScr gadget !!
struct Image					*jumpimage		= NULL;	// Obtained by NewObject().
BOOL								KeepWinPos		= FALSE;	// This field determines whether
																	// AllocateWindow() should use the
																	// current position or the prefs
																	// values to position the window.
WORD								KeepWinLeft, KeepWinTop;// For remembering the window
																	// position when jumping screens.

#define V(x)	((void *)(x))								// We put some information in the

/*------------------*/
/* AmigaGuide help. */
/*------------------*/
AMIGAGUIDECONTEXT				ag_AmigaGuide;		// Pointer to AmigaGuide context.
struct NewAmigaGuide			ag_NAG;				// Used to start AmigaGuide.
BOOL								ag_Available;

STRPTR AGContext [] =								// Context ID's.
{
	"MAIN",												// These items must match the
	"ABOUT",												// way the menu items are build.
	"INFORMATION",										// do
	"QUIT",												// do
	"SLB",												// do
	"APPINFO",											// do
	NULL
};

/*--------------*/
/* ARexx stuff. */
/*--------------*/
AREXXCONTEXT					RexxStuff;
BOOL								RexxAvailable = TRUE;

/*-----------*/
/* App Info: */
/*-----------*/
BOOL								AppInfoActive	= FALSE;
struct AppIcon					*ai				= NULL;
struct AppMessage				*amsg				= NULL;
struct DiskObject				*dobj				= NULL;
struct MsgPort					*amp				= NULL;
UBYTE								*VersionBuf		= NULL;	// [160];

/*--------------*/
/* Asl related: */
/*--------------*/
UBYTE								*Asldir			= NULL;	//	[128];
UBYTE								*Aslfile			= NULL;	// [128];
UBYTE								*DisplayBuf		= NULL;	// [512];
UBYTE								*ResultDir		= NULL;	// [128];
UBYTE								*ResultFile		= NULL;	// [128];
UBYTE								*ResultPath		= NULL;	// [256];

/*-------------*/
/* Cx related: */
/*-------------*/
struct MsgPort					*CxMsgPort		= NULL;	// Message port for Cx.
CxObj								*CxMyBroker		= NULL;	// Our broker!
CxObj								*CxFilterObj	= NULL;	// Filter object.
CxObj								*CxSenderObj	= NULL;	// Sender object.
CxObj								*CxTranslateObj= NULL;	// Translator object.
UBYTE								*Hotkey			= NULL;	// Hotkey for commodity.
int								gargc;						// Global copy of argc.
char								**gargv;						// Global copy of argv.
UBYTE								**tt				= NULL;	// Tooltypes.

/*-----------------*/
/* Locale related: */
/*-----------------*/
struct Catalog					*catalog			= NULL;	// Watcher.catalog.
struct CatCompArrayType		*StringArray	= &CatCompArray [0];
ULONG								StringCount		= sizeof (CatCompArray) / sizeof (CatCompArray [0]);

/*---------------*/
/* Volume info : */
/*---------------*/
BPTR								VolumeLock [20];	// Used by Lock().
struct InfoData __aligned	id;					// Used by Info().

/*----------------*/
/* Communication: */
/*----------------*/
UBYTE							*ENVARCPrefsName	= "ENVARC:Watcher.Prefs";
UBYTE							*ENVPrefsName		= "ENV:Watcher.Prefs";
struct List					*NotifyList	= NULL;	// Mainting notications in a list.
struct NotifyNode			*NotifyNode;			// Nodes of notifications.
struct MsgPort				*NotifyPort	= NULL;	// Notification on Prefs file.
struct NotifyRequest		*NotifyReq	= NULL;	// Notification request.

struct MsgPort				*TimerPort	= NULL;	// Message port for timer.device.
struct timerequest		*TimerIO		= NULL;	// For doing IO to timer.device.

/*-------*/
/* Misc: */
/*-------*/
BOOL							HideMode		= FALSE;	// CX_POPUP.
UBYTE							ProgramName [PGMNAMELEN];
UBYTE							WindowTitle [80];		// The most important variable!
ULONG							days,hrs,secs,mins,mics;

struct Requester			SleepReq;				// For sleepy windows.
struct Requester			SleepReq2;				// do
UWORD chip					WaitPointer [] =		// Designed by C=
{
	0x0000, 0x0000, 0x0400, 0x07C0, 0x0000, 0x07C0, 0x0100, 0x0380, 0x0000, 0x07E0,
	0x07C0, 0x1FF8, 0x1FF0, 0x3FEC, 0x3FF8, 0x7FDE, 0x3FF8, 0x7FBE, 0x7FFC, 0xFF7F,
	0x7EFC, 0xFFFF, 0x7FFC, 0xFFFF, 0x3FF8, 0x7FFE, 0x3FF8, 0x7FFE, 0x1FF0, 0x3FFC,
	0x07C0, 0x1FF8, 0x0000, 0x07E0, 0x0000, 0x0000
};

/*-------------------------*/
/* SystemListBrowser Misc: */
/*-------------------------*/
ULONG							SLBidcmpSignals;
struct List					*MyScrList		= NULL;
struct List					*MyLibList		= NULL;
struct List					*MyDevList		= NULL;
struct List					*MyTskList		= NULL;
struct List					*MyPrtList		= NULL;
struct List					*MyResList		= NULL;
struct List					*MyFntList		= NULL;
struct List					*MyVolList		= NULL;
struct List					*MyAssList		= NULL;
struct Screen				*LV_SelectedScr;

UBYTE							*CycleText []	= { "Public Screens",
														 "Libraries",
														 "Devices",
														 "Tasks",
														 "Ports",
														 "Resources",
														 "Fonts",
														 "Volumes",
														 "Assigns",
														 NULL
													  };

UWORD							DisplayType		= 0;

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                F U N C T I O N    P R O T O T Y P E S						*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*-----*/
/* Cx: */
/*-----*/
BOOL				CxSetup						(int argc, char *argv []);
void				CxShutDown					(void);
BOOL				HandleCxIDCMP				(ULONG msgid, ULONG msgtype);

/*----------*/
/* IDCMP.c: */
/*----------*/
ULONG				HandleWatcherIDCMP		(ULONG class, UWORD code, APTR iaddress);
BOOL				HandleampIDCMP				(struct AppMessage *amsg);
BOOL				HandleSLBIDCMP				(ULONG class, UWORD code, APTR iaddress);

/*---------*/
/* Lists.c */
/*---------*/
void				SystemListBrowserExit	(void);
BOOL				AllocAllLists				(void);
void				ResetAllLists				(void);
void				RemAllNodes					(void);
void				FreeAllLists				(void);

/*--------------*/
/* Preferences: */
/*--------------*/
BOOL				ReadPrefs					(UBYTE *fname, BOOL Notify);
void				UsePrefsDefaults			(void);
BOOL				SetupPrefsNotification	(void);
void				RemovePrefsNotification (void);

/*------------*/
/* Support.c: */
/*------------*/
BOOL				Inform						(struct Window *w, STRPTR Title,
													 STRPTR Text, APTR args, ...);
BOOL				SleepWindow					(struct Window *w, struct Requester *r);
void				WakeUpWindow				(struct Window *w, struct Requester *r);

/*------------*/
/* Watcher.c: */
/*------------*/
void				OpenLibs						(void);
void				MiscPrep						(void);
void				SetupWindow					(void);
ULONG				HandleIDCMP					(void);
void				CleanExit					(WORD ExitCode, ULONG LocaleNum, ULONG DosExitCode);
struct Screen	*AbleToJumpScr				(void);
void				AllocateWindow				(struct Screen *pubScr);
void				BuildWindowTitle			(STRPTR Buffer);
void				DeAllocateWindow			(void);
void				JumpToNextScr				(void);
void				MakeMenu						(void);

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                                main()											*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void main (int argc, char *argv [])
{
	/*------------------------------------------*/
	/* First of all, we only support Workbench. */
	/*------------------------------------------*/
	if (argc > 0)
	{
		printf (VERS " can only be started from Workbench and requires KS 2.04+\n");
		exit (RETURN_WARN);
	}

	/*--------------------------------------*/
	/* Make global copies of argc and argv. */
	/*--------------------------------------*/
	gargc = argc;
	gargv = argv;

	/*-----------------------------------------------------------*/
	/* Finding a pointer to our task's window for EasyRequest(). */
	/*-----------------------------------------------------------*/
	p = (struct Process *) FindTask (NULL);
	WindowPtr = (struct Window *) p->pr_WindowPtr;
	p->pr_WindowPtr = (void *) -1;

	/*------------------------*/
	/* Get our programs name. */
	/*------------------------*/
	strcpy (ProgramName, p->pr_Task.tc_Node.ln_Name);

	/*------------------------------------------*/
	/* Make sure we know if we're running V39+. */
	/*------------------------------------------*/
	if (SysBase->LibNode.lib_Version >= 39)
	{
		V39 = TRUE;
	}

	/*------------------------------------*/
	/* Create memory pool if running V39. */
	/*------------------------------------*/
	if (V39)
	{
		if (mem_pool = CreatePool (MEMF_FAST, 4096, 2048))
		{
			mem_pool_ok = TRUE;
		}
		else
		{
			mem_pool_ok = FALSE;
		}
	}
	else
	{
		mem_pool_ok = FALSE;
	}

	/*-----------------*/
	/* Open libraries. */
	/*-----------------*/
	OpenLibs ();

	/*------------------------------------*/
	/* Misc preparations and allocations. */
	/*------------------------------------*/
	MiscPrep ();

	/*------------------------------------*/
	/* Setup and open the Watcher window. */
	/*------------------------------------*/
	SetupWindow ();

	/*------------------------*/
	/* The rest is in here... */
	/*------------------------*/
	HandleIDCMP ();

	/*------------------------*/
	/* Cleaning up our act... */
	/*------------------------*/
	CleanExit (RETURN_OK, NULL, 0);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             SetupWindow()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void SetupWindow (void)
{
	strcpy (PubScrBuf, "Workbench");

	/*---------------------------------*/
	/* About to call AllocateWindow(). */
	/*---------------------------------*/
	if (WPrefs->wp_PubScreen [0] != '\0')
	{
		/*---------------------------------------------------------*/
		/* Public screen name specified. We try if we can lock it. */
		/*---------------------------------------------------------*/
		if (PubScr = LockPubScreen (WPrefs->wp_PubScreen))
		{
			/*------------------------------------------------*/
			/* PUBSCREENNAME ok! We now have a pointer to it! */
			/*------------------------------------------------*/
			AllocateWindow (PubScr);
		}
		else
		{
			/*---------------------------------------------------------------*/
			/* Uuups! User specified a public screen which wasn't available. */
			/*---------------------------------------------------------------*/
			if (!(WPrefs->wp_NoJumpGadget))
			{
				/*-----------------------------------------------------------*/
				/* We find the next public screen and open our window there. */
				/*-----------------------------------------------------------*/
				PubScr = NULL;
				if (NextPubScr = AbleToJumpScr ())
				{
					PubScr = NextPubScr;
					AllocateWindow (PubScr);
				}
				else
				{
					CleanExit (RETURN_FAIL, M_CANT_FIND_PUBLIC_SCREEN, 0);
				}
			}
			else
			{
				/*----------------------------------------*/
				/* Obtaining pointer to Workbench screen. */
				/*----------------------------------------*/
				strcpy (PubScrBuf, "Workbench");
				if (PubScr = LockPubScreen (PubScrBuf))
				{
					/*-------------------------*/
					/* Workbench IS available. */
					/*-------------------------*/
					AllocateWindow (PubScr);
				}
				else
				{
					/*-----------------------------*/
					/* Workbench is NOT available. */
					/*-----------------------------*/
					CleanExit (RETURN_FAIL, M_WORKBENCH_NOT_AVAILABLE, 0);
				}
			}
		}
	}
	else
	{
		/*---------------------------------------------------------------------*/
		/* User didn't specify a specific public screen to open on, so we find */
		/* the next in the line.															  */
		/*---------------------------------------------------------------------*/
		if (!(WPrefs->wp_NoJumpGadget))
		{
			PubScr = NULL;
			if (NextPubScr = AbleToJumpScr ())
			{
				PubScr = NextPubScr;
				AllocateWindow (PubScr);
			}
			else
			{
				CleanExit (RETURN_FAIL, M_CANT_FIND_PUBLIC_SCREEN, 0);
			}
		}
		else
		{
			/*----------------------------------------*/
			/* Obtaining pointer to Workbench screen. */
			/*----------------------------------------*/
			strcpy (PubScrBuf, "Workbench");
			if (PubScr = LockPubScreen (PubScrBuf))
			{
				/*-------------------------*/
				/* Workbench IS available. */
				/*-------------------------*/
				AllocateWindow (PubScr);
			}
			else
			{
				/*-----------------------------*/
				/* Workbench is NOT available. */
				/*-----------------------------*/
				CleanExit (RETURN_FAIL, M_WORKBENCH_NOT_AVAILABLE, 0);
			}
		}
	}
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             HandleIDCMP()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
ULONG HandleIDCMP (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	struct IntuiMessage	*imsg;					// Messages from window.
	struct IntuiMessage	*imsg2;					// Messages from window.
	struct AmigaGuideMsg	*agmsg;					// AmigaGuide message.
	struct RexxMsg			*rxmsg;					// ARexx message.
	struct NotifyMessage	*notifymsg;				// Message concerning notification.
	UBYTE						InformTxt [80];		// Inform text buffer.
	ULONG						class;					// IntuiMessage Class and GadgetID
	ULONG						class2;					// IntuiMessage Class for SLB.
	UWORD						Code;						// IntuiMessage Code etc.
	UWORD						Code2;					// IntuiMessage Code.
	APTR						iAddress;				// IntuiMessage IAddress.
	APTR						iAddress2;				// IntuiMessage IAddress.
	BOOL						timeToExit = FALSE;	// Exit switch.
	CxMsg						*cxmsg;					// Message from CX.
	ULONG						cxmsgid, cxmsgtype;	// Id and Type of message from CX.

	ULONG						timerSignals 		= (1L << TimerPort->mp_SigBit);
	ULONG						agSignals	 		= AmigaGuideSignal (ag_AmigaGuide);
	ULONG						rexxSignals  		= ARexxSignal (RexxStuff);
	ULONG						notifySignals		= (1L << NotifyPort->mp_SigBit);
	ULONG						ampSignals			= (1L << amp->mp_SigBit);
	ULONG						cxSignals			= (1L << CxMsgPort->mp_SigBit);
	ULONG						signal;

	/*---------*/
	/* C O D E */
	/*---------*/
	if (Win)
	{
		idcmpSignals = (1L << Win->UserPort->mp_SigBit);
	}

	/*---------------------------------------*/
	/* We issue a asynchronous wait command. */
	/*---------------------------------------*/
	TimerIO->tr_node.io_Command	= TR_ADDREQUEST;

	/*----------------------------------------------------*/
	/* Checking if user supplied update ratio in seconds. */
	/*----------------------------------------------------*/
	if (WPrefs->wp_UpdateSec)
	{
		TimerIO->tr_time.tv_secs	= WPrefs->wp_UpdateSec;
		TimerIO->tr_time.tv_micro	= (WPrefs->wp_UpdateMic) ? WPrefs->wp_UpdateMic : 0;
	}
	else
	{
		if (WPrefs->wp_UpdateMic)
		{
			TimerIO->tr_time.tv_secs	= 0;
			TimerIO->tr_time.tv_micro	= WPrefs->wp_UpdateMic;
		}
		else
		{
			TimerIO->tr_time.tv_secs	= 1;
			TimerIO->tr_time.tv_micro	= 0;
		}
	}

	/*----------------------------------*/
	/* Sending asynchronous IO request. */
	/*----------------------------------*/
	SendIO ((struct IORequest *) TimerIO);

	/*-------------------------------*/
	/* Clear the AmigaGuide context. */
	/*-------------------------------*/
	if (AmigaGuideBase)
	{
		SetAmigaGuideContext (ag_AmigaGuide, 0L, NULL);
	}

 HandleIDCMPAgain:

	/*----------------------------*/
	/* Wating for user choices... */
	/*----------------------------*/
	while (!timeToExit)
	{
		/*-----------------------------------------------------*/
		/* First we wait for signals to arrive at either port. */
		/*-----------------------------------------------------*/
		if (SLBWin)
		{
			if (AmigaGuideBase)
			{
				signal = Wait (notifySignals | idcmpSignals | SLBidcmpSignals | agSignals |
									rexxSignals | timerSignals | ampSignals | cxSignals);
			}
			else
			{
				signal = Wait (notifySignals | idcmpSignals | SLBidcmpSignals | rexxSignals |
									timerSignals | ampSignals | cxSignals);
			}
		}
		else
		{
			if (AmigaGuideBase)
			{
				signal = Wait (notifySignals | idcmpSignals | agSignals | rexxSignals | timerSignals |
									ampSignals | cxSignals);
			}
			else
			{
				signal = Wait (notifySignals | idcmpSignals | rexxSignals | timerSignals |
									ampSignals | cxSignals);
			}
		}

		/*------------------------------------------------------*/
		/* Checking if singal came from the Commodities System. */
		/*------------------------------------------------------*/
		if (signal & cxSignals)
		{
			/*--------------------------*/
			/* Get the message from CX. */
			/*--------------------------*/
			while (cxmsg = (CxMsg *) GetMsg (CxMsgPort))
			{
				/*------------------------------*/
				/* Grab id and type of message. */
				/*------------------------------*/
				cxmsgid		= CxMsgID (cxmsg);
				cxmsgtype	= CxMsgType (cxmsg);

				/*---------------------*/
				/* Remove the message. */
				/*---------------------*/
				ReplyMsg ((struct Message *) cxmsg);

				/*---------------------------*/
				/* Act according to message. */
				/*---------------------------*/
				if (HandleCxIDCMP (cxmsgid, cxmsgtype))
				{
					timeToExit = TRUE;
				}
			}
		}

		/*------------------------------------------*/
		/* Checking if signal came from our window. */
		/*------------------------------------------*/
		if ((signal & idcmpSignals) && (Win))
		{
			/*--------------------------------------------------------*/
			/* It did! We walk through all pending messages (if any). */
			/*--------------------------------------------------------*/
			while (imsg = GT_GetIMsg (Win->UserPort))
			{
				/*--------------------------------------------------------*/
				/* A message arrived. We save vital information from that */
				/* message, and remove it, by replying to it.				 */
				/*--------------------------------------------------------*/
				class		= imsg->Class;
				Code		= imsg->Code;
				iAddress	= imsg->IAddress;
				GT_ReplyIMsg (imsg);

				/*------------------------------------*/
				/* Take actions according to message. */
				/*------------------------------------*/
				switch (HandleWatcherIDCMP (class, Code, iAddress))
				{
					case 0 :
					{
						/*---------------*/
						/* Time to quit. */
						/*---------------*/
						timeToExit = TRUE;
						break;
					}
					case 1 :
					{
						/*------*/
						/* NOP. */
						/*------*/
						break;
					}
					case 2 :
					{
						/*---------------------------------------------------*/
						/* User interface now hidden and window not present. */
						/*---------------------------------------------------*/
						goto HandleIDCMPAgain;
					}
					default :
					{
						/*--------------------------------------*/
						/* Couldn't happen, but we're cautious. */
						/*--------------------------------------*/
						break;
					}
				}
			}
		}

		/*-------------------------------------------------------*/
		/* Checking if signal came from filesystem/notification. */
		/*-------------------------------------------------------*/
		if (signal & notifySignals)
		{
			/*------------------*/
			/* Process message. */
			/*------------------*/
			while (notifymsg = (struct NotifyMessage *) GetMsg (NotifyPort))
			{
				/*------------------------------------------------------------------*/
				/* Yes! Received notification on preference file!. We re-read them! */
				/*------------------------------------------------------------------*/
				if (Win)
				{
					DeAllocateWindow ();
					ReadPrefs (notifymsg->nm_NReq->nr_Name, FALSE);
				}
				ReplyMsg ((struct Message *) notifymsg);
				if (!Win)
				{
					AllocateWindow (PubScr);
					ScreenToFront (PubScr);
				}
			}
		}

		/*----------------------------------------*/
		/* Checking if signal came from App Info. */
		/*----------------------------------------*/
		if (signal & ampSignals)
		{
			/*--------------------------*/
			/* Act on all the messages. */
			/*--------------------------*/
			while (amsg = (struct AppMessage *) GetMsg (amp))
			{
				if (Win)
				{
					if (SLBWin)
					{
						/*----------------------------------------------------*/
						/* SLB window active which needs to be removed first. */
						/*----------------------------------------------------*/
						UBYTE *z = XGetString (M_WARNING);
						Inform (NULL, z, "%s", XGetString (M_QUIT_SLB_FIRST));
					}
					else
					{
						SleepWindow (Win, &SleepReq);
						if (HandleampIDCMP (amsg))
						{
							WakeUpWindow (Win, &SleepReq);
							goto HandleIDCMPAgain;
						}
						WakeUpWindow (Win, &SleepReq);
					}
				}
				ReplyMsg ((struct Message *) amsg);
			}
		}

		/*------------------------------------------*/
		/* Checking if signal came from SLB window. */
		/*------------------------------------------*/
		if (signal & SLBidcmpSignals)
		{
			/*-----------------------*/
			/* Process all messages. */
			/*-----------------------*/
			while (imsg2 = GT_GetIMsg (SLBWin->UserPort))
			{
				/*-------------------------*/
				/* Grab info from message. */
				/*-------------------------*/
				class2		= imsg2->Class;
				Code2			= imsg2->Code;
				iAddress2	= imsg2->IAddress;
				GT_ReplyIMsg (imsg2);

				/*----------------------*/
				/* Now act on the info. */
				/*----------------------*/
				if (HandleSLBIDCMP (class2, Code2, iAddress2))
				{
					goto HandleIDCMPAgain;
				}
			}
		}

		if (AmigaGuideBase)
		{
			/*----------------------------------*/
			/* Checking for AmigaGuide message. */
			/*----------------------------------*/
			if (signal & agSignals)
			{
				/*---------------------------------*/
				/* Processing AmigaGuide messages. */
				/*---------------------------------*/
				while (agmsg = GetAmigaGuideMsg (ag_AmigaGuide))
				{
					/*------------------------*/
					/* Checking message type. */
					/*------------------------*/
					switch (agmsg->agm_Type)
					{
						case ActiveToolID :					// AmigaGuide is ready.
						{
							break;
						}
						case ToolCmdReplyID :				// Reply to our command.
						{
							if (agmsg->agm_Pri_Ret)
							{
								/*-----------------------*/
								/* An error has occured. */
								/*-----------------------*/
								strcpy (InformTxt, GetAmigaGuideString (agmsg->agm_Sec_Ret));
								Inform (Win, "Information", InformTxt, NULL);
							}
							break;
						}
						case ToolStatusID :					// Status message.
						{
							if (agmsg->agm_Pri_Ret)
							{
								/*-----------------------*/
								/* An error has occured. */
								/*-----------------------*/
								strcpy (InformTxt, GetAmigaGuideString (agmsg->agm_Sec_Ret));
								Inform (Win, "Information", InformTxt, NULL);
							}
							break;
						}
						case ShutdownMsgID :					// Shutdown message.
						{
							if (agmsg->agm_Pri_Ret)
							{
								/*-----------------------*/
								/* An error has occured. */
								/*-----------------------*/
								strcpy (InformTxt, GetAmigaGuideString (agmsg->agm_Sec_Ret));
								Inform (Win, "Information", InformTxt, NULL);
							}
							break;
						}
						default :
						{
							break;
						}
					}

					/*------------------------------*/
					/* Reply to AmigaGuide message. */
					/*------------------------------*/
					ReplyAmigaGuideMsg (agmsg);
				}
			}
		}

		/*-------------------------------------*/
		/* Checking if signal came from ARexx! */
		/*-------------------------------------*/
		if (signal & rexxSignals)
		{
			/*----------------------------*/
			/* Processing ARexx messages. */
			/*----------------------------*/
			while (rxmsg = GetARexxMsg (RexxStuff))
			{
				/*------------------------------------------------*/
				/* Variables related to interpreting the message. */
				/*------------------------------------------------*/
				char cBuf [24];
				char *nextchar;
				char *error		= NULL;
				char *result	= NULL;
				LONG errlevel	= 0;

				/*------------------------*/
				/* Process ARexx message. */
				/*------------------------*/
				nextchar = stptok (ARG0 (rxmsg), cBuf, 24, " ,");
				if (*nextchar)
				{
					nextchar++;
				}

				/*-------------------*/
				/* GETTITLE command. */
				/*-------------------*/
				if (!Stricmp ("GETTITLE", cBuf))
				{
					/*--------------------------------*/
					/* Check that our window is open. */
					/*--------------------------------*/
					if (Win)
					{
						result = Win->Title;
					}
					else
					{
						error = XGetString (M_WINDOW_NOT_AVAILABLE);
						errlevel = 5;
					}
				}

				/*---------------------*/
				/* JUMPSCREEN command. */
				/*---------------------*/
				if (!Stricmp ("JUMPSCREEN", cBuf))
				{
					if (!(WPrefs->wp_NoJumpGadget))
					{
						/*------------------------------------------*/
						/* Check if there is another public screen. */
						/*------------------------------------------*/
						if (NextPubScr = AbleToJumpScr ())
						{
							/*-------------------*/
							/* We take the jump! */
							/*-------------------*/
							KeepWinPos = TRUE;
							JumpToNextScr ();
						}
						else
						{
							/*-----------------------------------------*/
							/* We inform that there are no other pulic */
							/* screens available.							 */
							/*-----------------------------------------*/
							error = XGetString (M_NO_OTHER_PUBSCREENS);
							errlevel = 5;
						}
					}
				}

				/*-------------------*/
				/* SHOWHELP command. */
				/*-------------------*/
				if (!Stricmp ("SHOWHELP", cBuf))
				{
					if (AmigaGuideBase)
					{
						/*--------------------*/
						/* Display help node. */
						/*--------------------*/
						SendAmigaGuideCmd (ag_AmigaGuide, NULL, AGA_Context, 0, TAG_DONE);
					}
					else
					{
						error = XGetString (M_SYSTEM_NOT_AVAILABLE);;
						errlevel = 5;
					}
				}

				/*---------------*/
				/* QUIT command. */
				/*---------------*/
				if (!Stricmp ("QUIT", cBuf))
				{
					timeToExit = TRUE;
				}

				/*-------------------*/
				/* Check for errors. */
				/*-------------------*/
				if (error)
				{
					SetARexxLastError (RexxStuff, rxmsg, error);
				}

				/*-------------------------*/
				/* Reply to ARexx message. */
				/*-------------------------*/
				ReplyARexxMsg (RexxStuff, rxmsg, result, errlevel);
			}
		}

		/*--------------------------------------------*/
		/* Checking if signal came from timer.device. */
		/*--------------------------------------------*/
		if (signal & timerSignals)
		{
			/*-------------------------------------------------------------*/
			/* Before we start reusing the TimerIO we need to be sure that */
			/* the previous asynchronous IO has ceased to exist.				*/
			/*-------------------------------------------------------------*/
			WaitIO ((struct IORequest *) TimerIO);

			/*----------------------------------*/
			/* Then we update the window title. */
			/*----------------------------------*/
			if (Win)
			{
				BuildWindowTitle (WindowTitle);
				SetWindowTitles (Win, (UBYTE *) WindowTitle, (UBYTE *) -1);
			}

			/*---------------------------------------*/
			/* And we issue a new asynchronous wait. */
			/*---------------------------------------*/
			TimerIO->tr_node.io_Command	= TR_ADDREQUEST;
			if (WPrefs->wp_UpdateSec)
			{
				TimerIO->tr_time.tv_secs	= WPrefs->wp_UpdateSec;
				TimerIO->tr_time.tv_micro	= (WPrefs->wp_UpdateMic) ? WPrefs->wp_UpdateMic : 0;
			}
			else
			{
				if (WPrefs->wp_UpdateMic)
				{
					TimerIO->tr_time.tv_secs	= 0;
					TimerIO->tr_time.tv_micro	= WPrefs->wp_UpdateMic;
				}
				else
				{
					TimerIO->tr_time.tv_secs	= 1;
					TimerIO->tr_time.tv_micro	= 0;
				}
			}
			SendIO ((struct IORequest *) TimerIO);
		}
	}
	return (0);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                            AbleToJumpScr()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
struct Screen *AbleToJumpScr (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	struct Screen *PossibleJumpScr;
	UBYTE				savedPubScrBuf [MAXPUBSCREENNAME + 1];

	/*---------*/
	/* C O D E */
	/*---------*/
	/*------------------------------------*/
	/* Saving current public screen name. */
	/*------------------------------------*/
	strcpy (savedPubScrBuf, PubScrBuf);

	/*------------------------------------------*/
	/* Finding next public screen in the cycle. */
	/*------------------------------------------*/
	if (NextPubScreen (PubScr, PubScrBuf))
	{
		/*------------------------------------------------------------*/
		/* There was another public screen, and the name of it, is in */
		/* PubScrBuf. Now we check whether or not it is the same that */
		/* we're already in!														  */
		/*------------------------------------------------------------*/
		if (!(Stricmp (savedPubScrBuf, PubScrBuf)))
		{
			/*----------------------------------*/
			/* No new public screen introduced. */
			/*----------------------------------*/
			return (NULL);
		}

		/*----------------------------------*/
		/* Locking the found public screen. */
		/*----------------------------------*/
		if (!(PossibleJumpScr = LockPubScreen (PubScrBuf)))
		{
			/*-------------------------------------------------*/
			/* We failed. Restore saved screen lock (pointer). */
			/*-------------------------------------------------*/
			return (NULL);
		}
		else
		{
			/*----------------------------------------------------*/
			/* Success! We return a pointer to the locked screen! */
			/*----------------------------------------------------*/
			return (PossibleJumpScr);
		}
	}
	else
	{
		/*------------------------------*/
		/* No public screens available. */
		/*------------------------------*/
		Inform (Win, "Information", "%s", XGetString (M_NO_OTHER_PUBSCREENS));
		return (NULL);
	}
	return (PossibleJumpScr);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                            JumpToNextScr()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void JumpToNextScr (void)
{
	DeAllocateWindow ();
	PubScr = NextPubScr;
	AllocateWindow (PubScr);
	ScreenToFront (PubScr);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                          DeAllocateWindow()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void DeAllocateWindow (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	struct IntuiMessage *imsg;						// For freeing all messages from
															// our window's UserPort before
															// closing it.

	/*---------*/
	/* C O D E */
	/*---------*/
	/*-------------------------------------------------------------------*/
	/* Before we shut down our window, we need to remember the position. */
	/*-------------------------------------------------------------------*/
	KeepWinLeft	= Win->LeftEdge;
	KeepWinTop	= Win->TopEdge;

	/*----------------------------*/
	/* Shut down amigaguide help. */
	/*----------------------------*/
	if (ag_AmigaGuide && AmigaGuideBase)
	{
		CloseAmigaGuide (ag_AmigaGuide);
		ag_AmigaGuide = NULL;
	}

	/*------------------*/
	/* Shut down ARexx. */
	/*------------------*/
	if (RexxStuff)
	{
		FreeARexx (RexxStuff);
		RexxStuff = NULL;
	}

	/*---------------------*/
	/* Freeing VisualInfo. */
	/*---------------------*/
	if (VisualInfo)
	{
		FreeVisualInfo (VisualInfo);
		VisualInfo = NULL;
	}

	/*------------------------------*/
	/* Freeing and releasing menus. */
	/*------------------------------*/
	if (Menus)
	{
		ClearMenuStrip (Win);
		FreeMenus (Menus);
		Menus = NULL;
	}

	/*---------------------------*/
	/* Removing gadget from Win. */
	/*---------------------------*/
	if ((Win) && (GList))
	{
		RemoveGList (Win, GList, -1);
	}

	/*--------------------*/
	/* Freeing draw info. */
	/*--------------------*/
	if (drinfo)
	{
		FreeScreenDrawInfo (Win->WScreen, drinfo);
		drinfo = NULL;
	}

	/*--------------------------------------------------*/
	/* Removing pending messages from windows UserPort. */
	/*--------------------------------------------------*/
	if (Win)
	{
		while (imsg = GT_GetIMsg (Win->UserPort))
		{
			GT_ReplyIMsg (imsg);
		}
	}

	/*-----------------*/
	/* Closing window. */
	/*-----------------*/
	if (Win)
	{
		if (SLBWin)
		{
			SystemListBrowserExit ();
			SLBWin = NULL;
		}
		CloseWindow (Win);
		Win = NULL;

		/*------------------------------------------------------*/
		/* Make idcmpSignals reflect that the window is closed. */
		/*------------------------------------------------------*/
		idcmpSignals = NULL;
	}

	/*--------------------------*/
	/* UnLocking public screen. */
	/*--------------------------*/
	if (PubScr)
	{
		UnlockPubScreen (NULL, PubScr);
	}

	/*-------------------*/
	/* Disposing gadget. */
	/*-------------------*/
	while (GList)
	{
		tmpgad = GList->NextGadget;
		DisposeObject (GList);
		GList = tmpgad;
	}

	/*------------------*/
	/* Disposing image. */
	/*------------------*/
	if (jumpimage)
	{
		DisposeObject (jumpimage);
		jumpimage = NULL;
	}
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                           AllocateWindow()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void AllocateWindow (struct Screen *pubScr)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	ULONG	WinWidth, WinHeight;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*-------------------*/
	/* Check Hide state. */
	/*-------------------*/
	if (HideMode)
	{
		return;
	}

	/*----------------------------------------------------*/
	/* We start calculating the dimensions of our window. */
	/*----------------------------------------------------*/
	WinHeight = PubScr->WBorTop + PubScr->RastPort.TxHeight + 1;
	WinWidth	 = (WPrefs->wp_WinWidth) ? (WinWidth = WPrefs->wp_WinWidth) :
													(WinWidth = (PubScr->Width - (WPrefs->wp_WinLeftEdge)));

	/*-------------------------------------------*/
	/* Checking if window is able to fit screen. */
	/*-------------------------------------------*/
	if (WinWidth > (PubScr->Width - (WPrefs->wp_WinLeftEdge)))
	{
		CleanExit (RETURN_FAIL, M_WINDOW_TOO_LARGE, 0);
	}

	/*----------------------------------*/
	/* Getting Visual Info for gadgets. */
	/*----------------------------------*/
	if (!(VisualInfo = GetVisualInfoA (PubScr, TAG_DONE)))
	{
		CleanExit (RETURN_FAIL, M_CANT_GET_VISUAL_INFO, 0);
	}

	/*-----------------------------------------------------------------------*/
	/* Before we open our window, we need the title of the window to reflect */
	/* the user's memory conditions.														 */
	/*-----------------------------------------------------------------------*/
	BuildWindowTitle (WindowTitle);

	if (KeepWinPos)
	{
		/*-------------------------*/
		/* Opening Watcher window. */
		/*-------------------------*/
		if (!(Win = OpenWindowTags (NULL,
											 WA_Left,			KeepWinLeft,
											 WA_Top,				KeepWinTop,
											 WA_Width,			WinWidth,
											 WA_Height,			WinHeight,
											 WA_IDCMP,			IDCMP_CLOSEWINDOW		|
																	IDCMP_GADGETUP			|
																	IDCMP_MENUPICK			|
																	IDCMP_MENUHELP			|
																	IDCMP_MOUSEMOVE		|
																	IDCMP_RAWKEY			|
																	IDCMP_REFRESHWINDOW,
											 WA_Flags,			WFLG_CLOSEGADGET	|
																	WFLG_DEPTHGADGET	|
																	WFLG_DRAGBAR		|
																	WFLG_NOCAREREFRESH,
											 WA_MenuHelp,		TRUE,
											 WA_Gadgets,		NULL,
											 WA_Title,			WindowTitle,
											 WA_PubScreen,		PubScr,
											 WA_NewLookMenus,	TRUE,
											 TAG_DONE)))
		{
			CleanExit (RETURN_FAIL, M_COULDNT_OPEN_WINDOW, 0);
		}
	}
	else
	{
		/*-------------------------*/
		/* Opening Watcher window. */
		/*-------------------------*/
		if (!(Win = OpenWindowTags (NULL,
											 WA_Left,				(WPrefs->wp_WinLeftEdge) ?
																		WPrefs->wp_WinLeftEdge : 0,
											 WA_Top,					(WPrefs->wp_WinTopEdge) ?
																		WPrefs->wp_WinTopEdge : 0,
											 WA_Width,				WinWidth,
											 WA_Height,				WinHeight,
											 WA_IDCMP,				IDCMP_CLOSEWINDOW		|
																		IDCMP_GADGETUP			|
																		IDCMP_MENUPICK			|
																		IDCMP_MENUHELP			|
																		IDCMP_MOUSEMOVE		|
																		IDCMP_RAWKEY			|
																		IDCMP_REFRESHWINDOW,
											 WA_Flags,				WFLG_CLOSEGADGET	|
																		WFLG_DEPTHGADGET	|
																		WFLG_DRAGBAR		|
																		WFLG_NOCAREREFRESH,
											 WA_MenuHelp,			TRUE,
											 WA_Gadgets,			NULL,
											 WA_Title,				WindowTitle,
											 WA_PubScreen,			PubScr,
											 WA_NewLookMenus,		TRUE,
											 TAG_DONE)))
		{
			CleanExit (RETURN_FAIL, M_COULDNT_OPEN_WINDOW, 0);
		}
	}

	/*-------------------------------*/
	/* Creating and activating menu. */
	/*-------------------------------*/
	MakeMenu ();

	if (AmigaGuideBase)
	{
		UBYTE pn [PGMNAMELEN];
		UBYTE pa [PGMNAMELEN];

		/*---------------------------------------*/
		/* Initialize amigaguide related fields. */
		/*---------------------------------------*/
		strcpy (pn, ProgramName);
		strcat (pn, "Help");
		ag_NAG.nag_BaseName		= pn;				// Applications name.

		if ((WPrefs->wp_GuideFile [0] == '\0') || (WPrefs->wp_GuideFile [0] == ' '))
		{
			/*-------------------------*/
			/* Check that file exists. */
			/*-------------------------*/
			BPTR FileLock;

			strcpy (pa, ProgramName);
			strcat (pa, ".guide");
			FileLock = Lock (pa, ACCESS_READ);
			if (FileLock)
			{
				UnLock (FileLock);
				ag_NAG.nag_Name	= pa;				// AmigaGuide document name.
			}
			else
			{
				Inform (Win, "Information", "%s", XGetString (M_CANT_FIND_GUIDE_FILE));
			}
		}
		else
		{
			/*-------------------------*/
			/* Check that file exists. */
			/*-------------------------*/
			BPTR FileLock;
			FileLock = Lock (WPrefs->wp_GuideFile, ACCESS_READ);
			if (FileLock)
			{
				UnLock (FileLock);
				ag_NAG.nag_Name	= WPrefs->wp_GuideFile;
			}
			else
			{
				Inform (Win, "Information", "%s", XGetString (M_GUIDE_ERROR));
			}
		}
		ag_NAG.nag_ClientPort	= "WATCHERHELP";		// ARexx port name.
		ag_NAG.nag_Context		= AGContext;			// Setup context table.
		ag_NAG.nag_Screen			= PubScr;				// Open on pubscr.

		/*------------------------------*/
		/* Open AmigaGuide help system. */
		/*------------------------------*/
		if (ag_AmigaGuide = OpenAmigaGuideAsync (&ag_NAG, NULL))
		{
			ag_Available = TRUE;
		}
		else
		{
			ag_Available = FALSE;
		}
	}
	else
	{
		ag_Available = FALSE;
	}

	/*-------------------*/
	/* Initialize ARexx. */
	/*-------------------*/
	RexxStuff = InitARexx ("Watcher", NULL);
	if (!(ARexxName (RexxStuff)))
	{
		/*---------------------------------------------------------*/
		/* We don't have an AREXX port, so we make a note of that! */
		/*---------------------------------------------------------*/
		RexxAvailable = FALSE;
	}

	/*---------------------------------------------------------*/
	/* The following only applies if the JumpGadget is wanted. */
	/*---------------------------------------------------------*/
	if (!(WPrefs->wp_NoJumpGadget))
	{
		/*---------------------------------------*/
		/* Getting draw info from public screen. */
		/*---------------------------------------*/
		if (!(drinfo = GetScreenDrawInfo (PubScr)))
		{
			CleanExit (RETURN_FAIL, M_CANT_GET_DRAWINFO, 0);
		}

		/*--------------------------*/
		/* Get system's ZOOM image. */
		/*--------------------------*/
		jumpimage = (struct Image *) NewObject (NULL, "sysiclass",
															 IA_Height,			WinHeight,
															 SYSIA_Which,		ZOOMIMAGE,
															 SYSIA_DrawInfo,	drinfo,
															 TAG_END);

		/*-----------------------------------------------------------*/
		/* Let tmpgad point to first in list of gadgets (empty now). */
		/*-----------------------------------------------------------*/
		tmpgad = (struct Gadget *) &GList;

		/*--------------------*/
		/* Build DOWN gadget. */
		/*--------------------*/
		JumpScrGad = (struct Gadget *)
						 NewObject (NULL, "buttongclass",
										GA_DrawInfo,		drinfo,
										GA_Image,			jumpimage,
										GA_SelectRender,	jumpimage,
										GA_Top,				0,
										GA_Left,				Win->Width - 46,
										GA_ID,				GD_JUMPSCR,
										GA_TopBorder,		TRUE,
										GA_Previous,		tmpgad,
										GA_Immediate,		TRUE,
										GA_RelVerify,		TRUE,
										TAG_END);

		/*-------------------------------------------------------------------*/
		/* Adding the JumpScr gadget as the FIRST gadget in our window. Note */
		/* that we are aware, that doing this is dangerous, but we are sure	*/
		/* the JmpScrGad'get doesn't overlap system gadgets, so this is OK!	*/
		/*-------------------------------------------------------------------*/
		AddGadget (Win, JumpScrGad, 0);
		RefreshGadgets (JumpScrGad, Win, NULL);
	}

	/*--------------------------------------------------*/
	/* Make idcmpSignals reflect that the window is up. */
	/*--------------------------------------------------*/
	idcmpSignals = (1L << Win->UserPort->mp_SigBit);

	/*---------------------*/
	/* Check the App Info: */
	/*---------------------*/
	if (AppInfoActive)
	{
		RemoveAppIcon (ai);
		ai = NULL;
		AppInfoActive = FALSE;
	}

	/*-----------------------------------------*/
	/* Check if we should launch App Info now. */
	/*-----------------------------------------*/
	if ((WPrefs->wp_AppInfoAutoStart) && (HideMode == FALSE))
	{
		/*----------------------------------*/
		/* Add the application icon to the. */
		/*----------------------------------*/
		dobj->do_CurrentX	= WPrefs->wp_AppInfoLeftEdge;
		dobj->do_CurrentY	= WPrefs->wp_AppInfoTopEdge;
		if (!(ai = AddAppIconA (1, 0, "App Info", amp, NULL, dobj, NULL)))
		{
			Inform (Win, "Error:", "%s", XGetString (M_CANT_LAUNCH_APPINFO));
		}
		AppInfoActive = TRUE;
	}
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                          BuildWindowTitle()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void BuildWindowTitle (STRPTR Buffer)
{
	//
	// It builds the window title with the information the user wants, ie.
	// according to the Watcher.prefs settings.
	//

	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	ULONG					fastMem, chipMem, largest, fastLargest, chipLargest;
	ULONG					bytesLeft, x;
	UBYTE					tempBuffer [80];
	UBYTE					dateBuffer [LEN_DATSTRING], timeBuffer [LEN_DATSTRING];
	UBYTE					dayBuffer [LEN_DATSTRING];
	UBYTE					Direction;
	UBYTE					alertBuf [100];
	struct DateStamp	ds;
	struct DateTime	dt;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*--------------*/
	/* Memory part. */
	/*--------------*/
	fastMem = AvailMem (MEMF_FAST);
	chipMem = AvailMem (MEMF_CHIP);
	fastLargest = AvailMem (MEMF_FAST | MEMF_LARGEST);
	chipLargest = AvailMem (MEMF_CHIP | MEMF_LARGEST);
	largest = (fastLargest > chipLargest) ? fastLargest : chipLargest;

	/*-----------------------------*/
	/* Reset user supplied buffer. */
	/*-----------------------------*/
	Buffer [0] = '\0';

	/*--------------------------------------------*/
	/* Initialize before looping through volumes. */
	/*--------------------------------------------*/
	VolCount = 0;

	/*--------------------------*/
	/* Looping through volumes. */
	/*--------------------------*/
	while ((WPrefs->wp_VolName [VolCount] [0] != '\0') && (VolCount < WPrefs->wp_VolCount))
	{
		/*---------------------------------------------------*/
		/* We check if we already have a lock on the volume. */
		/*---------------------------------------------------*/
		if (!(VolumeLock [VolCount]))
		{
			/*----------------------------------------------------------*/
			/* We don't have a lock. This could happen for ie. floppy	*/
			/* volumes say DF1:, which 'flops' in and out of the drive	*/
			/* causing Info(), UnLock() and then again Lock() here!		*/
			/*----------------------------------------------------------*/
			VolumeLock [VolCount] = Lock (WPrefs->wp_VolName [VolCount], ACCESS_READ);
		}

		/*--------------------------------------------------*/
		/* Check that we have a lock on the current volume. */
		/*--------------------------------------------------*/
		if (VolumeLock [VolCount])
		{
			/*-------------------------------------------------------*/
			/* We assume to have a lock! Now we can do Info() on it. */
			/*-------------------------------------------------------*/
			if (Info (VolumeLock [VolCount], &id))
			{
				bytesLeft = ((id.id_NumBlocks - id.id_NumBlocksUsed) *
								id.id_BytesPerBlock);

				/*--------------*/
				/* Check Alert. */
				/*--------------*/
				x = 0;
				while (x < WPrefs->wp_VolAlertCount)
				{
					/*--------------------------------------------------------*/
					/* Check if we have an alert watch on VolName [VolCount]. */
					/*--------------------------------------------------------*/
					if (!Stricmp (WPrefs->wp_VolName [VolCount], WPrefs->wp_VolAlert [x]))
					{
						/*----------------------------------------------------------*/
						/* Check if the volume free space is below the alert limit. */
						/*----------------------------------------------------------*/
						if (bytesLeft <= WPrefs->wp_VolAlertLimit [x])
						{
							/*-------------------------------------------------------------*/
							/* Volume IS below limit, we check if we already have alerted. */
							/*-------------------------------------------------------------*/
							if (!(VolAlertOk [x]))
							{
								UBYTE *z = XGetString (M_ALERT);
								/*-------------------------------------*/
								/* We haven't, so we issue an alert... */
								/*-------------------------------------*/
								sprintf (alertBuf, "%s %s", WPrefs->wp_VolAlert [x],
																	 XGetString (M_HAS_HIT_ALERT_LIMIT));
								Inform (Win, z, alertBuf, NULL);

								/*-------------------------------------------------*/
								/* We mark the volume as being already alerted to. */
								/*-------------------------------------------------*/
								VolAlertOk [x] = TRUE;
							}
						}
						else
						{
							/*----------------------------------------------*/
							/* We check if the volume has been below limit. */
							/*----------------------------------------------*/
							if (VolAlertOk [x])
							{
								UBYTE *z = XGetString (M_VOLUME_NOW_OK);
								sprintf (alertBuf, "%s %s", WPrefs->wp_VolAlert [x],
																	 XGetString (M_NOW_ABOVE_ALERT_LIMIT));
								Inform (Win, z, alertBuf, NULL);
								VolAlertOk [x] = FALSE;
							}
						}
					}
					x++;
				}

				/*----------------------------------------*/
				/* Check if free space changed on volume. */
				/*----------------------------------------*/
				if (VolFreeSpace [VolCount] > bytesLeft)
				{
					VolSizeChanged [VolCount] = 2;
					VolFreeSpace [VolCount] = bytesLeft;
				}
				else
				{
					if (VolFreeSpace [VolCount] < bytesLeft)
					{
						VolSizeChanged [VolCount] = 1;
					}
					else
					{
						VolSizeChanged [VolCount] = 0;
					}
				}
				VolFreeSpace [VolCount] = bytesLeft;

				/*-----------------------------------------------------------*/
				/* Info() OK! Fill user's buffer with data about volume free */
				/* size.																		 */
				/*-----------------------------------------------------------*/
				switch (VolSizeChanged [VolCount])
				{
					case 0 :
					{
						if (WPrefs->wp_VolumeFreeDirectionInd [0] != '\0')
						{
							Direction = WPrefs->wp_VolumeFreeDirectionInd [0];
						}
						else
						{
							Direction = '-';
						}
						break;
					}
					case 1 :
					{
						if (WPrefs->wp_VolumeFreeDirectionInd [1] != '\0')
						{
							Direction = WPrefs->wp_VolumeFreeDirectionInd [1];
						}
						else
						{
							Direction = '^';
						}
						break;
					}
					case 2 :
					{
						if (WPrefs->wp_VolumeFreeDirectionInd [2] != '\0')
						{
							Direction = WPrefs->wp_VolumeFreeDirectionInd [2];
						}
						else
						{
							Direction = 'v';
						}
						break;
					}
				}

				/*-----------------------------------------------------------*/
				/* Info() OK! Fill user's buffer with data about volume free */
				/* size.																		 */
				/*-----------------------------------------------------------*/
				switch (WPrefs->wp_VolNameType [VolCount])
				{
					case VBYTE :
					{
						if (WPrefs->wp_VolumeFreeDirection)
						{
							sprintf (tempBuffer, "%s%c%ld ", WPrefs->wp_VolName [VolCount], Direction, bytesLeft);
						}
						else
						{
							sprintf (tempBuffer, "%s%ld ", WPrefs->wp_VolName [VolCount], bytesLeft);
						}
						break;
					}
					case VKILOBYTE :
					{
						if (WPrefs->wp_VolumeFreeDirection)
						{
							sprintf (tempBuffer, "%s%c%ldK ", WPrefs->wp_VolName [VolCount], Direction,
																		 bytesLeft / 1024);
						}
						else
						{
							sprintf (tempBuffer, "%s%ldK ", WPrefs->wp_VolName [VolCount],
																		 bytesLeft / 1024);
						}
						break;
					}
					case VMEGABYTE :
					{
						if (WPrefs->wp_VolumeFreeDirection)
						{
							sprintf (tempBuffer, "%s%c%ldM ", WPrefs->wp_VolName [VolCount], Direction,
										bytesLeft / 1048576);
						}
						else
						{
							sprintf (tempBuffer, "%s%ldM ", WPrefs->wp_VolName [VolCount],
										bytesLeft / 1048576);
						}
						break;
					}
					case VAUTO :
					{
						if (bytesLeft < 10240)
						{
							/*-------------------*/
							/* Display in bytes. */
							/*-------------------*/
							if (WPrefs->wp_VolumeFreeDirection)
							{
								sprintf (tempBuffer, "%s%c%ld ", WPrefs->wp_VolName [VolCount], Direction,
																			bytesLeft);
							}
							else
							{
								sprintf (tempBuffer, "%s%ld ", WPrefs->wp_VolName [VolCount], bytesLeft);
							}
							break;
						}
						else
						{
							/*-----------------------*/
							/* Display in kilobytes. */
							/*-----------------------*/
							if (bytesLeft < 10485760)
							{
								if (WPrefs->wp_VolumeFreeDirection)
								{
									sprintf (tempBuffer, "%s%c%ldK ", WPrefs->wp_VolName [VolCount], Direction,
												bytesLeft / 1024);
								}
								else
								{
									sprintf (tempBuffer, "%s%ldK ", WPrefs->wp_VolName [VolCount],
												bytesLeft / 1024);
								}
								break;
							}
							else
							{
								/*-----------------------*/
								/* Display in megabytes. */
								/*-----------------------*/
								if (WPrefs->wp_VolumeFreeDirection)
								{
									sprintf (tempBuffer, "%s%c%ldM ", WPrefs->wp_VolName [VolCount], Direction,
												bytesLeft / 1048576);
								}
								else
								{
									sprintf (tempBuffer, "%s%ldM ", WPrefs->wp_VolName [VolCount],
												bytesLeft / 1048576);
								}
								break;
							}
						}
					}
				}
				strcat (Buffer, tempBuffer);
			}
			else
			{
				/*----------------------------------------------------*/
				/* Info() NOT OK. This could happen if the volume was */
				/* removed, in which case we need to let go of our		*/
				/* lock on the volume.											*/
				/*----------------------------------------------------*/
				if (VolumeLock [VolCount])
				{
					UnLock (VolumeLock [VolCount]);
					VolumeLock [VolCount] = NULL;
				}
			}
		}

		/*---------------------*/
		/* Go for next volume. */
		/*---------------------*/
		VolCount++;
	}

	/*----------------------------*/
	/* Checking for boolean args. */
	/*----------------------------*/
	if (WPrefs->wp_Total)
	{
		sprintf (tempBuffer, "T:%ld ", fastMem + chipMem);
		strcat (Buffer, tempBuffer);
	}
	if (WPrefs->wp_Fast)
	{
		sprintf (tempBuffer, "F:%ld ", fastMem);
		strcat (Buffer, tempBuffer);
	}
	if (WPrefs->wp_Chip)
	{
		sprintf (tempBuffer, "C:%ld ", chipMem);
		strcat (Buffer, tempBuffer);
	}
	if (WPrefs->wp_Largest)
	{
		sprintf (tempBuffer, "L:%ld ", largest);
		strcat (Buffer, tempBuffer);
	}
	if (WPrefs->wp_LargestFast)
	{
		sprintf (tempBuffer, "LF:%ld ", fastLargest);
		strcat (Buffer, tempBuffer);
	}
	if (WPrefs->wp_LargestChip)
	{
		sprintf (tempBuffer, "LC:%ld ", chipLargest);
		strcat (Buffer, tempBuffer);
	}
	if ((WPrefs->wp_DayOfWeek) || (WPrefs->wp_Date) || (WPrefs->wp_Time))
	{
		if (DateStamp (&ds))
		{
			dt.dat_Stamp.ds_Days		= ds.ds_Days;
			dt.dat_Stamp.ds_Minute	= ds.ds_Minute;
			dt.dat_Stamp.ds_Tick		= ds.ds_Tick;
			switch (WPrefs->wp_DateFormat)
			{
				case 0 :									// dd-mm-yy
				case 1 :
				{
					dt.dat_Format		= FORMAT_CDN;
					break;
				}
				case 2 :									// mm-dd-yy
				case 3 :
				{
					dt.dat_Format		= FORMAT_USA;
					break;
				}
			}				
			dt.dat_Flags				= DTB_SUBST;
			dt.dat_StrDay				= dayBuffer;
			dt.dat_StrDate				= dateBuffer;
			dt.dat_StrTime				= timeBuffer;
			if (DateToStr (&dt))
			{
				if (WPrefs->wp_DayOfWeek)
				{
					sprintf (tempBuffer, "%s ", dayBuffer);
					strcat (Buffer, tempBuffer);
				}
				if (WPrefs->wp_Date)
				{
					/*--------------------------------------------*/
					/* Check if we need to exchange '-' with '/'. */
					/*--------------------------------------------*/
					if (WPrefs->wp_DateFormat == 1 || WPrefs->wp_DateFormat == 3)
					{
						UWORD kurt = strlen (dateBuffer);
						while (kurt--)
						{
							if (dateBuffer [kurt] == '-')
							{
								dateBuffer [kurt] = '/';
							}
						}
					}
					sprintf (tempBuffer, "%s ", dateBuffer);
					strcat (Buffer, tempBuffer);
				}
				if (WPrefs->wp_Time)
				{
					if (!WPrefs->wp_TimeFormat24)
					{
						UBYTE	h [3];
						UWORD hnum;

						h [0] = timeBuffer [0];
						h [1] = timeBuffer [1];
						h [2] = '\0';
						hnum = atoi (h);
						if (hnum > 12)
						{
							hnum -= 12;
							sprintf (tempBuffer, "%ld:%spm", hnum, &timeBuffer [3]);
						}
						else
						{
							sprintf (tempBuffer, "%sam", timeBuffer);
						}
					}
					else
					{
						sprintf (tempBuffer, "%s ", timeBuffer);
					}
					strcat (Buffer, tempBuffer);
				}
			}
		}
	}
	if (WPrefs->wp_Cpu)
	{
		// Not implemented.
	}
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              OpenLibs()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void OpenLibs (void)
{
	/*---------------------------*/
	/* Opening graphics.library. */
	/*---------------------------*/
	if (!(GfxBase = OpenLibrary ("graphics.library", 37L)))
	{
		CleanExit (RETURN_FAIL, (ULONG) "Fatal Error: Couldn't open graphics.library V37.", 0);
	}

	/*----------------------------*/
	/* Opening intuition.library. */
	/*----------------------------*/
	if (!(IntuitionBase = (struct IntuitionBase *)
								 OpenLibrary ("intuition.library", 37L)))
	{
		CleanExit (RETURN_FAIL, (ULONG) "Fatal Error: Couldn't open intuition.library V37.", 0);
	}

	/*--------------------------------------------------------------------*/
	/* Opening locale.library. This library might not be there using V37! */
	/*--------------------------------------------------------------------*/
	LocaleBase = OpenLibrary ("locale.library", 0L);

	/*--------------------------*/
	/* Opening utility.library. */
	/*--------------------------*/
	if (!(UtilityBase = OpenLibrary ("utility.library", 37L)))
	{
		CleanExit (RETURN_FAIL, M_NO_UTILITY_LIBRARY, 0);
	}

	/*----------------------------*/
	/* Opening workbench.library. */
	/*----------------------------*/
	if (!(WorkbenchBase = OpenLibrary ("workbench.library", 37L)))
	{
		CleanExit (RETURN_FAIL, M_NO_WORKBENCH_LIBRARY, 0);
	}

	/*-----------------------*/
	/* Opening icon.library. */
	/*-----------------------*/
	if (!(IconBase = OpenLibrary ("icon.library", 37L)))
	{
		CleanExit (RETURN_FAIL, M_NO_ICON_LIBRARY, 0);
	}

	/*---------------------------*/
	/* Opening gadtools.library. */
	/*---------------------------*/
	if (!(GadToolsBase = OpenLibrary ("gadtools.library", 37L)))
	{
		CleanExit (RETURN_FAIL, M_NO_GADTOOLS_LIBRARY, 0);
	}

	/*---------------------------*/
	/* Opening diskfont.library. */
	/*---------------------------*/
	if (!(DiskfontBase = OpenLibrary ("diskfont.library", 37L)))
	{
		CleanExit (RETURN_FAIL, M_NO_DISKFONT_LIBRARY, 0);
	}

	/*------------------------------*/
	/* Opening commodities.library. */
	/*------------------------------*/
	if (!(CxBase = OpenLibrary ("commodities.library", 37L)))
	{
		CleanExit (RETURN_FAIL, M_NO_COMMODITIES_LIBRARY, 0);
	}

	/*----------------------*/
	/* Opening asl.library. */
	/*----------------------*/
	if (!(AslBase = OpenLibrary ("asl.library", 37L)))
	{
		CleanExit (RETURN_FAIL, M_NO_ASL_LIBRARY, 0);
	}

	if (V39)
	{
		/*---------------------------*/
		/* Opening iffparse.library. */
		/*---------------------------*/
		if (!(IFFParseBase = OpenLibrary ("iffparse.library", 39L)))
		{
			CleanExit (RETURN_FAIL, M_NO_IFFPARSE_LIBRARY, 0);
		}

		/*----------------------------*/
		/* Opening datatypes.library. */
		/*----------------------------*/
		if (!(DataTypesBase = OpenLibrary ("datatypes.library", 39L)))
		{
			CleanExit (RETURN_FAIL, M_NO_DATATYPES_LIBRARY, 0);
		}
	}

	/*-----------------------------*/
	/* Opening amigaguide.library. */
	/*-----------------------------*/
	if (!(AmigaGuideBase = OpenLibrary ("amigaguide.library", 34L)))
	{
		UBYTE *x = XGetString (M_WARNING);
		Inform (WindowPtr, x, "%s", XGetString (M_NO_AMIGAGUIDE_LIBRARY));
		AmigaGuideBase = NULL;
	}

	/*----------------------------------*/
	/* Allocate memory for preferences. */
	/*----------------------------------*/
	if (mem_pool_ok)
	{
		if (!(WPrefs = AllocPooled (mem_pool, sizeof (struct WPrefs))))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
	}
	else
	{
		if (!(WPrefs = AllocVec (sizeof (struct WPrefs), MEMF_ANY | MEMF_CLEAR)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
	}

	/*--------------------------*/
	/* Setup/Init notification. */
	/*--------------------------*/
	if (!(SetupPrefsNotification ()))
	{
		CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
	}

	/*--------------------------*/
	/* Read in the preferences. */
	/*--------------------------*/
	if (!(ReadPrefs (ENVPrefsName, TRUE)))
	{
		if (!(ReadPrefs (ENVARCPrefsName, TRUE)))
		{
			UBYTE *z = XGetString (M_ERROR);
			Inform (WindowPtr, z, "%s", XGetString (M_CANT_FIND_PREFS));
			UsePrefsDefaults ();
		}
	}

	/*----------------------------*/
	/* Opening localized catalog. */
	/*----------------------------*/
	if (LocaleBase)
	{
		catalog = OpenCatalog (NULL, "Watcher.catalog",
									  OC_BuiltInLanguage, "english",
									  OC_Language, WPrefs->wp_Language,
									  TAG_DONE);
	}
	else
	{
		catalog = XOpenCatalog (NULL, "Watcher.catalog",
										OC_BuiltInLanguage, "english",
										OC_Language, WPrefs->wp_Language,
										TAG_DONE);
	}
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              MiscPrep()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void MiscPrep (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	UBYTE *popup;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*--------------------------------*/
	/* Localize cycle gadget strings. */
	/*--------------------------------*/
	strcpy (CycleText [0], XGetString (M_CYCLE_PUBLIC_SCREENS));
	strcpy (CycleText [1], XGetString (M_CYCLE_LIBRARIES));
	strcpy (CycleText [2], XGetString (M_CYCLE_DEVICES));
	strcpy (CycleText [3], XGetString (M_CYCLE_TASKS));
	strcpy (CycleText [4], XGetString (M_CYCLE_PORTS));
	strcpy (CycleText [5], XGetString (M_CYCLE_RESOURCES));
	strcpy (CycleText [6], XGetString (M_CYCLE_FONTS));
	strcpy (CycleText [7], XGetString (M_CYCLE_VOLUMES));
	strcpy (CycleText [8], XGetString (M_CYCLE_ASSIGNS));

	/*----------------------------------------------------------------------*/
	/* Create our message port. We will use this port to communicate to the */
	/* timer.device.																			*/
	/*----------------------------------------------------------------------*/
	if (!(TimerPort = CreateMsgPort ()))
	{
		CleanExit (RETURN_FAIL, M_CANT_CREATE_MESSAGE_PORT, 0);
	}

	/*-----------------------*/
	/* Create timer request. */
	/*-----------------------*/
	if (!(TimerIO = (struct timerequest *)
						 CreateExtIO (TimerPort, sizeof (struct timerequest))))
	{
		CleanExit (RETURN_FAIL, M_CANT_CREATE_TIMER_REQUEST, 0);
	}

	/*------------------------*/
	/* Open the timer.device. */
	/*------------------------*/
	if (OpenDevice ("timer.device", UNIT_VBLANK,
						 (struct IORequest *) TimerIO, 0L))
	{
		CleanExit (RETURN_FAIL, M_CANT_OPEN_TIMER_DEVICE, 0);
	}

	/*---------------*/
	/* Setup broker. */
	/*---------------*/
	if (!(CxSetup (gargc, gargv)))
	{
		CleanExit (RETURN_FAIL, M_CANT_LAUNCH_CX_BROKER, 0);
	}

	/*-----------------------------------*/
	/* Create message port for App Info: */
	/*-----------------------------------*/
	if (!(amp = CreateMsgPort ()))
	{
		CleanExit (RETURN_FAIL, M_CANT_CREATE_MESSAGE_PORT, 0);
	}

	/*---------------------------*/
	/* Allocate memory for dobj: */
	/*---------------------------*/
	if (!(dobj = GetDiskObject (NULL)))
	{
		CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
	}

	/*------------------------------------*/
	/* Allocate memory for our SLB lists. */
	/*------------------------------------*/
	if (!AllocAllLists ())
	{
		CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
	}

	/*--------------------------*/
	/* Reset all our SLB lists. */
	/*--------------------------*/
	ResetAllLists ();

	/*------------------------------*/
	/* Allocate memory for buffers. */
	/*------------------------------*/
	if (V39)
	{
		if (!(Asldir = AllocPooled (mem_pool, 128)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(Aslfile = AllocPooled (mem_pool, 128)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(DisplayBuf = AllocPooled (mem_pool, 512)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(ResultDir = AllocPooled (mem_pool, 128)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(ResultFile = AllocPooled (mem_pool, 128)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(ResultPath = AllocPooled (mem_pool, 256)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(VersionBuf = AllocPooled (mem_pool, 160)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
	}
	else
	{
		if (!(Asldir = AllocVec (128, MEMF_ANY | MEMF_PUBLIC)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(Aslfile = AllocVec (128, MEMF_ANY | MEMF_PUBLIC)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(DisplayBuf = AllocVec (512,MEMF_ANY | MEMF_PUBLIC)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(ResultDir = AllocVec (128, MEMF_ANY | MEMF_PUBLIC)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(ResultFile = AllocVec (128, MEMF_ANY | MEMF_PUBLIC)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(ResultPath = AllocVec (256, MEMF_ANY | MEMF_PUBLIC)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
		if (!(VersionBuf = AllocVec (160, MEMF_ANY | MEMF_PUBLIC)))
		{
			CleanExit (RETURN_FAIL, NULL, ERROR_NO_FREE_STORE);
		}
	}

	/*------------*/
	/* Init dobj: */
	/*------------*/
	dobj->do_Gadget.Width			= appimage.Width;
	dobj->do_Gadget.Height			= appimage.Height;
	dobj->do_Gadget.GadgetRender	= &appimage;
	dobj->do_CurrentX					= WPrefs->wp_AppInfoLeftEdge;
	dobj->do_CurrentY					= WPrefs->wp_AppInfoTopEdge;

	/*--------------------------------------------*/
	/* First we must check the state of CX_POPUP. */
	/*--------------------------------------------*/
	if (!(tt = ArgArrayInit (gargc, gargv)))
	{
		HideMode = FALSE;
		goto dontmind;
	}

	/*-----------------*/
	/* Check CX_POPUP. */
	/*-----------------*/
	popup = ArgString (tt, "CX_POPUP", NULL);

	/*-----------------------------------------*/
	/* Determine if we should open our window. */
	/*-----------------------------------------*/
	if (!stricmp (popup, "no"))
	{
		HideMode = TRUE;
	}
	else
	{
		HideMode = FALSE;
	}

	/*------------------------------------*/
	/* Don't need the tooltypes any more. */
	/*------------------------------------*/
	ArgArrayDone ();

 dontmind:

	/*-----------------------------------------*/
	/* Check if we should launch App Info now. */
	/*-----------------------------------------*/
	if ((WPrefs->wp_AppInfoAutoStart) && (HideMode == FALSE))
	{
		/*----------------------------------*/
		/* Add the application icon to the. */
		/*----------------------------------*/
		if (!(ai = AddAppIconA (1, 0, "App Info", amp, NULL, dobj, NULL)))
		{
			Inform (Win, "Error:", "%s", XGetString (M_CANT_LAUNCH_APPINFO));
		}
		AppInfoActive = TRUE;
	}
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              CleanExit()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void CleanExit (WORD ExitCode, ULONG LocaleNum, ULONG DosExitCode)
{
	/*-----------------------*/
	/* Remove notifications. */
	/*-----------------------*/
	if (NotifyList)
	{
		RemovePrefsNotification ();
	}

	/*------------------------------------------*/
	/* UnLocking all previously locked volumes. */
	/*------------------------------------------*/
	if (WPrefs)
	{
		VolCount = 0;

		while ((WPrefs->wp_VolName [VolCount] [0] != '\0') && (VolCount <= WPrefs->wp_VolCount))
		{
			if (VolumeLock [VolCount])
			{
				UnLock (VolumeLock [VolCount]);
			}
			VolCount++;
		}
	}

	/*-----------------------------------------*/
	/* Freeing timer.device related resources. */
	/*-----------------------------------------*/
	if (TimerIO)
	{
		if (!(CheckIO ((struct IORequest *) TimerIO)))
		{
			AbortIO ((struct IORequest *) TimerIO);
		}
		CloseDevice ((struct IORequest *) TimerIO);
		DeleteExtIO ((struct IORequest *) TimerIO);
	}

	/*---------------------------------------*/
	/* Freeing all window related resources. */
	/*---------------------------------------*/
	if (Win)
	{
		DeAllocateWindow ();
	}

	/*-----------------------------------------*/
	/* Deleting message port for timer.device. */
	/*-----------------------------------------*/
	if (TimerPort)
	{
		DeleteMsgPort (TimerPort);
	}

	/*--------------------------------*/
	/* Free disk object for App Info: */
	/*--------------------------------*/
	if (dobj)
	{
		FreeDiskObject (dobj);
	}

	/*---------------------------------*/
	/* Remove AppIcon if it is active. */
	/*---------------------------------*/
	if (AppInfoActive && ai)
	{
		RemoveAppIcon (ai);
		ai = NULL;
		AppInfoActive = FALSE;
	}

	/*-------------------------------*/
	/* Deleting message port for Cx. */
	/*-------------------------------*/
	CxShutDown ();

	/*--------------------------------------*/
	/* Deleteing message port for App Info: */
	/*--------------------------------------*/
	if (amp)
	{
		DeleteMsgPort (amp);
	}

	/*----------------------------------*/
	/* Displaying error text if wanted. */
	/*----------------------------------*/
	if (LocaleNum)
	{
		UBYTE *x = XGetString (M_ERROR);
		Inform (WindowPtr, x, XGetString (LocaleNum), NULL);
	}
	else
	{
		UBYTE *x = XGetString (M_ERROR);
		if (DosExitCode)
		{
			UBYTE errbuf [256];
			if (Fault (DosExitCode, NULL, errbuf, 256))
			{
				Inform (WindowPtr, x, errbuf, NULL);
			}
		}
	}

	if (UtilityBase)
	{
		CloseLibrary (UtilityBase);
	}
	if (IconBase)
	{
		CloseLibrary (IconBase);
	}
	if (WorkbenchBase)
	{
		CloseLibrary (WorkbenchBase);
	}
	if (GfxBase)
	{
		CloseLibrary (GfxBase);
	}
	if (IntuitionBase)
	{
		CloseLibrary ((struct Library *) IntuitionBase);
	}
	if (GadToolsBase)
	{
		CloseLibrary (GadToolsBase);
	}
	if (DiskfontBase)
	{
		CloseLibrary (DiskfontBase);
	}
	if (IFFParseBase)
	{
		CloseLibrary (IFFParseBase);
	}
	if (DataTypesBase)
	{
		CloseLibrary (DataTypesBase);
	}
	if (CxBase)
	{
		CloseLibrary (CxBase);
	}
	if (LocaleBase)
	{
		if (catalog)
		{
			CloseCatalog (catalog);
		}
		CloseLibrary (LocaleBase);
	}
	else
	{
		if (catalog)
		{
			XCloseCatalog (catalog);
		}
	}
	if (AslBase)
	{
		CloseLibrary (AslBase);
	}
	if (AmigaGuideBase)
	{
		CloseLibrary (AmigaGuideBase);
	}

	/*------------------------------*/
	/* Free all nodes in all lists. */
	/*------------------------------*/
	RemAllNodes ();
	FreeAllLists ();

	/*-----------------------------*/
	/* Yo! Free ALLLLL the memory. */
	/*-----------------------------*/
	if (mem_pool_ok)
	{
		DeletePool (mem_pool);						// This free everything in the pool.
	}
	else
	{
		if (Asldir)
		{
			FreeVec (Asldir);
		}
		if (Aslfile)
		{
			FreeVec (Aslfile);
		}
		if (DisplayBuf)
		{
			FreeVec (DisplayBuf);
		}
		if (ResultDir)
		{
			FreeVec (ResultDir);
		}
		if (ResultFile)
		{
			FreeVec (ResultFile);
		}
		if (ResultPath)
		{
			FreeVec (ResultPath);
		}
		if (VersionBuf)
		{
			FreeVec (VersionBuf);
		}
		if (WPrefs)
		{
			FreeVec (WPrefs);
		}
	}

	/*-----------------------------*/
	/* Restore our window pointer. */
	/*-----------------------------*/
	p->pr_WindowPtr = WindowPtr;

	/*------------------------------------*/
	/* Exiting with correct return value. */
	/*------------------------------------*/
	exit (ExitCode);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              MakeMenu()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void MakeMenu (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	ULONG				MenuError = 0;
	struct NewMenu NewMenu [] =								// the user field of the menu, so
	{																	// that we can use it to call AG.
		NM_TITLE,	"Project",					NULL,	0,	NULL,	0L,
			NM_ITEM,	"About",						"A",	0,	NULL,	V(MCMD_ABOUT),
			NM_ITEM,	"Jump",						"J",	0,	NULL,	V(MCMD_JUMP),
			NM_ITEM,	NM_BARLABEL,				NULL,	0,	NULL,	0L,
			NM_ITEM, "WatcherPrefs",         "P",  0, NULL, V(MCMD_WATCHERPREFS),
			NM_ITEM,	NM_BARLABEL,				NULL,	0,	NULL,	0L,
			NM_ITEM,	"Hide",						"H",	0,	NULL,	V(MCMD_HIDE),
			NM_ITEM, NM_BARLABEL,				NULL,	0,	NULL,	0L,
			NM_ITEM,	"Quit",						"Q",	0,	NULL,	V(MCMD_QUIT),
		NM_TITLE,	"Utilities",				NULL, 0,	NULL,	0L,
			NM_ITEM,	"System List Browser",	"B",	0,	NULL,	V(MCMD_SLB),
			NM_ITEM, "App Info",					"I",	0,	NULL,	V(MCMD_APPINFO),
		NM_END,		0,								NULL,	0,	NULL,	0L
	};

	/*---------*/
	/* C O D E */
	/*---------*/
	NewMenu  [0].nm_Label	= XGetString (M_MENU_SLB_PROJECT);
	NewMenu  [1].nm_Label	= XGetString (M_MENU_SLB_ABOUT);
	NewMenu  [1].nm_CommKey	= XGetString (M_MENU_SLB_ABOUT_SC);
	NewMenu  [2].nm_Label	= XGetString (M_MENU_JUMP);
	NewMenu  [2].nm_CommKey	= XGetString (M_MENU_JUMP_SC);
	NewMenu  [6].nm_Label	= XGetString (M_MENU_HIDE);
	NewMenu  [6].nm_CommKey	= XGetString (M_MENU_HIDE_SC);
	NewMenu  [8].nm_Label	= XGetString (M_MENU_SLB_QUIT);
	NewMenu  [8].nm_CommKey	= XGetString (M_MENU_SLB_QUIT_SC);
	NewMenu  [9].nm_Label	= XGetString (M_MENU_UTILITIES);
	NewMenu [10].nm_Label	= XGetString (M_MENU_SLB_SLB);
	NewMenu [10].nm_CommKey	= XGetString (M_MENU_SLB_SLB_SC);

	/*------------------*/
	/* Create the menu. */
	/*------------------*/
	if (!(Menus = CreateMenus (NewMenu,
										GTMN_NewLookMenus,	TRUE,
										GTMN_FullMenu,			TRUE,
										GTMN_SecondaryError,	&MenuError)))
	{
		/*-----------------------------*/
		/* We examine what went wrong. */
		/*-----------------------------*/
		switch (MenuError)
		{
			case GTMENU_NOMEM :
			{
				CleanExit (RETURN_FAIL, M_NO_MEMORY_FOR_MENU, 0);
				break;
			}
			default :
			{
				CleanExit (RETURN_FAIL, M_UNABLE_TO_CREATE_MENU, 0);
				break;
			}
		}
	}
	LayoutMenus (Menus, VisualInfo,
					 GTMN_NewLookMenus, TRUE,
					 TAG_DONE);
	SetMenuStrip (Win, Menus);
	GT_RefreshWindow (Win, NULL);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                           OpenWindowTags()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
struct Window *OpenWindowTags (struct NewWindow *nw, ULONG tags, ...)
{
	/*------------------------------------------*/
	/* Stack based stub for OpenWindowTagList() */
	/*------------------------------------------*/
	return (OpenWindowTagList(nw, (struct TagItem *)&tags));
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             CreateMenus()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
struct Menu *CreateMenus (struct NewMenu *newmenu, Tag tag1, ...)
{
	/*-------------------------------------*/
	/* Stack based stub for CreateMenusA() */
	/*-------------------------------------*/
	return (CreateMenusA (newmenu, (struct TagItem *) &tag1));
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             LayoutMenus()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
BOOL LayoutMenus (struct Menu *firstmenu, APTR vi, Tag tag1, ...)
{
	/*-------------------------------------*/
	/* Stack based stub for LayoutMenusA() */
	/*-------------------------------------*/
	return (LayoutMenusA (firstmenu, vi, (struct TagItem *) &tag1));
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              NewObject()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
APTR NewObject (struct IClass *classPtr, UBYTE *classID, ULONG tag1, ...)
{
	/*-----------------------------------*/
	/* Stack based stub for NewObjectA() */
	/*-----------------------------------*/
	return (NewObjectA (classPtr, classID, (struct TagItem *) &tag1));
}
