/*
 *	$VER:ParM.c - (02.07.95) 18:58:24 Copyright © 1990 by S.R. & P.C.
 *
 *      Created:        01 Jul 1990
 *      Modified:	02 Jul 1995	18:58:24
 *
 *      Make>> smake
 *
 *	17/06/95:
 *		start Add ScreenNotify support.
 *	18/06/95:
 *		clean up source: localise some var.
 *	19/06/95:
 *		remove MYMENU & CLI support. Is there somebody still using it ?. This make src difficult to understand
 * 02/07/95:
 *		ParM don't always reopen its window after screen change. try to fix that by try 10 time to open window
 *		Now handle Ctrl-C and quit
 * 02/16/95:
 *		Now never reopen window, ScreenNotifyTest don't too...search for the pb...
 *		Found the pb. This due of a bug of NewMode 3.6
 */

#include "lib/ParMBase.h"
#include <proto/ParM.h>
#include <retina/retina.h>
#include <proto/retina.h>

#include <Libraries/VMem.h>
#include <proto/VMem.h>

#include "VMM_Stat.h"
#include "pragmas/VMM_pragmas.h"
#include "clib/VMM_protos.h"

#include <libraries/screennotify.h>
#include <proto/ScreenNotify.h>

#include <clib.h>

#include "ParM.h"

#define CATCOMP_NUMBERS
#include "Lib/CtlgStrings.h"

#define BASE_TIME	100000	/* the base time for all time operations: 10 time per seconds */

#define THE_END			0
#define NO_MENUS		10
#define NO_WIN			20

#define OPEN_ITEM		0
#define UPDATE_ITEM		1
#define STD_CFG_ITEM	2
#define COMMAND_ITEM	4
#define CHDIR_ITEM		6
#define QUIT_ITEM		8

/* MakeDateTimeString( ) arg */
#define DATE_STRING		1
#define TIME_STRING		2

#define MAX_PATH_LEN	255

#define MEMF_PHYS MEMF_PUBLIC	/* workaround to lack of this flags */

/*****				global variables					*****/

extern struct ParMConfig *ParMConfig;
extern struct ParMOpt ParMOpt;
extern struct NewWindow NWS;
extern char DefaultConfigFile[ ];
extern char CopyRight[ ];

static struct Process *ParMProcess;
static BOOL DoSetRast = TRUE;	/* Clear window on Open */
static BOOL DoNextSelect;
static struct DateStamp Time;	/* the System Time */
static struct TextAttr TextAttr;
static struct TextFont *Font;
static char InfoString[ 80];
static char Dir[ MAX_PATH_LEN + 1];
static char File[ 34];
static char DateFmt[ 20];

struct RetinaBase *RetinaBase;
struct Library *VMemBase;

static BOOL IsVisible( struct Window *Window)
{
	if (  Window->WScreen == IntuitionBase->ActiveScreen)
		return TRUE;

//KPrintF(  "IntuitionBase->ActiveScreen->TopEdge:%ld, (  Window->TopEdge + Window->Height):%ld\n", IntuitionBase->ActiveScreen->TopEdge, (  Window->TopEdge + Window->Height));
	if (  IntuitionBase->ActiveScreen->TopEdge > (  Window->TopEdge + Window->Height))
		return TRUE;

	return FALSE;
}


static void CleanupMenus( APTR VisualInfo, struct Menu *Menu)
{
	LayoutMenus(  Menu, VisualInfo,
		GTMN_NewLookMenus, ( ParMOpt.Flags & PF_NEWLOOKMENUS) || ( ParMOpt.ParMMode == MODE_MYMENU),
		TAG_DONE);
}

