//
// IDCMP.c -- Function related to IDCMP handling.
//
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                            I N C L U D E S									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
#include <exec/types.h>								// For UBYTE etc.
#include <exec/memory.h>							// For MEMF_ANY etc.
#include <clib/amigaguide_protos.h>				// Protos for OpenAmigaGuideA() etc.
#include <clib/datatypes_protos.h>				// Protos for ObtainDataTypeA() etc.
#include <clib/dos_protos.h>						// Protos for SystemTagList() etc.
#include <clib/exec_protos.h>						// Protos for ReplyMsg() etc.
#include <clib/gadtools_protos.h>				// Protos for GT_ReplyIMsg() etc.
#include <clib/intuition_protos.h>				// Protos for CloseScreen() etc.
#include <clib/wb_protos.h>						// Protos for AddAppIconA() etc.
#include <ctype.h>									// For toupper() macros etc.
#include <datatypes/datatypesclass.h>			// For GID_PICTURE etc.
#include <intuition/intuition.h>					// For IDCMP_CLOSEWINDOW etc.
#include <libraries/gadtools.h>					// For MENU_USERDATA etc.
#include <pragmas/amigaguide_pragmas.h>		// Pragmas for amigaguide.librar.
#include <pragmas/datatypes_pragmas.h>			// Pragmas for datatypes.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/intuition_pragmas.h>			// Pragmas for intuition.library.
#include <pragmas/wb_pragmas.h>					// Pragmas for workbench.library.
#include <stdio.h>									// Protos for sprintf() etc.
#include <string.h>									// Protos for strcpy() etc.
#include <workbench/startup.h>					// For struct WBArg etc.

#include "/include/Catalog.h"						// V37 compatible locale.
#define CATCOMP_NUMBERS
#include "/include/Watcher_strings.h"			// All strings used in Watcher.

#include "/include/Defines.h"						// For GD_JUMPSCR etc.
#include "/include/Nodes.h"						// For struct MyScrList etc.
#include "/include/Prefs.h"						// For struct WPrefs etc.
#include "Watcher.h"									// For DATE define.

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             I M P O R T S										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*------------*/
/* Variables: */
/*------------*/
extern struct Library			*AmigaGuideBase;	// amigaguide.library.
extern struct Library			*DataTypesBase;	// datatypes.library.
extern struct DosLibrary		*DOSBase;			// do.
extern struct Library			*GadToolsBase;		// gadtools.library.
extern struct IntuitionBase	*IntuitionBase;	// intuition.library
extern struct Library			*WorkbenchBase;	// workbench.library.
extern struct WPrefs				*WPrefs;				// Watcher preferences struct.
extern struct Screen				*NextPubScr;		// Next public screen.
extern BOOL							KeepWinPos;			// Used when jumping screens.
extern struct Window				*Win;					// Watcher window.
extern struct Requester			SleepReq;			// For sleepy windows.
extern ULONG						SLBidcmpSignals;	// IDCMP signals for SLB window.
extern struct Window				*SLBWin;				// System List Browser window.
extern BOOL							AppInfoActive;		// Is App Info running?
extern struct AppIcon			*ai;
extern struct MsgPort			*amp;					// Message port for App Info.
extern struct DiskObject		*dobj;				// Disk Object for App Info.
extern struct Menu				*Menus;				// do.
extern AMIGAGUIDECONTEXT		ag_AmigaGuide;		// Pointer to AmigaGuide context.
extern UBYTE						*Asldir;				// Asl cached directory.
extern UBYTE						*Aslfile;			// Asl cached file.
extern UBYTE						*DisplayBuf;		// [512];
extern UBYTE						*ResultDir;			// [128];
extern UBYTE						*ResultFile;		// [128];
extern UBYTE						*ResultPath;		// [256];
extern UBYTE						*VersionBuf;		// [160];
extern BOOL							V39;					// Are we running V39+ ?
extern UWORD						DisplayType;
extern struct List				*MyScrList;
extern struct List				*MyLibList;
extern struct List				*MyDevList;
extern struct List				*MyTskList;
extern struct List				*MyPrtList;
extern struct List				*MyResList;
extern struct List				*MyFntList;
extern struct List				*MyVolList;
extern struct List				*MyAssList;
extern struct Requester			SleepReq2;
extern struct Menu				*SLBMenus;			// Menu for SLB.
extern struct Gadget				*SLBGads [GADMAX];// Gadget pointer array.
extern BOOL							ag_Available;

/*------------*/
/* Functions: */
/*------------*/
extern struct Screen	*AbleToJumpScr				(void);
extern void				JumpToNextScr				(void);
extern BOOL				Inform						(struct Window *w, STRPTR Title,
															 STRPTR Text, APTR args, ...);
extern BOOL				SleepWindow					(struct Window *w, struct Requester *r);
extern void				About							(void);
extern void				WakeUpWindow				(struct Window *w, struct Requester *r);
extern void				SystemListBrowserInit	(void);
extern BOOL				Ask							(struct Window *w, STRPTR Title, STRPTR Text,
															 STRPTR GadText, APTR args, ...);
extern BOOL				LoadAFile					(UBYTE *dir, UBYTE *file,
															 UBYTE *resultdir, UBYTE *resultfile);
