/* FarPrint.c ***************************************************************
*
*	FarPrint ------	Debugging functions for programs which don't
*			have links to their environment.
*
*			FarPrint 'harbour' to receive and distribute
*			all incoming messages.
*
*	Author --------	Olaf Barthel of ED Electronic Design Hannover
*			Brabeckstrasse 35
*			D-3000 Hannover 71
*
*			Federal Republic of Germany.
*
*	This program truly is in the PUBLIC DOMAIN. Written on a sunny
*	September day in 1989.
*
*	Compiled using Aztec C 3.6a, CygnusEd Professional & ARexx.
*
****************************************************************************/

	/* Our main includes, note that you MUST have the ARP
	 * package to recompile FarPrint!
	 */

#include <intuition/intuitionbase.h>
#include <libraries/dosextens.h>
#include <libraries/arpbase.h>
#include <graphics/gfxbase.h>
#include <arpfunctions.h>
#include <exec/memory.h>

	/* Forward declarations. */

extern struct Library	*OpenLibrary();
extern struct Window	*OpenWindow();
extern struct Message	*GetMsg();
extern struct MenuItem	*ItemAddress();
extern struct MsgPort	*CreatePort();
extern struct TextFont	*OpenFont();
extern void		*AllocMem();
extern ULONG		 Wait();

	/* Signal sources. */

#define SIG_WINDOW	(1 << Window -> UserPort -> mp_SigBit)
#define SIG_PORT	(1 << FarPort -> mp_SigBit)

	/* Textprint macro. */

#define PrintRequest(Request) Text(RPort,Request,strlen(Request))

	/* External communication commands. */

#define FM_ADDTXT	0
#define FM_REQTXT	1
#define FM_REQNUM	2

	/* Custom task <-> task communication message. */

struct FarMessage
{
	struct Message	fm_ExecMessage;	/* Exec message link. */

	USHORT		fm_Command;	/* Perform which action? */
	STRPTR		fm_Identifier;	/* Who calls? */
	STRPTR		fm_Text;	/* Message to display. */
};

	/* Messages to be displayed. */

STRPTR TextList[128];
long InTextList = 0;

	/* Global and shared data structures. */

struct ArpBase		*ArpBase;
struct IntuitionBase	*IntuitionBase;
struct GfxBase		*GfxBase;
struct Window		*Window;
struct IntuiMessage	*Massage;
struct RastPort		*RPort;
struct MsgPort		*FarPort;
struct TextFont		*DefaultFont;
BOOL			Pausing = FALSE;

	/* Maximum number of chars in FileRequest path. */

#define MAXPATH	((FCHARS * 10) + DSIZE + 1)

	/* FileRequest working data. */

UBYTE Filename[FCHARS + 1];
UBYTE Directory[MAXPATH] = "SYS:";

	/* ARP FileRequester structure. */

struct FileRequester MyRequest =
{
	"Save message texts",
	(BYTE *)Filename,
	(BYTE *)Directory,
	NULL,NULL,NULL,NULL
};

	/* Run dump for up arrow gadget. */

USHORT UpMap[22] =
{
	0xFFFE,0xFEFE,0xFC7E,0xF83E,0xF01E,0xE00E,0xC006,0xF83E,
	0xF83E,0xF83E,0xFFFE,

	0x0000,0x0100,0x0380,0x07C0,0x0FE0,0x1FF0,0x3FF8,0x07C0,
	0x07C0,0x07C0,0x0000
};

	/* Run dump for down arrow gadget. */

USHORT DnMap[22] =
{
	0xFFFE,0xF83E,0xF83E,0xF83E,0xC006,0xE00E,0xF01E,0xF83E,
	0xFC7E,0xFEFE,0xFFFE,

	0x0000,0x07C0,0x07C0,0x07C0,0x3FF8,0x1FF0,0x0FE0,0x07C0,
	0x0380,0x0100,0x0000
};

	/* Image structures for bool gadgets. */

struct Image UpImage =
{
	0,0,
	15,11,2,
	(USHORT *)UpMap,
	0x03,0x00,
	(struct Image *)NULL
};

struct Image DnImage =
{
	0,0,
	15,11,2,
	(USHORT *)DnMap,
	0x03,0x00,
	(struct Image *)NULL
};

	/* Our default text definitions. */