static struct Menu *CreateParMMenus(  APTR VisualInfo, short Color)
{
	static struct NewMenu NewMenus[ ] =
	{
		{NM_TITLE, "ParM", 0, 0, 0, 0},
		{NM_ITEM, NULL, 0, 0, 0, 0},
		{NM_ITEM, NULL, 0, 0, 0, 0},
		{NM_ITEM, NULL, 0, 0, 0, 0},
		{NM_ITEM, NM_BARLABEL, 0, 0, 0, 0},
		{NM_ITEM, NULL, 0, 0, 0, 0},
		{NM_ITEM, NM_BARLABEL, 0, 0, 0, 0},
		{NM_ITEM, NULL, 0, 0, 0, 0},
		{NM_ITEM, NM_BARLABEL, 0, 0, 0, 0},
		{NM_ITEM, NULL, 0, 0, 0, 0},
		{NM_END}
	};
	long StrID = ParM_MSG_ParM_Open_MENU;
	struct NewMenu *NM;
	char *s;
	struct Menu *ParMMenu;

	NM = &NewMenus[ 1];
	while ( NM->nm_Type != NM_END)
	{
		if ( NM->nm_Label != NM_BARLABEL)
		{
			s = GetParMCatalogStr( StrID++);
			if ( *s == '_')
			{
				NM->nm_CommKey = s + 1;
				s += 3;
			}
			NM->nm_Label = s;
		}
		NM++;
	}
	if ( ParMMenu = CreateMenus( NewMenus, GTMN_FrontPen, Color, TAG_DONE))
		CleanupMenus( VisualInfo, ParMMenu);

	return ParMMenu;
}

static void ClearMenus(  struct Window *ParMWindow)
{
	if ( ParMOpt.ParMMode == MODE_MYMENU)
	{
	}
	else
		ClearMenuStrip( ParMWindow);
}

void UpDateMenus( APTR VisualInfo, struct Window *ParMWindow, struct Menu *ParMMenu)
{
	ClearMenus( ParMWindow);

	ParMConfig->LinkMenu = ParMMenu;
	ParMConfig->MenuPen = ParMOpt.ParMenuColor;

	if ( ParseMenus( ParMConfig))
		CleanupMenus( VisualInfo, ParMConfig->LinkMenu);

	if ( ParMOpt.ParMMode == MODE_MYMENU)
		;
	else
		SetMenuStrip( ParMWindow, ParMMenu);
}


void InitDateFmt( void)
{
	struct DateTime dt;
	char Date[ 18];

	memset( &dt, 0, sizeof ( struct DateTime));

	dt.dat_StrDate = Date;
	DateToStr( &dt);
	SPrintf( DateFmt, "%%-%lds %%10.10s  %%s", strlen( Date));
}


void MakeDateTimeString( char *dest, short Type)
{
	struct DateTime dt;
	char Date[ 18], Time[ 18], Day[ 18];

	memset( &dt, 0, sizeof ( struct DateTime));

	DateStamp( &dt.dat_Stamp);
	if ( Type == DATE_STRING)
	{
		dt.dat_Flags = DTF_FUTURE;
		dt.dat_StrDay = Day;
		dt.dat_StrDate = Date;
		dt.dat_StrTime = Time;
	}
	else
		dt.dat_StrTime = dest;
	DateToStr( &dt);
	if ( Type == DATE_STRING)
	{
		/* show week day only if both mem & time options are on */
		if ( ParMOpt.Flags & PF_SHOWTIME)
			SPrintf( dest, DateFmt, Day, Date, Time);
		else
			SPrintf( dest, "%10.10s  %s", Date, Time);
	}
}

#define RETINA_MEM_FMT	"Retina:%6lD  "
#define VMEM_MEM_FMT "  VMem:%7lD"	/* space at start because it was at last position */