extern BOOL				VersionSearch				(UBYTE *filename, LONG filelen, UBYTE *versionbuffer);
extern void				GetDataTypeString			(struct DataType *dt, UBYTE *strbuf);
extern Object			*GetPictureInfo			(struct DataType *dt, BPTR fileLock, UBYTE *infoBuf);
extern void				DisplayPicture				(struct DataType *dt, Object *o);
extern void				SystemListBrowserExit	(void);
extern void				UpdateScrList				(BOOL Full);
extern void				UpdateLibList				(BOOL Full);
extern void				UpdateDevList				(BOOL Full);
extern void				UpdateTskList				(BOOL Full);
extern void				UpdatePrtList				(BOOL Full);
extern void				UpdateResList				(BOOL Full);
extern void				UpdateFntList				(BOOL Full);
extern void				UpdateVolList				(BOOL Full);
extern void				UpdateAssList				(BOOL Full);
extern BOOL				EmptyList					(struct List *list);
extern struct Node 	*GetNodeNum					(struct List *l, ULONG num);
extern void				CreateSLBGadgets			(void);
extern void				FreeSLBGadgets				(void);
extern void				CollectScrList				(void);
extern void				CollectLibList				(void);
extern void				CollectDevList				(void);
extern void				CollectTskList				(void);
extern void				CollectPrtList				(void);
extern void				CollectResList				(void);
extern void				CollectFntList				(void);
extern void				CollectVolList				(void);
extern void				RemAllNodes					(void);
extern void				DeAllocateWindow			(void);

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                         HandleWatcherIDCMP()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
ULONG HandleWatcherIDCMP (ULONG class, UWORD code, APTR iaddress)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	UBYTE					*inf = XGetString (M_INFORMATION);
	UBYTE					*err = XGetString (M_ERROR);
	UBYTE					*war = XGetString (M_WARNING);
	struct Gadget		*g;
	ULONG					id;
	ULONG					menunum, itemnum;			// Selection vars.
	UWORD					selection;
	BOOL					MultipleMenu = TRUE;
	struct MenuItem	*item;						// As returned by ItemAddress().

	/*---------*/
	/* C O D E */
	/*---------*/
	switch (class)
	{
		/*------------------------------------------*/
		/* We check if user wanted to shut us down. */
		/*------------------------------------------*/
		case IDCMP_CLOSEWINDOW :
		{
			return (0);
		}

		/*---------------------*/
		/* Jumping screens :-) */
		/*---------------------*/
		case IDCMP_GADGETUP :
		{
			/*-----------------------------------------------*/
			/* But only if the NOJUMPGADGET isn't specified. */
			/*-----------------------------------------------*/
			if (!(WPrefs->wp_NoJumpGadget))
			{
				g = (struct Gadget *) iaddress;
				id = g->GadgetID;

				switch (id)
				{
					case GD_JUMPSCR :
					{
						/*------------------------------------------*/
						/* 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.							 */
							/*-----------------------------------------*/
							Inform (Win, inf, "%s", XGetString (M_NO_OTHER_PUBSCREENS));
						}
						break;
					}
					default :
					{
						break;
					}
				}
			}
			break;
		}

		/*--------------------------*/
		/* User choose a menu item. */
		/*--------------------------*/
		case IDCMP_MENUPICK :
		{
			selection = code;
			MultipleMenu = TRUE;
			while (selection != MENUNULL)
			{
				/*------------------------------------*/
				/* Get menu number and item selected. */
				/*------------------------------------*/
				menunum = MENUNUM (selection);
				itemnum = ITEMNUM (selection);

				/*-------------*/
				/* Which menu? */
				/*-------------*/
				switch (menunum)
				{
					case 0 :								// Project.
					{
						switch (itemnum)
						{
							case 0 :						// About.
							{
								SleepWindow (Win, &SleepReq);
								About ();
								WakeUpWindow (Win, &SleepReq);
								break;
							}
							case 1 :						// Jump.
							{
								/*------------------------------------------*/
								/* Check if there is another public screen. */
								/*------------------------------------------*/
								if (NextPubScr = AbleToJumpScr ())
								{
									/*-------------------*/
									/* We take the jump! */
									/*-------------------*/
									KeepWinPos = TRUE;
									JumpToNextScr ();
									MultipleMenu = FALSE;
									selection = MENUNULL;
								}
								else
								{
									/*------------------------------------------*/
									/* We inform that there are no other public */
									/* screens available.							  */
									/*------------------------------------------*/
									Inform (Win, inf, "%s", XGetString (M_NO_OTHER_PUBSCREENS));
								}
								break;
							}
							case 3 :						// WatcherPrefs.
							{
								/*---------------------------------------------------*/
								/* Put window to sleep before invoking WatcherPrefs. */
								/*---------------------------------------------------*/
								SleepWindow (Win, &SleepReq);
								if (SystemTagList ("SYS:Prefs/WatcherPrefs", TAG_END))
								{
									Inform (Win, err, "%s", XGetString (M_CANT_FIND_WATCHERPREFS));
								}
								WakeUpWindow (Win, &SleepReq);
								break;
							}
							case 5 :						// Hide.
							{
								/*------------------------------------------*/
								/* Check that the SLB window is not active. */
								/*------------------------------------------*/
								if (!SLBWin)
								{
									/*---------------------------------------------*/
									/* Check if wee need to close our window down. */
									/*---------------------------------------------*/
									if (Win)
									{
										/*--------------------------------------*/
										/* Check if we need to remove App Info. */
										/*--------------------------------------*/
										if (AppInfoActive && ai)
										{
											/*---------------------*/
											/* We remove App Info. */
											/*---------------------*/
											RemoveAppIcon (ai);
											ai = NULL;
											AppInfoActive = FALSE;
										}
										/*-------------------------------*/
										/* We remove our Watcher window. */
										/*-------------------------------*/
										DeAllocateWindow ();
										return (2);
									}
									else
									{
										/*---------------------*/
										/* Window not present. */
										/*---------------------*/
										Inform (NULL, "Watcher:", "%s", XGetString (M_ALREADY_DISABLED));
									}
								}
								else
								{
									/*----------------------------------------------------*/
									/* SLB window active which needs to be removed first. */
									/*----------------------------------------------------*/
									UBYTE *z = XGetString (M_WARNING);
									Inform (NULL, z, "%s", XGetString (M_QUIT_SLB_FIRST));
								}
								break;
							}
							case 7 :						// Quit.
							{
								return (0);
								break;
							}
							default :
							{
								break;
							}
						}
						break;
					}
					case 1 :								// Utilitites.
					{
						switch (itemnum)
						{
							case 0 :						// System List Browser.
							{
								SystemListBrowserInit ();
								SLBidcmpSignals = (1L << SLBWin->UserPort->mp_SigBit);
								break;
							}
							case 1 :						// App Info.
							{
								/*-----------------------------------*/
								/* Check if App Info already active. */
								/*-----------------------------------*/
								if (AppInfoActive)
								{
									Inform (Win, war, "%s", XGetString (M_DOUBLE_CLICK_TO_REMOVE));
								}
								else
								{
									/*----------------------------------*/
									/* Add the application icon to the. */
									/*----------------------------------*/
									if (!(ai = AddAppIconA (1, 0, "App Info", amp, NULL,
																	dobj, NULL)))
									{
										Inform (Win, err, "%s", XGetString (M_CANT_LAUNCH_APPINFO));
									}
									AppInfoActive = TRUE;
								}
							}
						}
						break;
					}
					default :
					{
						break;
					}
				}
				if (MultipleMenu)
				{
					selection = (UWORD) ((struct MenuItem *)
									ItemAddress (Menus,
													 (LONG) selection))->NextSelect;
				}
			}
			break;
		}
		case IDCMP_MENUHELP :
		{
			/*--------------------------------------------*/
			/* Determine item to get AmigaGuide help for. */
			/*--------------------------------------------*/
			if (item = ItemAddress (Win->MenuStrip, code))
			{
				if (AmigaGuideBase)
				{
					/*-------------------*/
					/* Display the node. */
					/*-------------------*/
					SendAmigaGuideCmd (ag_AmigaGuide, NULL,
											 AGA_Context, (LONG) MENU_USERDATA (item),
											 TAG_DONE);
				}
				else
				{
					Inform (Win, war, "%s", XGetString (M_SYSTEM_NOT_AVAILABLE));
				}
			}
			break;
		}
		case IDCMP_RAWKEY :
		{
			/*-------------------------------*/
			/* Act according to key pressed: */
			/*-------------------------------*/
			switch (code)
			{
				case HELP_KEY :
				{
					if (AmigaGuideBase)
					{
						/*--------------------*/
						/* Display help node. */
						/*--------------------*/
						SendAmigaGuideCmd (ag_AmigaGuide, NULL,
												 AGA_Context, 0,
												 TAG_DONE);
					}
					else
					{
						Inform (Win, war, "Warning", "%s", XGetString (M_SYSTEM_NOT_AVAILABLE));
					}
					break;
				}
				case ESC_KEY :
				{
					return (0);
					break;
				}
				case SPACE_KEY :
				{
					SystemListBrowserInit ();
					SLBidcmpSignals = (1L << SLBWin->UserPort->mp_SigBit);
					break;
				}
			}
			break;
		}
		default :
		{
			break;
		}
	}
	return (1);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                           HandleampIDCMP()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