struct TextAttr DefaultAttr[3] =
{
	{(UBYTE *)"topaz.font",8,FS_NORMAL ,FPF_ROMFONT},
	{(UBYTE *)"topaz.font",8,FSF_BOLD  ,FPF_ROMFONT},
	{(UBYTE *)"topaz.font",8,FSF_ITALIC,FPF_ROMFONT}
};

	/* Select the "About..." menuitem to get this text. */

struct IntuiText AboutTxt[14] =
{
	{3,1,JAM1,8,  4,&DefaultAttr[1],(UBYTE *)"FarPrint v1.3",			&AboutTxt[ 1]},

	{2,1,JAM1,8, 16,&DefaultAttr[0],(UBYTE *)"Was  written  by  Olaf 'Olsen'",	&AboutTxt[ 2]},
	{2,1,JAM1,8, 24,&DefaultAttr[0],(UBYTE *)"Barthel   of   ED   Electronic",	&AboutTxt[ 3]},
	{2,1,JAM1,8, 32,&DefaultAttr[0],(UBYTE *)"Design Hannover.  The FarPrint",	&AboutTxt[ 4]},
	{2,1,JAM1,8, 40,&DefaultAttr[0],(UBYTE *)"package   is  meant  to  be  a",	&AboutTxt[ 5]},
	{2,1,JAM1,8, 48,&DefaultAttr[0],(UBYTE *)"simple   replacement  for  the",	&AboutTxt[ 6]},
	{2,1,JAM1,8, 56,&DefaultAttr[0],(UBYTE *)"debug.lib  functions which are",	&AboutTxt[ 7]},
	{2,1,JAM1,8, 64,&DefaultAttr[0],(UBYTE *)"usually  to  transmit text and",	&AboutTxt[ 8]},
	{2,1,JAM1,8, 72,&DefaultAttr[0],(UBYTE *)"other   data   to  a  terminal",	&AboutTxt[ 9]},
	{2,1,JAM1,8, 80,&DefaultAttr[0],(UBYTE *)"connected  to  the serial port",	&AboutTxt[10]},
	{2,1,JAM1,8, 88,&DefaultAttr[0],(UBYTE *)"of the Amiga.",			&AboutTxt[11]},

	{0,1,JAM1,8,104,&DefaultAttr[2],(UBYTE *)"(C) Copyright 1989 by...,",		&AboutTxt[12]},
	{0,1,JAM1,8,112,&DefaultAttr[2],(UBYTE *)"ED Electronic Design Hannover",	NULL},

	{0,1,JAM1,5,  3,&DefaultAttr[0],(UBYTE *)"Understood",				NULL}
};

	/* This will become our menu. */

struct IntuiText FarIntTxt[6] =
{
	{0,1,JAM2,2,1,&DefaultAttr[0],(UBYTE *)"About FarPrint...      ",NULL},
	{0,1,JAM1,2,1,&DefaultAttr[1],(UBYTE *)"_______________________",NULL},
	{0,1,JAM2,2,1,&DefaultAttr[0],(UBYTE *)"Save Message texts     ",NULL},
	{0,1,JAM2,2,1,&DefaultAttr[0],(UBYTE *)"Pause                  ",NULL},
	{0,1,JAM2,2,1,&DefaultAttr[0],(UBYTE *)"Iconify Window         ",NULL},
	{0,1,JAM2,2,1,&DefaultAttr[0],(UBYTE *)"Quit FarPrint          ",NULL}
};

	/* Now transform it into a chain of menu items. */

struct MenuItem FarMenuItem[6] =
{
	{&FarMenuItem[1],0, 0,188,10, 86,0,(APTR)&FarIntTxt[0],NULL,'?',NULL,NULL},
	{&FarMenuItem[2],0, 3,188,10,210,0,(APTR)&FarIntTxt[1],NULL,  0,NULL,NULL},
	{&FarMenuItem[3],0,13,188,10, 86,0,(APTR)&FarIntTxt[2],NULL,'S',NULL,NULL},
	{&FarMenuItem[4],0,23,188,10, 86,0,(APTR)&FarIntTxt[3],NULL,'P',NULL,NULL},
	{&FarMenuItem[5],0,33,188,10, 86,0,(APTR)&FarIntTxt[4],NULL,'I',NULL,NULL},
	{NULL,           0,43,188,10, 86,0,(APTR)&FarIntTxt[5],NULL,'Q',NULL,NULL}
};

	/* This binds them into a menu. */