static void MakeInfoString(  struct Window *ParMWindow)
{
	long chip_free, fast_free;
	short i = 0;

	if (  ParMWindow == IntuitionBase->ActiveWindow && ( ParMOpt.Flags & PF_SHOWMEM))
		MakeDateTimeString( InfoString, DATE_STRING);
	else
	{
		if ( ParMOpt.Flags & PF_SHOWMEM)
		{
			chip_free = AvailMem(  MEMF_CHIP) >> 10;
			fast_free = AvailMem(  MEMF_FAST | MEMF_PHYS) >> 10;
			if ( RetinaBase)
				i = SPrintf( InfoString, RETINA_MEM_FMT, Retina_AvailMem( 0) >> 10);
			i += SPrintf( &InfoString[ i], GetParMCatalogStr( ParM_MSG_Mem_Fmt), chip_free, fast_free);
			if (  FindPort(  "VMM_Port"))	/* avoid starting of VMM caused by vmm.library function call */
			{
				struct Library *VMMBase;

				if (  VMMBase = OpenLibrary(  "vmm.library", 1L))	/* since VMM port exist, this imply that vmm.library was alredy opened so that this OpenLibrary( ) don't cause any disk access */
				{
					i += SPrintf(  &InfoString[  i], VMEM_MEM_FMT, AvailVMem(  MEMF_ANY) >> 10);
					CloseLibrary( VMMBase);
				}
				else
					i += SPrintf(  &InfoString[  i], VMEM_MEM_FMT, 0);
			}
			else if (  VMemBase)
				i += SPrintf(  &InfoString[  i], VMEM_MEM_FMT, VMAvailMem( MEMF_ANY, VMEMF_VIRTUAL) >> 10);
		}
		if ( ParMOpt.Flags & PF_SHOWTIME)
		{
			if ( ParMOpt.Flags & PF_SHOWMEM)
			{
				InfoString[ i++] = ' ';
				InfoString[ i++] = ' ';
			}
			MakeDateTimeString( &InfoString[ i], TIME_STRING);
		}
	}
}


static void MakeInfoStringInit( void)
{
	struct DateTime dt;
	char Time[ 18];
	short i = 0;

	if ( ParMOpt.Flags & PF_SHOWMEM)
	{
		BOOL VMMInstalled = FALSE;

		if ( RetinaBase)
			i = SPrintf( InfoString, RETINA_MEM_FMT, 8888L);
		i += SPrintf( &InfoString[ i], GetParMCatalogStr( ParM_MSG_Mem_Fmt), 8888L, 88888L);
		{
//			struct Library *VMMBase;
//			if (  VMMBase = OpenLibrary(  "vmm.library", 1L))
//			{
//				/* don't use any function or this start VMM */
//				VMMInstalled = TRUE;
//				CloseLibrary( VMMBase);
//			}
			BPTR VMMLock;

			/* I use Lock( ) because loading vmm.library start VMM. I just want to know if VMM is installed */
			if (  VMMLock = Lock(  "Libs:VMM.library", ACCESS_READ))
			{
				VMMInstalled = TRUE;
				UnLock(  VMMLock);
			}
		}
		if (  VMemBase || VMMInstalled)
			i += SPrintf( &InfoString[ i], VMEM_MEM_FMT, 888888L);
	}
	if ( ParMOpt.Flags & PF_SHOWTIME)
	{
		if ( ParMOpt.Flags & PF_SHOWMEM)
		{
			InfoString[ i++] = ' ';
			InfoString[ i++] = ' ';
		}
		memset( &dt, 0, sizeof ( struct DateTime));

		dt.dat_StrTime = Time;
		DateToStr( &dt);
		strcpy( &InfoString[ i], Time);
	}
}


static void RefreshInfoString(  struct Window *ParMWindow)
{
	struct RastPort *rp;

	if (  ParMWindow && ( ParMOpt.Flags & ( PF_SHOWMEM | PF_SHOWTIME)))
	{
		MakeInfoString(  ParMWindow);
		rp = ParMWindow->RPort;
		if ( DoSetRast)
		{
			SetRast( rp, ParMOpt.MTBlockPen);
			DoSetRast = FALSE;
		}
		SetAPen( rp, ParMOpt.MTDetailPen);
		Move( rp, 4, Font->tf_Baseline + 1);
		Text( rp, InfoString, strlen( InfoString));
		if ( rp->cp_x < ParMWindow->Width)
		{
			SetAPen( rp, ParMOpt.MTBlockPen);
			RectFill( rp, rp->cp_x, 1, ParMWindow->Width, Font->tf_YSize + 1);
		}
	}
}


/* change parm current directory */
static void ChangeDir( char *dir)
{
	BPTR NewLock, OldLock;

	if ( NewLock = Lock( dir, ACCESS_READ))
	{
		if ( OldLock = CurrentDir( NewLock))
			UnLock( OldLock);
	}
}