BOOL HandleampIDCMP (struct AppMessage *amsg)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	UBYTE										*err = XGetString (M_ERROR);
	struct DataType						*dt = NULL;
	Object									*o  = NULL;
	UBYTE										datatypeID			[20];

	APTR										filebuf;
	struct FileInfoBlock __aligned	fib;
	BPTR										filelock;
	BPTR										filehandle;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*-------------------------------------------------*/
	/* Check if the appicon was simply double-clicked. */
	/*-------------------------------------------------*/
	if (amsg->am_NumArgs == 0)
	{
		UBYTE *quest = XGetString (M_QUESTION);
		UBYTE *quit  = XGetString (M_MENU_SLB_QUIT);
		UBYTE *load  = XGetString (M_LOAD);
		UBYTE *cancel= XGetString (M_CANCEL);
		UBYTE kurt [40];

		/*-----------------------------------------------------------------*/
		/* No parameters, the user double-clicked the appicon. We put up a */
		/* requester where the user can either 'Quit', 'Load' or 'Cancel'. */
		/*-----------------------------------------------------------------*/
		strcpy (kurt, quit);
		strcat (kurt, "|");
		strcat (kurt, load);
		strcat (kurt, "|");
		strcat (kurt, cancel);
		switch (Ask (Win, quest, "%s", kurt, XGetString (M_APPINFO_REQ1)))
		{
			case 0 :							// Cancel App Info.
			{
				return (FALSE);
				break;
			}
			case 1 :							// Quit App Info.
			{
				/*------------------------------*/
				/* Remove all pending messages. */
				/*------------------------------*/
				ReplyMsg ((struct Message *) amsg);
				while (amsg = (struct AppMessage *) GetMsg (amp))
				{
					ReplyMsg ((struct Message *) amsg);
				}

				/*---------------------*/
				/* Remove the appicon. */
				/*---------------------*/
				RemoveAppIcon (ai);
				ai = NULL;
				AppInfoActive = FALSE;
				return (TRUE);
				break;
			}
			case 2 :
			{
				/*-------------------------*/
				/* Reset result variables. */
				/*-------------------------*/
				ResultDir [0] = '\0';
				ResultFile [0] = '\0';

				/*---------------------------*/
				/* Put up the Asl requester. */
				/*---------------------------*/
				if (LoadAFile (Asldir, Aslfile, ResultDir, ResultFile))
				{
					/*-----------------------------------*/
					/* Buffer result directory and file. */
					/*-----------------------------------*/
					strcpy (Asldir, ResultDir);
					strcpy (Aslfile, ResultFile);

					/*--------------------------*/
					/* Build full path to file. */
					/*--------------------------*/
					strcpy (ResultPath, ResultDir);
					AddPart (ResultPath, ResultFile, 256);
				}
				else
				{
					return (FALSE);
				}
				break;
			}
		}
	}
	else
	{
		/*---------------------------------------*/
		/* Check that we have a valid parameter. */
		/*---------------------------------------*/
		if (amsg->am_ArgList->wa_Name [0] != '\0')
		{
			/*-----------------------------------------------------*/
			/* Check if we can get the name of the directory lock. */
			/*-----------------------------------------------------*/
			if (NameFromLock (amsg->am_ArgList->wa_Lock, ResultPath, 256))
			{
				/*-------------------*/
				/* Build ResultPath. */
				/*-------------------*/
				AddPart (ResultPath, amsg->am_ArgList->wa_Name, 256);
			}
		}
		else
		{
			UBYTE *aa = XGetString (M_INFORMATION);
			UBYTE *bb = XGetString (M_ONLY_REAL_FILES_SUPPORTED);
			Inform (NULL, aa, bb, NULL);
			return (FALSE);
		}
	}

	/*----------------*/
	/* Lock the file. */
	/*----------------*/
	if (filelock = Lock (ResultPath, ACCESS_READ))
	{
		/*------------------------*/
		/* Check with data types. */
		/*------------------------*/
		if (V39)
		{
			/*-------------------------*/
			/* First get the datatype. */
			/*-------------------------*/
			if (!(dt = ObtainDataTypeA (DTST_FILE, (APTR) filelock, NULL)))
			{
				Inform (NULL, err, "%s", XGetString (M_CANT_OBTAIN_DATATYPE));
				strcpy (datatypeID, XGetString (M_UNKNOWN));
			}
			else
			{
				/*---------------------------------------------*/
				/* Get the datatype string, eg. "GIF Picture". */
				/*---------------------------------------------*/
				GetDataTypeString (dt, datatypeID);
			}
		}

		/*---------------------------*/
		/* Get the size of the file. */
		/*---------------------------*/
		if (Examine (filelock, &fib))
		{
			/*----------------------------------*/
			/* Allocate memory for file buffer. */
			/*----------------------------------*/
			if (filebuf = AllocVec (fib.fib_Size, MEMF_ANY | MEMF_CLEAR))
			{
				/*------------*/
				/* Open file. */
				/*------------*/
				if (filehandle = Open (ResultPath, MODE_OLDFILE))
				{
					/*--------------------------------*/
					/* Read the file into our buffer. */
					/*--------------------------------*/
					Read (filehandle, filebuf, fib.fib_Size);

					/*----------------------------------*/
					/* Get the version string (if any). */
					/*----------------------------------*/
					if (!(VersionSearch (filebuf, fib.fib_Size, VersionBuf)))
					{
						strcpy (VersionBuf, XGetString (M_NONE));
					}

					if (V39)
					{
						/*--------------------------------------------------------------------------*/
						/* Further actions depend on the datatypes we support. This is checked now, */
						/* so that we can give the user additional action option on the requester.  */
						/*--------------------------------------------------------------------------*/
						switch (dt->dtn_Header->dth_GroupID)
						{
							case 0 :
							{
								break;
							}
							case GID_PICTURE :
							{
								/*-------------*/
								/* L O C A L S */
								/*-------------*/
								UBYTE buf [40];

								/*-------------------------*/
								/* Get picture dimensions. */
								/*-------------------------*/
								if (o = GetPictureInfo (dt, filelock, buf))
								{
									/*------------------------*/
									/* Build buf for display. */
									/*------------------------*/
									UBYTE *x = XGetString (M_DATATYPE_INFO);
									UBYTE *y = XGetString (M_DISPLAY_CANCEL);
									sprintf (DisplayBuf, x,
												ResultPath, fib.fib_Size, VersionBuf, datatypeID, buf);
									x = XGetString (M_PICTURE_DATATYPE);
									if (Ask (NULL, x, DisplayBuf, y, NULL))
									{
										DisplayPicture (dt, o);
									}
									DisposeDTObject (o);
								}
								break;
							}
							default :
							{
								UBYTE *x = XGetString (M_VERSION_INFO);
								UBYTE *y = XGetString (M_INFORMATION);

								sprintf (DisplayBuf, x, ResultPath, fib.fib_Size, VersionBuf);
								Inform (NULL, y, DisplayBuf, NULL);
							}
						}
					}
					else
					{
						UBYTE *x = XGetString (M_VERSION_INFO);
						UBYTE *y = XGetString (M_INFORMATION);
						sprintf (DisplayBuf, x, ResultPath, fib.fib_Size, VersionBuf);
						Inform (NULL, y, DisplayBuf, NULL);
					}

					/*-------------*/
					/* Close file. */
					/*-------------*/
					Close (filehandle);
				}
				else
				{
					UBYTE *x = XGetString (M_WARNING);
					Inform (Win, x, "%s", XGetString (M_UNABLE_TO_OPEN_FILE));
				}
				FreeVec (filebuf);
			}
			else
			{
				UBYTE *y = XGetString (M_WARNING);
				UBYTE *x = XGetString (M_COULDNT_ALLOCATE_X_MEMORY);
				Inform (Win, y, x, (APTR) &fib.fib_Size);
			}
		}
		UnLock (filelock);
	}
	else
	{
		UBYTE *x = XGetString (M_WARNING);
		UBYTE *y = XGetString (M_UNABLE_TO_OBTAIN_LOCK);
		Inform (Win, x, y, ResultPath);
	}
	return (FALSE);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                           HandleSLBIDCMP()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