struct Menu FarMenu = {NULL,0,0,112,0,257,"FarPrint v1.3",&FarMenuItem[0]};

	/* Now comes some gadget data. */

UBYTE StrInfStr[81],UndoStrInfStr[81];

struct StringInfo FarStrInf  = {&StrInfStr[0],&UndoStrInfStr[0],0,81,0,0,0,0,0,NULL,NULL,NULL};
struct PropInfo   FarPropInf = {AUTOKNOB | FREEVERT,0,0,0,MAXBODY,0,0,0,0,0,0};

SHORT FarBrdDat[] =
{
	-1,-1,88,-1,88,14,-1,14,
	-1,-1,632,-1,632,8,-1,8,-1,-1,
	-2,-1,633,-1,633,8,-2,8,-2,-1,
	0,0,-639,0,
	0,0,-637,0,
};

struct Border FarBrd[5] =
{
	{  0,  0,0,7,0,4,&FarBrdDat[ 0],NULL},
	{  0,  0,1,0,0,5,&FarBrdDat[ 8],&FarBrd[2]},
	{  0,  0,1,0,0,5,&FarBrdDat[18],NULL},
	{639,116,1,0,0,2,&FarBrdDat[28],&FarBrd[4]},
	{638,116,1,0,0,2,&FarBrdDat[32],NULL}
};

struct Gadget FarGad[4] =
{
	{&FarGad[1],  4,128,632, 8,GADGHCOMP | GADGHCOMP | GADGDISABLED,RELVERIFY | GADGIMMEDIATE,              STRGADGET ,(APTR)&FarBrd[1],NULL,NULL,NULL,(APTR)&FarStrInf, 0,NULL},
	{&FarGad[2],621, 11, 15,11,GADGIMAGE | GADGHCOMP               ,RELVERIFY | GADGIMMEDIATE,              BOOLGADGET,(APTR)&UpImage,  NULL,NULL,NULL,NULL,             1,NULL},
	{&FarGad[3],621,104, 15,11,GADGIMAGE | GADGHCOMP               ,RELVERIFY | GADGIMMEDIATE,              BOOLGADGET,(APTR)&DnImage,  NULL,NULL,NULL,NULL,             2,NULL},
	{NULL      ,621, 23, 15,80,GADGHNONE                           ,RELVERIFY | GADGIMMEDIATE | FOLLOWMOUSE,PROPGADGET,(APTR)&FarBrd[0],NULL,NULL,NULL,(APTR)&FarPropInf,3,NULL}
};

	/* The main window. */

struct NewWindow NewWindow =
{
	0,11,
	640,137,
	0,1,
	CLOSEWINDOW | MOUSEMOVE | GADGETUP | GADGETDOWN | MENUPICK,
	WINDOWDEPTH | WINDOWCLOSE | WINDOWDRAG,
	(struct Gadget *)&FarGad[0],
	(struct Image *)NULL,
	(STRPTR)"FarPrint v1.3",
	(struct Screen *)NULL,
	(struct BitMap *)NULL,
	0,0,
	0,0,
	WBENCHSCREEN
};

	/* CLI detach stuff. */

long  _stack		= 8000;
long  _priority		= 0;
long  _BackGroundIO	= 0;
char *_procname		= "FarPrint v1.3";

	/* SetPropPosition(Value):
	 *
	 *	Sets the slider position of the proportional
	 *	gadget.
	 */

void
SetPropPosition(Value)
long Value;
{
	if(Value > InTextList || Value < 0)
		return;

	if(InTextList)
		ModifyProp(&FarGad[3],Window,NULL,AUTOKNOB | FREEVERT,0,Value * (MAXPOT / InTextList),0,MAXBODY / InTextList);
	else
		ModifyProp(&FarGad[3],Window,NULL,AUTOKNOB | FREEVERT,0,MAXPOT,0,MAXBODY);
}

	/* GetPropPosition():
	 *
	 *	Returns the slider position of the proportional
	 *	gadget.
	 */