static BOOL GetFileDir( char *Path, struct TagItem *Tags)
{
	struct Library *AslBase;
	struct FileRequester *FR;
	BOOL Ok = FALSE;

	if ( !( AslBase = OpenLibrary( "asl.library", 37)))
	{
		SimpleReq( GetParMCatalogStr( ParM_MSG_RequiresAsl));
		return FALSE;
	}
	if ( FR = ( struct FileRequester *)AllocAslRequest( ASL_FileRequest, Tags))
	{
		if ( Ok = AslRequestTags( FR, TAG_DONE))
		{
			strcpy( Path, ( char *)FR->fr_Drawer);
			AddPart( Path, FR->fr_File, MAX_PATH_LEN);
		}
		FreeAslRequest( FR);
	}
	CloseLibrary( AslBase);
	return Ok;
}


static struct TagItem CfgTags[ ] =
{
	{ASLFR_TitleText, NULL},
	{ASLFR_Flags1, FRB_DOPATTERNS},
	{ASLFR_InitialPattern, ( ULONG) "#?.cfg"},
	{ASLFR_InitialDrawer, ( ULONG) Dir},
	{ASLFR_InitialFile, ( ULONG) File},
	{TAG_DONE}
};


static void OpenMenus( struct Window *ParMWindow)
{
	strcpy( Dir, ParMConfig->CurCfg);
	strcpy( File, FilePart( Dir));
	*PathPart( Dir) = '\0';	/* cut off filename from fr_Dir */
	CfgTags[ 0].ti_Data = ( ULONG) GetParMCatalogStr( ParM_MSG1L_Open);
	if ( !GetFileDir( Dir, CfgTags))
		return;		/* quit if Open canceled */
	if ( strlen( Dir) >= 80)
	{
		SimpleReq( GetParMCatalogStr( ParM_MSG_PathTooLong));
		return;
	}
	strcpy( ParMConfig->CurCfg, Dir);
}

static void GetNewDir( void)
{
	struct TagItem DirTags[ ] =
	{
		{ASLFR_TitleText, NULL},
		{ASLFR_Flags2, FRB_DRAWERSONLY},
		{ASLFR_InitialDrawer, ( ULONG) Dir},
		{TAG_DONE}
	};
	NameFromLock( ParMProcess->pr_CurrentDir, Dir, MAX_PATH_LEN);
	DirTags[ 0].ti_Data = ( ULONG) GetParMCatalogStr( ParM_MSG_EnterNewDir);
	if ( GetFileDir( Dir, DirTags))
		ChangeDir( Dir);
}


/* Print busy message in place of window title */

static void Busy(  struct Window *ParMWindow, BOOL status)
{
	if ( ParMOpt.ParMMode == MODE_WINDOW)
	{
		SetWindowTitles(  ParMWindow, ( status) ? GetParMCatalogStr( ParM_MSG_Busy) : "ParM", CopyRight);
		if ( ParMOpt.Flags & ( PF_SHOWMEM | PF_SHOWTIME))
		{
			if ( status)	/* Busy */
				RefreshWindowFrame(  ParMWindow);
			else
				SetRast(  ParMWindow->RPort, ParMOpt.MTBlockPen);
		}
	}
}


static void DoExtMenu( APTR VisualInfo, struct Window *ParMWindow, struct Menu *ParMMenu, UWORD MenuNum)
{
	struct MenuInfo *MI;
	struct Extended_WBStartup *EWBS;

	MI = GTMENUITEM_USERDATA( ItemAddress( ParMMenu, MenuNum));
	switch ( MI->mi_RunMode)
	{
		case RM_Run:
		case RM_Shell:
			RunTags( ParMConfig, &MI->mi_RunInfo, PR_Mode, MI->mi_RunMode, TAG_DONE);
			break;
		case RM_WorkBench:
			if ( ( EWBS = MakeWBStartup( ParMConfig->ReqTitle, &MI->mi_RunInfo))
			    && WBRunTags( ParMConfig->ReqTitle, EWBS, WBRun_Pri, MI->mi_RunInfo.ri_Pri, TAG_DONE)
			    && ( MI->mi_RunInfo.ri_Flags & RIF_WBTOFRONT))
			{
				WBenchToFront( );
			}
			break;
		case RM_Cfg:		/* new cfg */
			strcpy( ParMConfig->CurCfg, MI->mi_RunInfo.ri_Cmd);
			UpDateMenus( VisualInfo, ParMWindow, ParMMenu);
			DoNextSelect = FALSE;	/* Tell DoIntuiMsg not to execute next menu selection */
			break;
	}
}