BOOL HandleSLBIDCMP (ULONG class, UWORD code, APTR iaddress)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	UBYTE						*updatekeyx	= XGetString (M_UPDATE_C);
	UWORD						updatekey	= updatekeyx [0];
	UBYTE						Buffer [500];
	struct MyScrNode		*scrnode;
	struct MyLibDevNode	*libdevnode;
	struct MyTskNode		*tsknode;
	struct MyPrtNode		*prtnode;
	struct MyResNode		*resnode;
	struct MyFntNode		*fntnode;
	struct MyVolNode		*volnode;
	struct MyAssNode		*assnode;
	ULONG						id2;
	UWORD						selection2;
	ULONG						menunum2, itemnum2;
	struct IntuiMessage	*imsg2;					// Messages from window.

	/*---------*/
	/* C O D E */
	/*---------*/
	switch (class)
	{
		case IDCMP_CLOSEWINDOW :
		{
			/*---------------------------------------------------------*/
			/* First, we need to empty our window userport's messages. */
			/*---------------------------------------------------------*/
			while (imsg2 = GT_GetIMsg (SLBWin->UserPort))
			{
				GT_ReplyIMsg (imsg2);
			}
			SystemListBrowserExit ();
			return (TRUE);
		}
		case IDCMP_GADGETUP :
		{
			id2 = ((struct Gadget *) iaddress)->GadgetID;
			switch (id2)
			{
				case GD_CYCLE :			// Cycle: Type of contents.
				{
					DisplayType = code;
					switch (code)
					{
						case OBJ_SCREEN :
						{
							UpdateScrList (FALSE);
							break;
						}
						case OBJ_LIBRARY :
						{
							UpdateLibList (FALSE);
							break;
						}
						case OBJ_DEVICE :
						{
							UpdateDevList (FALSE);
							break;
						}
						case OBJ_TASK :
						{
							UpdateTskList (FALSE);
							break;
						}
						case OBJ_PORT :
						{
							UpdatePrtList (FALSE);
							break;
						}
						case OBJ_RESOURCE :
						{
							UpdateResList (FALSE);
							break;
						}
						case OBJ_FONT :
						{
							UpdateFntList (FALSE);
							if (EmptyList (MyFntList))
							{
								SleepWindow (SLBWin, &SleepReq2);
								Inform (SLBWin, NULL, "%s", XGetString (M_HIT_UPDATE_FONT));
								WakeUpWindow (SLBWin, &SleepReq2);
							}
							break;
						}
						case OBJ_VOLUME :
						{
							UpdateVolList (FALSE);
							if (EmptyList (MyVolList))
							{
								SleepWindow (SLBWin, &SleepReq2);
								Inform (SLBWin, NULL, "%s", XGetString (M_HIT_UPDATE_VOLUME));
								WakeUpWindow (SLBWin, &SleepReq2);
							}
							break;
						}
						case OBJ_ASSIGN :
						{
							UpdateAssList (FALSE);
							if (EmptyList (MyAssList))
							{
								SleepWindow (SLBWin, &SleepReq2);
								Inform (SLBWin, NULL, "%s", XGetString (M_HIT_UPDATE_ASSIGN));
								WakeUpWindow (SLBWin, &SleepReq2);
							}
							break;
						}
						default :
						{
							break;
						}
					}
					break;
				}
				case GD_LISTVIEW :
				{
					switch (DisplayType)
					{
						case OBJ_SCREEN :
						{
							UBYTE *z = XGetString (M_PUBLIC_SCREEN_INFO);
							int x;

							/*---------------------------------------*/
							/* Get the screen node that was choosen. */
							/*---------------------------------------*/
							scrnode = (struct MyScrNode *)
										 GetNodeNum (MyScrList, code);

							/*--------------------------------*/
							/* Strip blanks at end of string. */
							/*--------------------------------*/
							x = strlen (scrnode->msn_TitName) - 1;
							if (scrnode->msn_TitName [x] == ' ')
							{
								while (scrnode->msn_TitName [x--] == ' ') ;
								if (scrnode->msn_TitName [x + 1] != '\0')
								{
									scrnode->msn_TitName [x + 1] = '\0';
								}
							}
							sprintf (Buffer, z,
										scrnode->msn_PubName,
										scrnode->msn_TitName,
										scrnode->msn_Address,
										scrnode->msn_Box.Width,
										scrnode->msn_Box.Height,
										scrnode->msn_Depth,
										scrnode->msn_Font->ta_Name,
										scrnode->msn_Font->ta_YSize,
										(scrnode->msn_Windows) ? "Yes" : "No",
										(scrnode->msn_Gadgets) ? "Yes" : "No");
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, Buffer, NULL);
							WakeUpWindow (SLBWin, &SleepReq2);
							break;
						}
						case OBJ_LIBRARY :
						{
							UBYTE *z = XGetString (M_LIBRARY_INFO);
							UWORD x;

							/*----------------------------------------*/
							/* Get the library node that was choosen. */
							/*----------------------------------------*/
							libdevnode = (struct MyLibDevNode *)
											 GetNodeNum (MyLibList, code);

							/*-------------------------------*/
							/* Remove trailing '\r' or '\n'. */
							/*-------------------------------*/
							x = strlen (libdevnode->mldn_IdString) - 1;
							while ((libdevnode->mldn_IdString [x] == '\n') ||
									 (libdevnode->mldn_IdString [x] == '\r'))
							{
								x--;
							}
							libdevnode->mldn_IdString [++x] = '\0';

							/*-----------------------------*/
							/* Gather infor for requester. */
							/*-----------------------------*/
							sprintf (Buffer, z,
										libdevnode->mldn_Name,
										libdevnode->mldn_Version,
										libdevnode->mldn_Revision,
										libdevnode->mldn_IdString,
										libdevnode->mldn_OpenCount);
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, Buffer, NULL);
							WakeUpWindow (SLBWin, &SleepReq2);
							break;
						}
						case OBJ_DEVICE :
						{
							UBYTE *z = XGetString (M_DEVICE_INFO);
							UWORD x;

							/*----------------------------------------*/
							/* Get the library node that was choosen. */
							/*----------------------------------------*/
							libdevnode = (struct MyLibDevNode *)
											 GetNodeNum (MyDevList, code);

							/*-------------------------------*/
							/* Remove trailing '\r' or '\n'. */
							/*-------------------------------*/
							x = strlen (libdevnode->mldn_IdString) - 1;
							while ((libdevnode->mldn_IdString [x] == '\n') ||
									 (libdevnode->mldn_IdString [x] == '\r'))
							{
								x--;
							}
							libdevnode->mldn_IdString [++x] = '\0';

							/*-----------------------------*/
							/* Gather infor for requester. */
							/*-----------------------------*/
							sprintf (Buffer, z,
										libdevnode->mldn_Name,
										libdevnode->mldn_Version,
										libdevnode->mldn_Revision,
										libdevnode->mldn_IdString,
										libdevnode->mldn_OpenCount);
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, Buffer, NULL);
							WakeUpWindow (SLBWin, &SleepReq2);
							break;
						}
						case OBJ_TASK :
						{
							UBYTE *z1 = XGetString (M_TASK_INFO_1);
							UBYTE *z2 = XGetString (M_TASK_INFO_2);

							/*----------------------------------------*/
							/* Get the library node that was choosen. */
							/*----------------------------------------*/
							tsknode = (struct MyTskNode *)
										 GetNodeNum (MyTskList, code);

							/*-----------------------------------------------*/
							/* Checking if we're dealing with a CLI process. */
							/*-----------------------------------------------*/
							if (tsknode->mtn_CliProcess)
							{
								LONG stackSize;
								stackSize = tsknode->mtn_Cli.cli_DefaultStack * 4;
								if (stackSize == 0)
								{
									stackSize = 2 * (tsknode->mtn_Upper - tsknode->mtn_Lower);
								}

								sprintf (Buffer, z1,
											tsknode->mtn_Name,
											tsknode->mtn_CliNumber,
											tsknode->mtn_CliCmdName,
											tsknode->mtn_Priority,
											tsknode->mtn_Stack,
											stackSize);
								SleepWindow (SLBWin, &SleepReq2);
								Inform (SLBWin, NULL, Buffer, NULL);
								WakeUpWindow (SLBWin, &SleepReq2);
							}
							else
							{
								sprintf (Buffer, z2,
											tsknode->mtn_Name,
											tsknode->mtn_Priority,
											tsknode->mtn_Stack,
											tsknode->mtn_Lower,
											tsknode->mtn_Upper,
											2 * (tsknode->mtn_Upper - tsknode->mtn_Lower),
											2 * (tsknode->mtn_Upper - tsknode->mtn_Stack));
								SleepWindow (SLBWin, &SleepReq2);
								Inform (SLBWin, NULL, Buffer, NULL);
								WakeUpWindow (SLBWin, &SleepReq2);
							}
							break;
						}
						case OBJ_PORT :
						{
							UBYTE *z = XGetString (M_PORT_INFO);

							/*----------------------------------------*/
							/* Get the library node that was choosen. */
							/*----------------------------------------*/
							prtnode = (struct MyPrtNode *)
										  GetNodeNum (MyPrtList, code);
							sprintf (Buffer, z,
										prtnode->mpn_Name,
										prtnode->mpn_Pri,
										prtnode->mpn_Address,
										prtnode->mpn_SigTask);
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, Buffer, NULL);
							WakeUpWindow (SLBWin, &SleepReq2);
							break;
						}
						case OBJ_RESOURCE :
						{
							UBYTE *z = XGetString (M_RESOURCE_INFO);
							UWORD x;

							/*----------------------------------------*/
							/* Get the library node that was choosen. */
							/*----------------------------------------*/
							resnode = (struct MyResNode *)
										 GetNodeNum (MyResList, code);

							/*-----------------------------------------------------------*/
							/* Check that libnode is valid before doing something to the */
							/* IdString. Not all resource use this node.						 */
							/*-----------------------------------------------------------*/
							if (resnode->mrn_Version)
							{
								/*-------------------------------*/
								/* Remove trailing '\r' or '\n'. */
								/*-------------------------------*/
								x = strlen (resnode->mrn_IdString) - 1;
								while ((resnode->mrn_IdString [x] == '\n') ||
										 (resnode->mrn_IdString [x] == '\r'))
								{
									x--;
								}
								resnode->mrn_IdString [++x] = '\0';

								/*-----------------------------*/
								/* Gather infor for requester. */
								/*-----------------------------*/
								sprintf (Buffer, z,
											resnode->mrn_Name,
											resnode->mrn_Version,
											resnode->mrn_Revision,
											resnode->mrn_IdString,
											resnode->mrn_OpenCount);
								SleepWindow (SLBWin, &SleepReq2);
								Inform (SLBWin, NULL, Buffer, NULL);
								WakeUpWindow (SLBWin, &SleepReq2);
							}
							else
							{
								/*---------------------*/
								/* No additional info. */
								/*---------------------*/
								SleepWindow (SLBWin, &SleepReq2);
								Inform (SLBWin, NULL, "%s", XGetString (M_NO_ADDITIONAL_INFORMATION));
								WakeUpWindow (SLBWin, &SleepReq2);
							}
							break;
						}
						case OBJ_FONT :
						{
							UBYTE *z = XGetString (M_FONT_INFO);

							/*----------------------------------------*/
							/* Get the library node that was choosen. */
							/*----------------------------------------*/
							fntnode = (struct MyFntNode *)
										 GetNodeNum (MyFntList, code);

							sprintf (Buffer, z,
												  fntnode->mfn_Name,
												  fntnode->mfn_tf.tf_YSize,
												  fntnode->mfn_Type,
												  fntnode->mfn_tf.tf_Style,
												  fntnode->mfn_StylesText,
												  fntnode->mfn_tf.tf_Flags,
												  fntnode->mfn_FlagsText,
												  fntnode->mfn_tf.tf_XSize,
												  fntnode->mfn_tf.tf_Baseline,
												  fntnode->mfn_tf.tf_Accessors,
												  fntnode->mfn_tf.tf_LoChar,
												  fntnode->mfn_tf.tf_HiChar,
												  fntnode->mfn_XDPI,
												  fntnode->mfn_YDPI);

							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, Buffer, NULL);
							WakeUpWindow (SLBWin, &SleepReq2);
							break;
						}
						case OBJ_VOLUME :
						{
							UBYTE *z = XGetString (M_VOLUME_INFO);

							/*---------------------------------------*/
							/* Get the volume node that was choosen. */
							/*---------------------------------------*/
							volnode = (struct MyVolNode *)
										 GetNodeNum (MyVolList, code);

							sprintf (Buffer, z,
												  volnode->mvn_Name,
												  volnode->mvn_DevName,
												  volnode->mvn_CrDate,
												  volnode->mvn_Size / (1024 * 1024),
												  volnode->mvn_Size / 1024,
												  volnode->mvn_Size,
												  volnode->mvn_Free / (1024 * 1024),
												  volnode->mvn_Free / 1024,
												  volnode->mvn_Free,
												  //FRH: Here we have a bug for volumes above 240MB.
												  ((volnode->mvn_Free / 1024) * 100) / (volnode->mvn_Size / 1024));
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, Buffer, NULL);
							WakeUpWindow (SLBWin, &SleepReq2);
							break;
						}
						case OBJ_ASSIGN :
						{
							UBYTE *z1 = XGetString (M_ASSIGN_INFO_1);
							UBYTE *z2 = XGetString (M_ASSIGN_INFO_2);

							/*---------------------------------------*/
							/* Get the assign node that was choosen. */
							/*---------------------------------------*/
							assnode = (struct MyAssNode *)
										 GetNodeNum (MyAssList, code);

							if (assnode->man_Late)
							{
								sprintf (Buffer, z1,
													  assnode->man_Name,
													  assnode->man_DirName);
							}
							else
							{
								sprintf (Buffer, z2,
													  assnode->man_Name,
													  assnode->man_DirName);
							}

							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, Buffer, NULL);
							WakeUpWindow (SLBWin, &SleepReq2);
							break;
						}
						break;
					}
					break;
				}
				case GD_BUTTON :
				{
					switch (DisplayType)
					{
						case OBJ_SCREEN :
						{
							UpdateScrList (TRUE);
							break;
						}
						case OBJ_LIBRARY :
						{
							UpdateLibList (TRUE);
							break;
						}
						case OBJ_DEVICE :
						{
							UpdateDevList (TRUE);
							break;
						}
						case OBJ_TASK :
						{
							UpdateTskList (TRUE);
							break;
						}
						case OBJ_PORT :
						{
							UpdatePrtList (TRUE);
							break;
						}
						case OBJ_RESOURCE :
						{
							UpdateResList (TRUE);
							break;
						}
						case OBJ_FONT :
						{
							UpdateFntList (TRUE);
							break;
						}
						case OBJ_VOLUME :
						{
							UpdateVolList (TRUE);
							break;
						}
						case OBJ_ASSIGN :
						{
							UpdateAssList (TRUE);
							break;
						}
						default :
						{
							break;
						}
					}
					break;
				}
			}
			break;
		}
		case IDCMP_NEWSIZE :
		{
			/*-----------------------------------------------------------*/
			/* We remove all the gadgets resize them and add them again. */
			/*-----------------------------------------------------------*/
			FreeSLBGadgets ();
			CreateSLBGadgets ();
			break;
		}
		case IDCMP_MENUPICK :
		{
			selection2 = code;
			while (selection2 != MENUNULL)
			{
				menunum2 = MENUNUM (selection2);
				itemnum2 = ITEMNUM (selection2);

				switch (menunum2)
				{
					case 0 :					// Project.
					{
						switch (itemnum2)
						{
							case 0 :			// Update All Lists
							{
								SleepWindow (SLBWin, &SleepReq2);
								RemAllNodes ();
								CollectScrList ();
								CollectLibList ();
								CollectDevList ();
								CollectTskList ();
								CollectPrtList ();
								CollectResList ();
								CollectFntList ();
								CollectVolList ();
								WakeUpWindow (SLBWin, &SleepReq2);
								break;
							}
							case 1 :			// About.
							{
								UBYTE *z = XGetString (M_SLB_INFO);

								SleepWindow (SLBWin, &SleepReq2);
								Inform (SLBWin, NULL, "%s %s", z, DATE);
								WakeUpWindow (SLBWin, &SleepReq2);
								break;
							}
							case 3 :			// Quit.
							{
								/*---------------------------------------------------------*/
								/* First, we need to empty our window userport's messages. */
								/*---------------------------------------------------------*/
								while (imsg2 = GT_GetIMsg (SLBWin->UserPort))
								{
									GT_ReplyIMsg (imsg2);
								}
								SystemListBrowserExit ();
								return (TRUE);
							}
						}
						break;
					}
				}
				selection2 = (UWORD) ((struct MenuItem *)
								 ItemAddress (SLBMenus, (LONG) selection2))->NextSelect;
			}
			break;
		}
		case IDCMP_REFRESHWINDOW :
		{
			GT_BeginRefresh (SLBWin);
			GT_EndRefresh (SLBWin, TRUE);
			break;
		}
		case IDCMP_VANILLAKEY :
		{
			if (code == 9)								// TAB key.
			{
				/*----------------------------------------------------*/
				/* Up the display type by one and check for overflow. */
				/*----------------------------------------------------*/
				DisplayType++;
				if (DisplayType >= OBJ_MAXOBJS)
				{
					DisplayType = 0;
				}

				/*--------------------------*/
				/* Adjust the cycle gadget. */
				/*--------------------------*/
				GT_SetGadgetAttrs (SLBGads [0], SLBWin, NULL,
										 GTCY_Active, DisplayType,
										 TAG_END);

				/*-------------------------------*/
				/* And display the correct list. */
				/*-------------------------------*/
				switch (DisplayType)
				{
					case OBJ_SCREEN :
					{
						UpdateScrList (FALSE);
						break;
					}
					case OBJ_LIBRARY :
					{
						UpdateLibList (FALSE);
						break;
					}
					case OBJ_DEVICE :
					{
						UpdateDevList (FALSE);
						break;
					}
					case OBJ_TASK :
					{
						UpdateTskList (FALSE);
						break;
					}
					case OBJ_PORT :
					{
						UpdatePrtList (FALSE);
						break;
					}
					case OBJ_RESOURCE :
					{
						UpdateResList (FALSE);
						break;
					}
					case OBJ_FONT :
					{
						UpdateFntList (FALSE);
						if (EmptyList (MyFntList))
						{
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, "%s", XGetString (M_HIT_UPDATE_FONT));
							WakeUpWindow (SLBWin, &SleepReq2);
						}
						break;
					}
					case OBJ_VOLUME :
					{
						UpdateVolList (FALSE);
						if (EmptyList (MyVolList))
						{
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, "%s", XGetString (M_HIT_UPDATE_VOLUME));
							WakeUpWindow (SLBWin, &SleepReq2);
						}
						break;
					}
					case OBJ_ASSIGN :
					{
						UpdateAssList (FALSE);
						if (EmptyList (MyAssList))
						{
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, "%s", XGetString (M_HIT_UPDATE_ASSIGN));
							WakeUpWindow (SLBWin, &SleepReq2);
						}
						break;
					}
					default :
					{
						break;
					}
				}
			}

			if (code == 27)							// ESC key.
			{
				/*---------------------------------------------------------*/
				/* First, we need to empty our window userport's messages. */
				/*---------------------------------------------------------*/
				while (imsg2 = GT_GetIMsg (SLBWin->UserPort))
				{
					GT_ReplyIMsg (imsg2);
				}
				SystemListBrowserExit ();
				return (TRUE);
			}

			if (code == 32)							// SPACE key.
			{
				if (DisplayType == OBJ_MAXOBJS - 1)
				{
					DisplayType = 1;
				}
				else
				{
					DisplayType++;
				}

				switch (code)
				{
					case OBJ_SCREEN :
					{
						UpdateScrList (FALSE);
						break;
					}
					case OBJ_LIBRARY :
					{
						UpdateLibList (FALSE);
						break;
					}
					case OBJ_DEVICE :
					{
						UpdateDevList (FALSE);
						break;
					}
					case OBJ_TASK :
					{
						UpdateTskList (FALSE);
						break;
					}
					case OBJ_PORT :
					{
						UpdatePrtList (FALSE);
						break;
					}
					case OBJ_RESOURCE :
					{
						UpdateResList (FALSE);
						break;
					}
					case OBJ_FONT :
					{
						UpdateFntList (FALSE);
						if (EmptyList (MyFntList))
						{
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, "%s", XGetString (M_HIT_UPDATE_FONT));
							WakeUpWindow (SLBWin, &SleepReq2);
						}
						break;
					}
					case OBJ_VOLUME :
					{
						UpdateVolList (FALSE);
						if (EmptyList (MyVolList))
						{
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, "%s", XGetString (M_HIT_UPDATE_VOLUME));
							WakeUpWindow (SLBWin, &SleepReq2);
						}
						break;
					}
					case OBJ_ASSIGN :
					{
						UpdateAssList (FALSE);
						if (EmptyList (MyAssList))
						{
							SleepWindow (SLBWin, &SleepReq2);
							Inform (SLBWin, NULL, "%s", XGetString (M_HIT_UPDATE_ASSIGN));
							WakeUpWindow (SLBWin, &SleepReq2);
						}
						break;
					}
					default :
					{
						break;
					}
				}
			}

			if ((code == toupper (updatekey)) || (code == tolower (updatekey)))
			{
				switch (DisplayType)
				{
					case OBJ_SCREEN :
					{
						UpdateScrList (TRUE);
						break;
					}
					case OBJ_LIBRARY :
					{
						UpdateLibList (TRUE);
						break;
					}
					case OBJ_DEVICE :
					{
						UpdateDevList (TRUE);
						break;
					}
					case OBJ_TASK :
					{
						UpdateTskList (TRUE);
						break;
					}
					case OBJ_PORT :
					{
						UpdatePrtList (TRUE);
						break;
					}
					case OBJ_RESOURCE :
					{
						UpdateResList (TRUE);
						break;
					}
					case OBJ_FONT :
					{
						UpdateFntList (TRUE);
						break;
					}
					case OBJ_VOLUME :
					case OBJ_ASSIGN :
					{
						UpdateVolList (TRUE);
						UpdateAssList (TRUE);
						break;
					}
					default :
					{
						break;
					}
				}
			}
			break;
		}
		case IDCMP_RAWKEY :
		{
			switch (code)
			{
				case HELP_KEY :
				{
					if (AmigaGuideBase)
					{
						if (ag_Available)
						{
							SendAmigaGuideCmd (ag_AmigaGuide, NULL,
													 AGA_Context, 0,
													 TAG_DONE);
						}
						else
						{
							Inform (SLBWin, NULL, "%s", XGetString (M_NO_GUIDE_FILE_AVAILABLE));
						}
					}
					else
					{
						UBYTE *z = XGetString (M_WARNING);
						Inform (SLBWin, z, "%s", XGetString (M_SYSTEM_NOT_AVAILABLE));
					}
					break;
				}
			}
			break;
		}
		case IDCMP_INTUITICKS :
		{
			break;
		}
	}
	return (FALSE);
}