long
GetPropPosition()
{
	long Value;

	if(InTextList)
		Value = FarPropInf . VertPot / (MAXPOT / InTextList);
	else
		Value = FarPropInf . VertPot / MAXPOT;

	if(Value >= InTextList)
		Value = InTextList - 1;
}

	/* DrawText(From,SaveTime):
	 *
	 *	Draws the list of recorded messages.
	 */

void
DrawText(From,SaveTime)
long From;
BOOL SaveTime;
{
	long i,Length;

	static long LastPosition = -1;

	if(LastPosition == From && SaveTime)
		return;

	LastPosition = From;

	SetAPen(RPort,0);
	RectFill(RPort,4,11,618,114);
	SetAPen(RPort,1);

	for(i = 0 ; i < 13 ; i++)
	{
		if(i + From >= InTextList || !TextList[i])
			break;

		Move(RPort,4,17 + 8 * i);

		if((Length = strlen(TextList[i + From])) > 77)
			Length = 77;

		if(Length)
			FastText(RPort,TextList[i + From],Length);
	}
}

	/* AddText(Message):
	 *
	 *	Adds a message to the current list of recorded
	 *	texts.
	 */

void
AddText(Message)
STRPTR *Message;
{
		/* Only 128 messages allowed. */

	if(InTextList == 128)
	{
		register long i;

		FreeMem(TextList[0],strlen(TextList[0]) + 1);

		for(i = 0 ; i < 127 ; i++)
			TextList[i] = TextList[i + 1];

		InTextList = 127;
	}

	if(TextList[InTextList] = (STRPTR)AllocMem(strlen(Message) + 1,MEMF_PUBLIC))
	{
		strcpy(TextList[InTextList],Message);

		InTextList++;

		ModifyProp(&FarGad[3],Window,NULL,AUTOKNOB | FREEVERT,0,FarPropInf . VertPot,0,MAXBODY / InTextList);

		if(GetPropPosition() + 13 < InTextList)
			SetPropPosition(GetPropPosition() + 1);

		DrawText(GetPropPosition(),FALSE);
	}
}

	/* FreeTextList():
	 *
	 *	Frees the list of recorded messages.
	 */

void
FreeTextList()
{
	long i;

	for(i = 0 ; i < InTextList ; i++)
		if(TextList[i])
			FreeMem(TextList[i],strlen(TextList[i] + 1));
}

	/* ClearRequest():
	 *
	 *	Clears the part of the window above the string
	 *	gadget.
	 */

void
ClearRequest()
{
	SetAPen(RPort,0);
	RectFill(RPort,2,117,637,126);
	SetAPen(RPort,1);

	Move(RPort,2,124);
}

	/* SaveText():
	 *
	 *	Saves the list of recorded messages to disk. Uses
	 *	the ARP FileRequester.
	 */
	
void
SaveText()
{
	char *Selection;
	UBYTE *Title = Window -> Title;

	if(!InTextList)
		return;

	if(Selection = FileRequest(&MyRequest))
	{
		if(Selection[0])
		{
			UBYTE Destination[FCHARS + 1 + MAXPATH];
			long DestFile;

			strcpy(Destination,Directory);

			if(Directory[strlen(Directory) - 1] != ':' && Directory[strlen(Directory) - 1] != '/')
				strcat(Destination,"/");

			strcat(Destination,Filename);

			if(DestFile = Open(Destination,MODE_NEWFILE))
			{
				long i;

				for(i = 0 ; i < InTextList ; i++)
				{
					if(Write(DestFile,TextList[i],strlen(TextList[i])) < 1)
						break;

					if(Write(DestFile,"\n",1) < 1)
						break;
				}

				Close(DestFile);

				SetWindowTitles(Window,"Message texts saved",-1);

				Delay(TICKS_PER_SECOND * 2);

				SetWindowTitles(Window,Title,-1);

				return;
			}
		}
	}

	SetWindowTitles(Window,"Message texts NOT saved!",-1);

	Delay(TICKS_PER_SECOND * 2);

	SetWindowTitles(Window,Title,-1);
}

	/* CloseAll(ReturnCode):
	 *
	 *	Frees anything we have allocated and quits.
	 */