static struct Window *OpenParMWindow( STRPTR HostPubScreenName)
{
	struct IntuiText IT;
	struct Window *ParMWindow;
	struct NewWindow NewWindow = NWS;
	struct Screen *HostPubScreenScreen;

	if ( HostPubScreenScreen = LockPubScreen( HostPubScreenName))
	{
		AskFont( &HostPubScreenScreen ->RastPort, &TextAttr);	/* Get screen font */
		Font = OpenFont( &TextAttr);
		IT.ITextFont = &TextAttr;

		/* Screen->BarHeight is one pixel less than true height */
		NewWindow.Height = HostPubScreenScreen ->BarHeight;
		if ( DOSBase->dl_lib.lib_Version < 39)
			NewWindow.Height++;	/* In V39, do not hide screen's title bar bevel effect */

		/* calculate the real lenght of string ParM ( font can be proportional in 2.0) */
		/* if the font is proportional tf_YSize chould contain max char size */
		if ( ParMOpt.Flags & ( PF_SHOWMEM | PF_SHOWTIME))
		{
			MakeInfoStringInit( );
			IT.IText = InfoString;
		}
		else
		{
			IT.IText = "ParM";
			NewWindow.Width = 10;
			if ( NewWindow.Flags & WFLG_DEPTHGADGET)
				NewWindow.Width += 51;	/* Depth gadget stay hidden when show Mem/Time */
		}
		NewWindow.Width += IntuiTextLength(  &IT) + 6;
		if ( NewWindow.LeftEdge + NewWindow.Width > HostPubScreenScreen ->Width - 23)
			NewWindow.LeftEdge = HostPubScreenScreen ->Width - NewWindow.Width - 23;

		if (  ParMWindow = OpenWindowTags(  &NewWindow, WA_AutoAdjust, TRUE, TAG_DONE))
		{
			UnlockPubScreen( NULL, HostPubScreenScreen);
			SetWindowTitles(  ParMWindow, "ParM", CopyRight);
			SetFont(  ParMWindow->RPort, Font);
			return ParMWindow;
		}
		UnlockPubScreen( NULL, HostPubScreenScreen);
	}

	return NULL;
}

static struct Menu *StartParMMenu( APTR *VisualInfo, struct Window *ParMWindow)
{
	struct Menu *ParMMenu = NULL;

	ParMConfig->Win = ParMWindow;
	*VisualInfo = GetVisualInfo( ParMWindow->WScreen, TAG_DONE);
	if ( ParMOpt.ParMenuColor < 0)
		ParMOpt.ParMenuColor = ParMWindow->DetailPen;
	if ( ParMMenu = CreateParMMenus( *VisualInfo, ParMOpt.ParMenuColor))
	{
		ParMConfig->LinkMenu = ParMMenu;

		UpDateMenus( *VisualInfo, ParMWindow, ParMMenu);
		SetBPen( ParMWindow->RPort, ParMOpt.MTBlockPen);
		SetDrMd( ParMWindow->RPort, JAM2);
		RefreshInfoString( ParMWindow);

		return ParMMenu;
	}

	return NULL;
}

static void EndParMMenu( APTR *VisualInfo, struct Window *ParMWindow, struct Menu *ParMMenu)
{
	ClearMenus( ParMWindow);
	FreeParMMenus( ParMConfig);
	FreeMenus( ParMMenu);
	ParMMenu = NULL;
	FreeVisualInfo( *VisualInfo);
	*VisualInfo = NULL;
}