void
CloseAll(ReturnCode)
long ReturnCode;
{
	FreeTextList();

	FreeFastText();

	if(DefaultFont)
		CloseFont(DefaultFont);

	if(FarPort)
	{
		struct Message *TmpMessage;

		while(TmpMessage = (struct Message *)GetMsg(FarPort))
			ReplyMsg(TmpMessage);

		ClearMenuStrip(Window);

		Forbid();
		DeletePort(FarPort);
		Permit();
	}

	if(Window)
	{
		while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
			ReplyMsg(Massage);

		ClearMenuStrip(Window);

		CloseWindow(Window);
	}

	if(ArpBase)
		CloseLibrary(ArpBase);

	exit(ReturnCode);
}

	/* OpenAll():
	 *
	 *	Sets up everything we need to execute successfully.
	 */

void
OpenAll()
{
	if(!(ArpBase = (struct ArpBase *)OpenLibrary("arp.library",ArpVersion)))
		CloseAll(20);

	IntuitionBase	= (struct IntuitionBase *)ArpBase -> IntuiBase;
	GfxBase		= (struct GfxBase *)ArpBase -> GfxBase;

	if(!(FarPort = (struct MsgPort *)CreatePort("FarPort",0)))
		CloseAll(20);

	if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
		CloseAll(20);

	SetMenuStrip(Window,&FarMenu);

	if(!(DefaultFont = (struct TextFont *)OpenFont(&DefaultAttr[0])))
		CloseAll(20);

	if(!InitFastText(DefaultFont))
		CloseAll(20);

	RPort = Window -> RPort;

	SetAPen(RPort,1);
	SetBPen(RPort,0);
	SetDrMd(RPort,JAM2);

	DrawBorder(RPort,&FarBrd[3],0,0);

	SetFont(RPort,DefaultFont);
}

	/* Iconify():
	 *
	 *	Rewritten version of Leo Schwab's Iconify routine.
	 */