static void CloseParMWindow( struct Window *ParMWindow)
{
	CloseWindow( ParMWindow);
	if ( Font)
	{
		CloseFont( Font);
		Font = NULL;
	}
}

long ParMMain( void)
{
	BOOL Quit = FALSE;

	ULONG MsgClass;
	UWORD Code, Qual;
	BPTR OldCIS, OldCOS, fh = 0;
	APTR OldConsoleTask;

	/* for TopInfo String */
	struct MsgPort *Timer_Port = NULL;
	struct timerequest Time_Req;
	long TimerOpen = 1;
	struct MsgPort *IntuiPort = NULL;
	ULONG IntuiSignal = 0;
	ULONG TimerSignal = 0;
	ULONG Signal = 0;
	ULONG WaitMask = 0;

	struct Window *ParMWindow = NULL;
	struct Menu *ParMMenu = NULL;
	APTR VisualInfo = NULL;

	struct Library *ScreenNotifyBase = NULL;
	struct MsgPort *ScreenNotifyPort = NULL;
	ULONG ScreenNotifySignal = 0;
	APTR ScreenNotifyHandle = NULL;

	RetinaBase = ( struct RetinaBase *)OpenLibrary( "retina.library", 2L);
	VMemBase = OpenLibrary( "vmem.library", 1L);

	InitDateFmt( );
	ParMProcess = ( struct Process *)SysBase->ThisTask;
	switch ( ParMOpt.ParMMode)
	{
		case MODE_WINDOW:
			if (  !(  ParMWindow = OpenParMWindow(  NULL)))
				goto Bye;
			if ( !( ParMMenu = StartParMMenu( &VisualInfo, ParMWindow)))
				goto Bye;
			IntuiPort = ParMWindow->UserPort;
			IntuiSignal = 1L << IntuiPort->mp_SigBit;
			WaitMask |= IntuiSignal;
			if ( ( ParMOpt.Flags & ( PF_SHOWMEM | PF_SHOWTIME)) && ( Timer_Port = CreateMsgPort( )))
			{
				if ( !( TimerOpen = OpenDevice( TIMERNAME, UNIT_VBLANK, ( struct IORequest *)&Time_Req, 0L)))
				{
					Time_Req.tr_node.io_Message.mn_ReplyPort = Timer_Port;
					Time_Req.tr_node.io_Command = TR_ADDREQUEST;
					Time_Req.tr_node.io_Flags = 0;
					Time_Req.tr_node.io_Error = 0;
					Time_Req.tr_time.tv_secs = 0;
					Time_Req.tr_time.tv_micro = BASE_TIME * ParMOpt.RefreshTime;
				}
			}
			if (  ScreenNotifyBase = OpenLibrary( SCREENNOTIFY_NAME, SCREENNOTIFY_VERSION))
			{
				ScreenNotifyPort = CreateMsgPort( );
				ScreenNotifySignal = 1L << ScreenNotifyPort->mp_SigBit;
				WaitMask |= ScreenNotifySignal;
				ScreenNotifyHandle = AddWorkbenchClient(  ScreenNotifyPort , 0);
			}

			break;
		case MODE_CLI:
			goto Bye;
			break;
		case MODE_MYMENU:
			goto Bye;
			break;
	}

	OldCIS = ParMProcess->pr_CIS;
	OldCOS = ParMProcess->pr_COS;
	OldConsoleTask = ParMProcess->pr_ConsoleTask;
	if ( ParMOpt.Flags & PF_USENULL && ( fh = Open( "NIL:", MODE_NEWFILE)))
	{
		ParMProcess->pr_CIS = fh;
		ParMProcess->pr_COS = fh;
		ParMProcess->pr_ConsoleTask = 0;
	}
	/* Monitor Menu Events */

	WaitMask |= IntuiSignal;
	if ( Timer_Port)
	{
		TimerSignal = 1L << Timer_Port->mp_SigBit;
		WaitMask |= TimerSignal;
		SendIO( ( struct IORequest *)&Time_Req.tr_node);
	}

	WaitMask |= SIGBREAKF_CTRL_C;
	while ( !Quit)
	{
		struct IntuiMessage *IMsg;

		Signal = Wait( WaitMask);
		if ( Signal & IntuiSignal)
		{
			while ( IMsg = ( struct IntuiMessage *)GetMsg( IntuiPort))
			{
				MsgClass = IMsg->Class;
				Code = IMsg->Code;
				Qual = IMsg->Qualifier;
				if ( MsgClass == IDCMP_RAWKEY && !( Qual & IEQUALIFIER_REPEAT) && !( Code & IECODE_UP_PREFIX))
				{
					UWORD TmpCode;

					if ( ( TmpCode = FindMenuHotKey( ParMConfig, ParMMenu, Code, Qual, IMsg->IAddress)) != MENUNULL)
					{
						Code = TmpCode;
						MsgClass = IDCMP_MENUPICK;
					}
					// Give nul Qualifier for RawKeyToAscii( ) to allow 'alt' keys as menu qualifier keys
					else if ( Code = RawKeyToAscii( Code, Qual & ~( IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT), IMsg->IAddress))
					{
						if ( Code >= 32 && Code <= 255)
						{
							ULONG const EXCLUDE_QUAL_MASK	= ( IEQUALIFIER_RELATIVEMOUSE|IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT|IEQUALIFIER_NUMERICPAD|IEQUALIFIER_CAPSLOCK);

							if ( ( Qual & ~EXCLUDE_QUAL_MASK) == ( ParMConfig->ShortCutQual & ~EXCLUDE_QUAL_MASK))
							{
								Code = MakeMenuShortCut( ParMMenu, Code);
								MsgClass = IDCMP_MENUPICK;
							}
						}
					}
				}
				switch ( MsgClass)
				{
					case IDCMP_ACTIVEWINDOW:
					case IDCMP_INACTIVEWINDOW:
						if ( ParMOpt.ParMMode == MODE_WINDOW && ( ParMOpt.Flags & ( PF_SHOWMEM | PF_SHOWTIME)))
						{
							Delay( 6);	/* let intuition do its defered drawing */
							DoSetRast = TRUE;
						}
						break;
					case IDCMP_CLOSEWINDOW:
						Quit = TRUE;
						break;
					case IDCMP_MENUPICK:
						DoNextSelect = TRUE;
						if ( Code != MENUNULL)
						{
							ULONG const FirstParMMenuNum = 0;	// from removed MyMeny support

							Busy( ParMWindow, TRUE);
							do
							{
								/* Prevent extended selection of workbench menus */
								if ( MENUNUM( Code) == FirstParMMenuNum)
								{
									switch ( ITEMNUM( Code))
									{
									case OPEN_ITEM:
										OpenMenus( ParMWindow);
										UpDateMenus( VisualInfo, ParMWindow, ParMMenu);
										DoNextSelect = FALSE;
										break;
									case UPDATE_ITEM:
										UpDateMenus( VisualInfo, ParMWindow, ParMMenu);
										DoNextSelect = FALSE;
										break;
									case STD_CFG_ITEM:
										strcpy( ParMConfig->CurCfg, DefaultConfigFile);
										UpDateMenus( VisualInfo, ParMWindow, ParMMenu);
										DoNextSelect = FALSE;
										break;
									case COMMAND_ITEM:
										Command( ParMConfig);
										break;
									case CHDIR_ITEM:
										GetNewDir( );
										break;
									case QUIT_ITEM:
										Quit = TRUE;
										DoNextSelect = FALSE;
									}
								}
								else if ( MENUNUM( Code) > FirstParMMenuNum)	/* custom menus */
									DoExtMenu( VisualInfo, ParMWindow, ParMMenu, Code);
							} while ( DoNextSelect && ( Code = ItemAddress( ParMMenu, Code)->NextSelect) != MENUNULL);
							Busy( ParMWindow, FALSE);
						}
						break;
				}
				ReplyMsg( IMsg);
			}
		}
		if ( Signal & TimerSignal)
		{
			if ( ParMWindow && ( ParMOpt.Flags & PF_AUTOFRONT) && IsHidden( ParMWindow))
				WindowToFront( ParMWindow);
			Time_Req.tr_time.tv_secs = 0;
			Time_Req.tr_time.tv_micro = BASE_TIME * ParMOpt.RefreshTime;
			SendIO( ( struct IORequest *)&Time_Req.tr_node);
		}
		if (  Signal & ScreenNotifySignal)
		{
			struct ScreenNotifyMessage *snm;

			/* Get message */
			while (  snm = ( struct ScreenNotifyMessage *)GetMsg( ScreenNotifyPort))
			{
				/* Workbench notification? */
				if (  snm->snm_Type == SCREENNOTIFY_TYPE_WORKBENCH)
				{
					/* Yes, Open/Close event? */
					switch (  ( ULONG)snm->snm_Value)
					{
						case FALSE:	/* WB Close -> close our window */
							if ( ParMWindow)
							{
								if ( ParMMenu)
								{
									EndParMMenu( &VisualInfo, ParMWindow, ParMMenu);
									ParMMenu = NULL;
								}
								if ( ParMWindow)
								{
									CloseParMWindow( ParMWindow);
									ParMWindow = NULL;
								}
								WaitMask &= ~IntuiSignal;
								IntuiSignal = 0;
								IntuiPort = NULL;

								// workaround a bug of ScreenNotify library wich send WBOpen immediatly after WBClose even if 
								// the WB haven't yet be closed and reopened
								//Delay(  20);	// workaround a bug of
							}
						break;
						case TRUE:	/* WB Open -> reopen our window */
						{
							UBYTE i = 0;
							while ( (i < 10) && !( ParMWindow = OpenParMWindow( NULL)))
							{
								i++;
								Delay( 50L);
							}
							if ( ParMWindow)
							{
								if ( ParMMenu = StartParMMenu( &VisualInfo, ParMWindow))
								{
									IntuiPort = ParMWindow->UserPort;
									IntuiSignal = 1L << IntuiPort->mp_SigBit;
									WaitMask |= IntuiSignal;
								}
								else
									Quit = TRUE;
							}
							else
								Quit = TRUE;
						}
						break;
					}
				}
				ReplyMsg( ( struct Message *)snm);
			}
		}
		if ( Signal & SIGBREAKF_CTRL_C)
			Quit = TRUE;
		//if ( ParMWindow && ( ParMOpt.ParMMode == MODE_WINDOW) && IsVisible( ParMWindow))
		if ( ParMWindow && ( ParMOpt.ParMMode == MODE_WINDOW))
			RefreshInfoString( ParMWindow);
		/* See if some wb messages have been replied, and free them */
		FreeRepliedWBMessages( );
	}

	if ( !TimerOpen)
	{
		AbortIO( ( struct IORequest *)&Time_Req);		/* wait for the last timer msg before exit */
		CloseDevice( ( struct IORequest *)&Time_Req);
	}
	if ( Timer_Port)
		DeleteMsgPort( Timer_Port);

	ParMProcess->pr_CIS = OldCIS;
	ParMProcess->pr_COS = OldCOS;
	ParMProcess->pr_ConsoleTask = OldConsoleTask;
	if ( fh)
		Close( fh);

	Bye:
	if ( ParMMenu)
	{
		EndParMMenu( &VisualInfo, ParMWindow, ParMMenu);
		ParMMenu = NULL;
	}
	if ( ParMWindow)
	{
		CloseParMWindow( ParMWindow);
		ParMWindow = NULL;
	}

	if (  ScreenNotifyHandle )
	{
		/* Unregister WB client */
		while ( !RemWorkbenchClient( ScreenNotifyHandle))
			Delay(  10);
	}
	if (  ScreenNotifyPort)
		DeleteMsgPort(  ScreenNotifyPort);
	if (  ScreenNotifyBase)
		CloseLibrary(  ScreenNotifyBase);

	if ( RetinaBase)
		CloseLibrary( RetinaBase);
	if ( VMemBase)
		CloseLibrary( VMemBase);

	return 0;
}