Iconify()
{
		/* Bitmap rundump for icon image. */

	static USHORT IconMap[184] =
	{
		0x1FFF,0xFFFF,0xFFFF,0xF000,0x3000,0x0000,0x0000,0x1800,
		0x3000,0x0000,0x0000,0x1800,0x31C0,0x0008,0xD001,0x1800,
		0x3080,0x0001,0x0001,0x1800,0x308E,0x73CB,0x938F,0x1800,
		0x3090,0x8A29,0x1451,0x1800,0x3090,0x8A29,0x17D1,0x1800,
		0x3090,0x8A29,0x1411,0x1800,0x31CE,0x7229,0x138F,0x1800,
		0x3000,0x0000,0x0000,0x1800,0x3000,0x0000,0x0000,0x1800,
		0x3078,0x0000,0x0804,0x1800,0x3040,0x0000,0x0004,0x1800,
		0x3041,0xC778,0xEBCE,0x1800,0x3072,0x2845,0x0A24,0x1800,
		0x3042,0x2845,0x0A24,0x1800,0x3042,0x2845,0x0A24,0x1800,
		0x3041,0xE879,0x0A24,0x1800,0x3000,0x0040,0x0000,0x1800,
		0x3000,0x0000,0x0000,0x1800,0x1FFF,0xFFFF,0xFFFF,0xE800,
		0x0000,0x0000,0x0000,0x0000,

		0x1000,0x0000,0x0000,0x1000,0x0FFF,0xFFFF,0xFFFF,0xC000,
		0xC000,0x0000,0x0000,0x6000,0xC000,0x0000,0x0000,0x6000,
		0xC700,0x0032,0xE006,0x6000,0xC300,0x0004,0x0000,0x6000,
		0xC32D,0x6596,0x6B2E,0x6000,0xC363,0x34D6,0x6826,0x6000,
		0xC363,0x34D6,0x6BE6,0x6000,0xC221,0x0CD6,0x6860,0x6000,
		0xC7BD,0xECF6,0x6F3E,0x6000,0xC000,0x0000,0x0000,0x6000,
		0xC000,0x0000,0x0000,0x6000,0xC1B0,0x0000,0x3018,0x6000,
		0xC180,0x0000,0x0010,0x6000,0xC185,0x97B2,0xF598,0x6000,
		0xC1AC,0xD19A,0x34D8,0x6000,0xC18C,0xD19A,0x34D8,0x6000,
		0xC18C,0x1186,0x34D8,0x6000,0xC187,0xF1B6,0x3CD8,0x6000,
		0xC000,0x0180,0x0000,0x6000,0xF000,0x0000,0x0000,0x1800,
		0x3FFF,0xFFFF,0xFFFF,0xC000
	};

	static struct Image IconImage =
	{
		0,0,
		53,23,2,
		(USHORT *)IconMap,
		0x03,0x00,
		(struct Image *)NULL
	};

		/* This is the 'icon stuff. */

	static struct Gadget IconGadget =
	{
		NULL,
		0,0,53,23,
		GADGHCOMP | GRELWIDTH | GRELHEIGHT | GADGIMAGE,
		GADGIMMEDIATE,
		WDRAGGING,
		(APTR)&IconImage,
		NULL,NULL,NULL,NULL,
		0,0
	};

	static struct NewWindow IconNewWindow =
	{
		0,11,53,23,
		-1,-1,
		GADGETDOWN | INACTIVEWINDOW,
		BORDERLESS | RMBTRAP,
		&IconGadget,
		NULL,NULL,NULL,NULL,
		0,0,0,0,
		WBENCHSCREEN
	};

	struct Window *IconWindow;

	register struct IntuiMessage *IconMessage;
	long Seconds = 0,Micros = 0,CurrentSeconds,CurrentMicros,Class;

		/* Free some data. */

	FreeFastText();

	NewWindow . TopEdge = Window -> TopEdge;

	while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
		ReplyMsg(Massage);

	ClearMenuStrip(Window);

	CloseWindow(Window);

		/* Build the icon. */

	if(!(IconWindow = (struct Window *)OpenWindow(&IconNewWindow)))
		goto Finish;

	IconWindow -> UserData = (BYTE *)0x49434F4EL;

	FOREVER
	{
			/* Wait for the user to reactivate us. */

		WaitPort(IconWindow -> UserPort);

		if(IconMessage = (struct IntuiMessage *)GetMsg(IconWindow -> UserPort))
		{
			Class		= IconMessage -> Class;
			CurrentSeconds	= IconMessage -> Seconds;
			CurrentMicros	= IconMessage -> Micros;

			ReplyMsg(IconMessage);

			if(Class == GADGETDOWN)
			{
				if(DoubleClick(Seconds,Micros,CurrentSeconds,CurrentMicros))
					break;

				Seconds	= CurrentSeconds;
				Micros	= CurrentMicros;
			}

				/* Say, if you dragged an icon, released
				 * it and did so repeatedly, would you
				 * expect the icon to be double-clicked?
				 * Since Workbench icons don't behave that
				 * way we reset the double-click counter
				 * once the icon is released.
				 */

			if(Class == INACTIVEWINDOW)
				Seconds = Micros = 0;
		}
	}

		/* Remember icon position. */

	IconNewWindow . LeftEdge= IconWindow -> LeftEdge;
	IconNewWindow . TopEdge	= IconWindow -> TopEdge;

	CloseWindow(IconWindow);

		/* Restore window and display. */

Finish:	if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
		CloseAll(20);

	RPort = Window -> RPort;

	SetAPen(RPort,1);
	SetBPen(RPort,0);
	SetDrMd(RPort,JAM2);

	DrawBorder(RPort,&FarBrd[3],0,0);

	SetFont(RPort,DefaultFont);

	SetMenuStrip(Window,&FarMenu);

	if(!InitFastText(DefaultFont))
		CloseAll(20);

	DrawText(GetPropPosition(),FALSE);

	ClearRequest();
	PrintRequest("- No pending requests -");

	if(Pausing)
		SetWindowTitles(Window,"FarPrint v1.3 (pausing)",-1);
}

	/* Some stubs, we don't need these routines. */

void _cli_parse() {}
void _wb_parse() {}

void
main()
{
		/* Startup & initialization. */

	OpenAll();

	ClearRequest();
	PrintRequest("- No pending requests -");

	FOREVER
	{
			/* Wait for something to wake us up. */

		Wait(SIG_WINDOW | SIG_PORT);

AskPort:	if(!Pausing)
		{
			struct FarMessage *FarMessage;

			if(!(FarMessage = (struct FarMessage *)GetMsg(FarPort)))
				goto AskWindow;

				/* Add a text to the list? */

			if(FarMessage -> fm_Command == FM_ADDTXT)
			{
				AddText(FarMessage -> fm_Text);

				ReplyMsg(FarMessage);

				continue;
			}

				/* External caller requests input. */

			ClearRequest();
			PrintRequest("\"");PrintRequest(FarMessage -> fm_Identifier);PrintRequest("\"");

				/* Text or number required? */

			if(FarMessage -> fm_Command == FM_REQTXT)
			{
				PrintRequest(" requests string input.");
				FarGad[0] . Activation &= ~LONGINT;
			}
			else
			{
				PrintRequest(" requests numeric input.");
				FarGad[0] . Activation |= LONGINT;
			}

				/* Ask user to enter something. */

			OnGadget(&FarGad[0],Window,NULL);

			FOREVER
			{
				ActivateWindow(Window);
				ActivateGadget(&FarGad[0],Window,NULL);

				WaitPort(Window -> UserPort);

				if(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
				{
					ULONG Class = Massage -> Class;
					struct Gadget *ID = (struct Gadget *)Massage -> IAddress;

					ReplyMsg(Massage);

					if(Class == GADGETUP && ID -> GadgetID == 0)
						break;
				}
			}

			strcpy(FarMessage -> fm_Text,StrInfStr);
			setmem(StrInfStr,81,0);

			FarStrInf . BufferPos = FarStrInf . DispPos = 0;

			OffGadget(&FarGad[0],Window,NULL);

			ClearRequest();
			PrintRequest("- No pending requests -");

			ReplyMsg(FarMessage);
		}

			/* Examine the window. */

AskWindow:	while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
		{
			ULONG Class = Massage -> Class;
			USHORT Code = Massage -> Code;
			struct Gadget *ID = (struct Gadget *)Massage -> IAddress;
			USHORT MenuNum;
			struct MenuItem *Item;
			long Value;

			ReplyMsg(Massage);

				/* Scroll the scrollbar? */

			if(Class == GADGETDOWN && (ID -> GadgetID == 1 || ID -> GadgetID == 2))
			{
				FOREVER
				{
					Value = GetPropPosition();

					if(ID -> GadgetID == 1)
						SetPropPosition(Value - 1);

					if(ID -> GadgetID == 2)
						SetPropPosition(Value + 1);

					DrawText(GetPropPosition(),TRUE);

					if(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
					{
						Class = Massage -> Class;

						ReplyMsg(Massage);

						if(Class == GADGETUP)
							break;
					}
				}
			}

				/* Selected a menu item. */

			if(Class == MENUPICK)
			{
				MenuNum = Code;

				while(MenuNum != MENUNULL)
				{
					switch(ITEMNUM(MenuNum))
					{
						case 0:	Window -> Flags |= RMBTRAP;
							AutoRequest(Window,&AboutTxt[0],NULL,&AboutTxt[13],NULL,NULL,278,158);
							Window -> Flags &= ~RMBTRAP;

							goto AskPort;

						case 2:	SaveText();

							goto AskPort;

						case 3:	if(Pausing)
							{
								FarIntTxt[3] . IText	= (UBYTE *)"Pause                  ";
								FarMenuItem[3] . Command= 'P';

								SetWindowTitles(Window,"FarPrint v1.3",-1);
							}
							else
							{
								FarIntTxt[3] . IText	= (UBYTE *)"Continue               ";
								FarMenuItem[3] . Command= 'C';

								SetWindowTitles(Window,"FarPrint v1.3 (pausing)",-1);
							}

							Pausing ^= TRUE;

							goto AskPort;

						case 4:	Iconify();
							goto AskPort;

						case 5:	CloseAll(0);
							
						default:break;
					}

					Item = (struct MenuItem *)ItemAddress(&FarMenu,MenuNum);

					MenuNum = Item -> NextSelect;
				}
			}

				/* Proportional gadget container selected. */

			if(Class == GADGETDOWN && ID -> GadgetID == 3)
				DrawText(GetPropPosition(),TRUE);

				/* User drags the scrollbar. */

			if(Class == MOUSEMOVE)
				DrawText(GetPropPosition(),TRUE);

				/* Finis... */

			if(Class == CLOSEWINDOW)
				CloseAll(0);
		}
	}
}
