/*
**	termTextBuffer.c
**
**	Support routines for the text buffer.
**
**	Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* Gadget ID codes. */

enum	{	GAD_SCROLLER,GAD_UP,GAD_DOWN };

	/* Menu ID codes. */

enum	{	MEN_SEARCH,MEN_REPEAT,MEN_GOTO,MEN_CLEARBUF_CONTENTS,MEN_QUITBUF };

	/* Gadget ID codes. */

enum	{	GAD_STRING,GAD_LOAD,GAD_OK,GAD_CANCEL };

	/* A handy macro to determine the length of a string. */

#define LINE_WIDTH(s)	(s)[-1]

	/* The dimensions of the scroller images. */

#define ARROW_WIDTH	18
#define ARROW_HEIGHT	11

STATIC struct NewMenu BufferMenu[] =
{
	{ NM_TITLE, NULL,		 0 , 0, 0, (APTR)0},
	{  NM_ITEM, NULL,		 0 , 0, 0, (APTR)MEN_SEARCH},
	{  NM_ITEM, NULL,		 0 , 0, 0, (APTR)MEN_REPEAT},
	{  NM_ITEM, NM_BARLABEL,	 0 , 0, 0, (APTR)0},
	{  NM_ITEM, NULL,		 0 , 0, 0, (APTR)MEN_GOTO},
	{  NM_ITEM, NM_BARLABEL,	 0 , 0, 0, (APTR)0},
	{  NM_ITEM, NULL,		 0 , 0, 0, (APTR)MEN_CLEARBUF_CONTENTS},
	{  NM_ITEM, NM_BARLABEL,	 0 , 0, 0, (APTR)0},
	{  NM_ITEM, NULL,		 0 , 0, 0, (APTR)MEN_QUITBUF},

	{ NM_END, 0,			 0 , 0, 0, (APTR)0}
};

	/* Some private data (render info & window). */

STATIC struct Window		*BufferWindow;
STATIC struct Screen		*BufferScreen;

STATIC struct RastPort		*BPort;
STATIC APTR			 BufferVisualInfo;

STATIC LONG			 NumBufferLines,
				 NumBufferColumns,
				 LastTopLine;

STATIC BYTE			 BufferTerminated;

STATIC WORD			 LocalTextFontWidth,
				 LocalTextFontHeight,
				 LocalTextFontBase;

STATIC struct TTextAttr		 LocalTextFont;
STATIC UBYTE			 LocalTextFontName[MAX_FILENAME_LENGTH];

STATIC struct TTextAttr		 LocalUserFont;
STATIC UBYTE			 LocalUserFontName[MAX_FILENAME_LENGTH];

STATIC LONG			 TopLine = -1,
				 DisplayedLines;

STATIC struct SearchInfo	*BufferSearchInfo;
STATIC BYTE			 SearchForward = TRUE;

STATIC struct Gadget		*Scroller,
				*UpArrow,
				*DownArrow;

STATIC struct Image		*UpImage,
				*DownImage;

STATIC UWORD			*BufferLineWidths,
				*BufferLineOffsets,
				*BufferColumnOffsets;

	/* DeleteScroller(VOID):
	 *
	 *	Delete scroller and arrow objects.
	 */

STATIC VOID
DeleteScroller(VOID)
{
	if(Scroller)
	{
		DisposeObject(Scroller);

		Scroller = NULL;
	}

	if(UpArrow)
	{
		DisposeObject(UpArrow);

		UpArrow = NULL;
	}

	if(DownArrow)
	{
		DisposeObject(DownArrow);

		DownArrow = NULL;
	}

	if(UpImage)
	{
		DisposeObject(UpImage);

		UpImage = NULL;
	}

	if(DownImage)
	{
		DisposeObject(DownImage);

		DownImage = NULL;
	}
}

	/* CreateScroller(LONG Height):
	 *
	 *	Create scroller and arrow objects.
	 */

STATIC BYTE __regargs
CreateScroller(LONG Height)
{
	struct DrawInfo	*DrawInfo;
	BYTE		 Result = FALSE;

	if(DrawInfo = GetScreenDrawInfo(BufferScreen))
	{
		if(UpImage = (struct Image *)NewObject(NULL,"sysiclass",
			SYSIA_Size,	SYSISIZE_MEDRES,
			SYSIA_Which,	UPIMAGE,
			SYSIA_DrawInfo,	DrawInfo,
		TAG_DONE))
		{
			if(DownImage = (struct Image *)NewObject(NULL,"sysiclass",
				SYSIA_Size,	SYSISIZE_MEDRES,
				SYSIA_Which,	DOWNIMAGE,
				SYSIA_DrawInfo,	DrawInfo,
			TAG_DONE))
			{
				LONG ScrollerHeight,LeftEdge;

				ScrollerHeight = Height - 2 * ARROW_HEIGHT;

				LeftEdge = BufferScreen -> Width - ARROW_WIDTH;

				if(Scroller = NewObject(NULL,"propgclass",
					GA_ID,		GAD_SCROLLER,

					GA_Top,		0,
					GA_Left,	LeftEdge,
					GA_Width,	ARROW_WIDTH,
					GA_Height,	ScrollerHeight,
					GA_Immediate,	TRUE,
					GA_FollowMouse,	TRUE,
					GA_RelVerify,	TRUE,

					PGA_Freedom,	FREEVERT,
					PGA_NewLook,	TRUE,

					PGA_Visible,	1,
					PGA_Total,	1,
				TAG_DONE))
				{
					STATIC struct TagItem ArrowMappings[] = { GA_ID,GA_ID,TAG_END };

					if(UpArrow = NewObject(NULL,"buttongclass",
						GA_ID,		GAD_UP,
						GA_Image,	UpImage,
						GA_Left,	LeftEdge,
						GA_Top,		ScrollerHeight,
						GA_Height,	ARROW_HEIGHT,
						GA_Width,	ARROW_WIDTH,
						GA_Immediate,	TRUE,
						GA_RelVerify,	TRUE,
						GA_Previous,	Scroller,

						ICA_TARGET,	ICTARGET_IDCMP,
						ICA_MAP,	ArrowMappings,
					TAG_DONE))
					{
						if(DownArrow = NewObject(NULL,"buttongclass",
							GA_ID,		GAD_DOWN,
							GA_Image,	DownImage,
							GA_Left,	LeftEdge,
							GA_Top,		ScrollerHeight + ARROW_HEIGHT,
							GA_Height,	ARROW_HEIGHT,
							GA_Width,	ARROW_WIDTH,
							GA_Immediate,	TRUE,
							GA_RelVerify,	TRUE,
							GA_Previous,	UpArrow,

							ICA_TARGET,	ICTARGET_IDCMP,
							ICA_MAP,	ArrowMappings,
						TAG_DONE))
							Result = TRUE;
					}
				}
			}
		}

		FreeScreenDrawInfo(BufferScreen,DrawInfo);
	}

	if(!Result)
		DeleteScroller();

	return(Result);
}

	/* PrintLine(STRPTR Buffer,LONG LineNumber):
	 *
	 *	Print a line at a given line number in the displayed area.
	 */

STATIC VOID
PrintLine(STRPTR Buffer,LONG LineNumber)
{
	WORD Length = Buffer[-1];

		/* Print the text. */

	if(Length)
	{
		Move(BPort,0,BufferLineOffsets[LineNumber] + LocalTextFontBase);

		if(Length > NumBufferColumns)
			Length = NumBufferColumns;

		Text(BPort,Buffer,Length);
	}

		/* The line doesn't exactly fill the displayed line,
		 * so erase the remaining columns.
		 */

	if(Length < BufferLineWidths[LineNumber])
	{
		SetAPen(BPort,0);
		RectFill(BPort,BufferColumnOffsets[Length],BufferLineOffsets[LineNumber],BufferColumnOffsets[BufferLineWidths[LineNumber]] - 1,BufferLineOffsets[LineNumber + 1] - 1);
		SetAPen(BPort,1);
	}

	BufferLineWidths[LineNumber] = Length;
}

	/* RedrawScreen(LONG FirstLine):
	 *
	 *	Redraw the contents of the entire screen and return the
	 *	number of lines actually drawn.
	 */

STATIC LONG
RedrawScreen(LONG FirstLine)
{
	LONG i,Last,Line = 0,Result;

	ObtainSemaphore(BufferSemaphore);

		/* Determine last line to display. */

	if((Last = FirstLine + NumBufferLines) >= Lines)
		Last = Lines;

	Result = Last - FirstLine;

	if(Lines)
	{
		if(LastTopLine != -1)
		{
			LONG Delta = FirstLine - LastTopLine;

			if(ABS(Delta) < NumBufferLines)
			{
					/* No change? */

				if(!Delta)
				{
					ReleaseSemaphore(BufferSemaphore);

					return(Result);
				}
				else
				{
					LastTopLine = FirstLine;

						/* Scrolled up? */

					if(Delta < 0)
					{
						for(i = NumBufferLines - 1 ; i >= -Delta ; i--)
							BufferLineWidths[i] = BufferLineWidths[i + Delta];

						ClipBlit(BPort,0,0,BPort,0,BufferLineOffsets[-Delta],BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines + Delta],MINTERM_COPY);

						Last = FirstLine - Delta;
					}
					else
					{
						for(i = Delta ; i < NumBufferLines ; i++)
							BufferLineWidths[i - Delta] = BufferLineWidths[i];

							/* Scrolled down. */

						ClipBlit(BPort,0,BufferLineOffsets[Delta],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - Delta],MINTERM_COPY);

						FirstLine += NumBufferLines - Delta;

						Line = NumBufferLines - Delta;
					}
				}
			}
			else
				LastTopLine = FirstLine;
		}
		else
			LastTopLine = FirstLine;

		if(BufferLines)
		{
			for(i = FirstLine ; i < Last ; i++)
				PrintLine(BufferLines[i],Line++);
		}
	}

	ReleaseSemaphore(BufferSemaphore);

		/* We didn't fill the whole screen, so clear the rest. */

	if(Result < NumBufferLines)
	{
		WORD i;

		for(i = Result ; i < NumBufferLines ; i++)
			BufferLineWidths[i] = 0;

		SetAPen(BPort,0);
		RectFill(BPort,0,BufferLineOffsets[Result],BufferColumnOffsets[NumBufferColumns] - 1,BufferLineOffsets[NumBufferLines] - 1);
		SetAPen(BPort,1);
	}

	return(Result);
}

	/* MarkArea(LONG Column,LONG Line,LONG Length):
	 *
	 *	Mark an area in the term Buffer window.
	 */

STATIC VOID
MarkArea(LONG Column,LONG Line,LONG Length)
{
	STATIC LONG OldColumn = -1,OldLine = -1,OldLength = -1;

	if(OldColumn != -1)
		ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[OldColumn],BufferLineOffsets[OldLine],BufferColumnOffsets[OldLength],LocalTextFontHeight,MINTERM_NOT_C);

	if(Column != -1)
	{
		if(OldColumn != Column || OldLine != Line || OldLength != Length)
			ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[Column],BufferLineOffsets[Line],BufferColumnOffsets[Length],LocalTextFontHeight,MINTERM_NOT_C);
	}

	OldColumn	= Column;
	OldLine		= Line;
	OldLength	= Length;
}

	/* BufferClipPage(struct BlockMarker *Marker):
	 *
	 *	Send the marked area to the clipboard.
	 */

STATIC VOID __inline
BufferClipPage(struct BlockMarker *Marker)
{
	if(BufferLines)
	{
		struct IFFHandle *Handle;

		if(Handle = AllocIFF())
		{
			if(Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit))
			{
				InitIFFasClip(Handle);

				if(!OpenIFF(Handle,IFFF_WRITE))
				{
					if(!PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN))
					{
						if(!PushChunk(Handle,0,ID_CHRS,IFFSIZE_UNKNOWN))
						{
							LONG	Lines = Marker -> LastLine - Marker -> FirstLine - 1,
								i;

							if(LINE_WIDTH(BufferLines[Marker -> FirstLine]) > Marker -> FirstColumn)
								WriteTrimmedString(Handle,&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],LINE_WIDTH(BufferLines[Marker -> FirstLine]) - Marker -> FirstColumn);

							WriteChunkBytes(Handle,"\n",1);

							if(Lines > 0)
							{
								for(i = 0 ; i < Lines ; i++)
								{
									if(LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]))
										WriteTrimmedString(Handle,BufferLines[Marker -> FirstLine + 1 + i],LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]));

									WriteChunkBytes(Handle,"\n",1);
								}
							}

							if(Marker -> LastColumn > LINE_WIDTH(BufferLines[Marker -> LastLine]))
								WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],LINE_WIDTH(BufferLines[Marker -> LastLine]));
							else
								WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],Marker -> LastColumn);

							WriteChunkBytes(Handle,"\n",1);

							PopChunk(Handle);
						}

						PopChunk(Handle);
					}

					CloseIFF(Handle);
				}

				CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
			}

			FreeIFF(Handle);
		}
	}
}

	/* BufferClip(VOID):
	 *
	 *	Start buffer marking process.
	 */

STATIC VOID
BufferClip(VOID)
{
	struct BlockMarker	*Marker;
	LONG			 FirstX = BufferWindow -> MouseX / LocalTextFontWidth,
				 FirstY = BufferWindow -> MouseY / LocalTextFontHeight;

	if(Marker = BM_SetMark(BufferWindow -> RPort,ToggleSelect,ToggleSelect,NumBufferColumns,NumBufferLines,0,0,TopLine,Lines,BufferWindow -> MouseX / LocalTextFontWidth,BufferWindow -> MouseY / LocalTextFontHeight,LocalTextFontWidth,LocalTextFontHeight))
	{
		struct IntuiMessage	*Massage;
		ULONG			 Code,IClass;
		BYTE			 Done = FALSE,Aborted = FALSE;
		LONG			 PlusX = LocalTextFontWidth - 1,
					 MouseX,MouseY,
					 Delta = 0;

		ReportMouse(TRUE,BufferWindow);

		while(!Done)
		{
			WaitPort(BufferWindow -> UserPort);

			while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
			{
				IClass	= Massage -> Class;
				Code	= Massage -> Code;
				MouseX	= Massage -> MouseX;
				MouseY	= Massage -> MouseY;

				ReplyMsg(Massage);

				if(IClass == IDCMP_INACTIVEWINDOW)
				{
					Done = Aborted = TRUE;

					break;
				}

				if(IClass == IDCMP_INTUITICKS && Delta != 0)
				{
					if(BufferLines)
					{
						if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
						{
							if(Delta < 0)
							{
								WORD i;

								for(i = NumBufferLines - 1 ; i > -Delta ; i--)
									BufferLineWidths[i] = BufferLineWidths[i + Delta];

								if(DisplayedLines)
									ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);

								BufferLineWidths[0] = NumBufferColumns;

								PrintLine(BufferLines[--TopLine],0);
							}
							else
							{
								WORD i;

								for(i = Delta ; i < NumBufferLines ; i++)
									BufferLineWidths[i - Delta] = BufferLineWidths[i];

								if(DisplayedLines)
									ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);

								BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;

								PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);

								TopLine++;
							}

							Marker -> Top += Delta;
							Marker -> LastY -= Delta;

							BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
						}
						else
							Delta = 0;
					}
				}

				if(IClass == IDCMP_MOUSEBUTTONS && (Code & IECODE_UP_PREFIX))
				{
					BM_Draw(Marker,Marker -> Unselect);

					Done = TRUE;

					break;
				}

				if(IClass == IDCMP_MOUSEMOVE)
				{
					BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,0);

					if(MouseY < 1)
					{
						if(TopLine > 0)
							Delta = -1;
					}
					else
					{
						if(MouseY >= BufferWindow -> Height - 1 && TopLine + NumBufferLines < Lines)
							Delta = 1;
					}

					while(Delta)
					{
						MouseX	= Window -> MouseX;
						MouseY	= Window -> MouseY;

						if((Delta < 0 && MouseY > 0) || (Delta > 0 && MouseY < BufferWindow -> Height - 1))
							break;
						else
						{
							if(BufferLines)
							{
								if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
								{
									if(Delta < 0)
									{
										WORD i;

										for(i = NumBufferLines - 1 ; i > -Delta ; i--)
											BufferLineWidths[i] = BufferLineWidths[i + Delta];

										if(DisplayedLines)
											ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);

										BufferLineWidths[0] = NumBufferColumns;

										PrintLine(BufferLines[--TopLine],0);
									}
									else
									{
										WORD i;

										for(i = Delta ; i < NumBufferLines ; i++)
											BufferLineWidths[i - Delta] = BufferLineWidths[i];

										if(DisplayedLines)
											ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);

										BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;

										PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);

										TopLine++;
									}

									Marker -> Top	+= Delta;
									Marker -> LastY	-= Delta;

									BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);

									SetGadgetAttrs(Scroller,BufferWindow,NULL,
										PGA_Top,TopLine,
									TAG_DONE);
								}
								else
									break;
							}
							else
								break;
						}
					}

					Delta = 0;
				}
			}
		}

		ReportMouse(FALSE,BufferWindow);

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

		if(!Aborted)
		{
			if(FirstX != BufferWindow -> MouseX / LocalTextFontWidth || FirstY != BufferWindow -> MouseY / LocalTextFontHeight)
			{
				SetWait(BufferWindow);

				if(Marker -> FirstColumn == Marker -> Width)
				{
					Marker -> FirstLine++;

					Marker -> FirstColumn = 0;
				}

				if(Marker -> LastColumn == 0)
				{
					Marker -> LastLine--;

					Marker -> LastColumn = Marker -> Width;
				}

				if(Marker -> FirstLine <= Marker -> LastLine)
				{
					if(Marker -> FirstLine != Marker -> LastLine || Marker -> FirstColumn != Marker -> LastColumn)
					{
						if(BufferLines)
						{
							if(Marker -> FirstLine == Marker -> LastLine)
								SaveClip(&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],Marker -> LastColumn - Marker -> FirstColumn);
							else
								BufferClipPage(Marker);
						}
					}
				}

				ClrWait(BufferWindow);
			}
		}

		FreeVec(Marker);
	}
}

	/* StartBufferSearch(BYTE NewSearchString):
	 *
	 *	Search the buffer for a string.
	 */

STATIC VOID
StartBufferSearch(BYTE NewSearchString)
{
	BlockWindow(BufferWindow);

	if(Lines)
	{
		STATIC UBYTE SearchBuffer[256];

		BYTE StartSearch = TRUE;

		if(NewSearchString || !SearchBuffer[0])
		{
			if(GetSearchString(BufferWindow,&BufferTerminated,SearchBuffer,&SearchForward))
			{
				if(SearchBuffer[0])
				{
					if(BufferSearchInfo)
						DeleteSearchInfo(BufferSearchInfo);

					BufferSearchInfo = CreateSearchInfo(SearchBuffer,SearchForward);
				}
				else
					StartSearch = FALSE;
			}
			else
				StartSearch = FALSE;
		}
		else
		{
			if(!BufferSearchInfo)
				BufferSearchInfo = CreateSearchInfo(SearchBuffer,TRUE);
		}

		if(StartSearch && BufferSearchInfo)
		{
			LONG LineNumber;

			ObtainSemaphore(BufferSemaphore);

			LineNumber = SearchTextBuffer(BufferSearchInfo);

			ReleaseSemaphore(BufferSemaphore);

			if(LineNumber == -1)
			{
				BlockWindows();

				MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_DID_NOT_FIND_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SearchBuffer);

				ReleaseWindows();

				FlushMsg(BufferWindow);

				BufferSearchInfo -> FoundY = -1;

				MarkArea(-1,-1,-1);
			}
			else
			{
				if(LineNumber < TopLine)
				{
					MarkArea(-1,-1,-1);

					DisplayedLines = RedrawScreen(TopLine = LineNumber);

					SetGadgetAttrs(Scroller,BufferWindow,NULL,
						PGA_Top,TopLine,
					TAG_DONE);
				}
				else
				{
					if(LineNumber > TopLine + DisplayedLines - 1)
					{
						MarkArea(-1,-1,-1);

						if(LineNumber >= Lines - NumBufferLines)
						{
							LONG NewCurrentLine;

							if((NewCurrentLine = Lines - NumBufferLines) < 0)
								NewCurrentLine = 0;

							if(TopLine != NewCurrentLine)
								DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
						}
						else
							DisplayedLines = RedrawScreen(TopLine = LineNumber);

						SetGadgetAttrs(Scroller,BufferWindow,NULL,
							PGA_Top,TopLine,
						TAG_DONE);
					}
				}

				MarkArea(BufferSearchInfo -> FoundX,LineNumber - TopLine,BufferSearchInfo -> PatternWidth);
			}
		}
	}
	else
		MyEasyRequest(BufferWindow,LocaleString(MSG_GLOBAL_NOTHING_IN_THE_BUFFER_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));

	ReleaseWindow(BufferWindow);
}

	/* LaunchBuffer():
	 *
	 *	Launch the buffer process.
	 */

BYTE
LaunchBuffer()
{
		/* Is the buffer process already running? */

	if(BufferProcess)
	{
			/* Tell it to bring its screen to the front. */

		Signal(BufferProcess,SIG_TOFRONT);

			/* Return success. */

		return(TRUE);
	}
	else
	{
		struct MsgPort	*ReplyPort;
		BYTE		 Result = FALSE;

			/* Create reply port. */

		if(ReplyPort = CreateMsgPort())
		{
			struct Message *Message;

				/* Create startup message. */

			if(Message = (struct Message *)AllocVec(sizeof(struct Message),MEMF_ANY|MEMF_CLEAR))
			{
				Message -> mn_ReplyPort	= ReplyPort;
				Message -> mn_Length	= sizeof(struct Message);

					/* Launc the buffer process. */

				if(BufferProcess = (struct Process *)CreateNewProcTags(
					NP_Entry,	BufferServer,
					NP_Name,	"term buffer process",
					NP_Priority,	0,
					NP_StackSize,	8192,
					NP_WindowPtr,	-1,
				TAG_END))
				{
						/* Send the startup message. */

					PutMsg(&BufferProcess -> pr_MsgPort,Message);

						/* Wait for reply. */

					WaitPort(ReplyPort);

						/* Pick up the reply. */

					GetMsg(ReplyPort);

						/* Is the process still running? */

					if(BufferProcess)
						Result = TRUE;
				}

					/* Free the startup message. */

				FreeVec(Message);
			}

				/* Delete the reply port. */

			DeleteMsgPort(ReplyPort);
		}

			/* Return the result. */

		return(Result);
	}
}

	/* TerminateBuffer():
	 *
	 *	Terminate the buffer process.
	 */

VOID
TerminateBuffer()
{
	if(BufferProcess)
	{
		Forbid();

		Signal(BufferProcess,SIG_KILL);

		ClrSignal(SIG_HANDSHAKE);

		Wait(SIG_HANDSHAKE);

		Permit();
	}

	LastTopLine = -1;
}

	/* BufferServer():
	 *
	 *	Asynchronous task to display the data stored in the
	 *	scrollback display buffer.
	 */

VOID __saveds
BufferServer()
{
	struct ColorSpec	 ColorSpec[3];

	ULONG			 SignalSet;

	struct IntuiMessage	*Massage;
	ULONG			 IClass,Code,Qualifier,LastQualifier = NULL;
	UBYTE			 Char,LastChar = 0;

	LONG			 MouseX,MouseY,LastWidth = 0;

	UBYTE			 PercentBuffer[80];

	struct Menu		*BufferMenuStrip;

	LONG			 Width;
	ULONG			 DisplayMode;

	struct Rectangle	 DisplayClip;
	struct DimensionInfo	 DimensionInfo;

	UWORD			 SomeColour,Height;

	struct TextFont		*LocalFont;

	struct Message		*StartupMessage;
	struct MsgPort		*StartupPort = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
	struct TagItem		*TagList;

		/* Wait for startup message. */

	WaitPort(StartupPort);

	StartupMessage = GetMsg(StartupPort);

		/* Clone the global font data. */

	LocalTextFontWidth	= TextFontWidth;
	LocalTextFontHeight	= TextFontHeight;
	LocalTextFontBase	= TextFontBase;

	memcpy(&LocalTextFont,&TextAttr,sizeof(struct TTextAttr));

	LocalTextFont . tta_Name = LocalTextFontName;

	strcpy(LocalTextFontName,TextAttr . tta_Name);

	memcpy(&LocalUserFont,&UserFont,sizeof(struct TTextAttr));

	LocalUserFont . tta_Name = LocalUserFontName;

	strcpy(LocalUserFontName,UserFont . tta_Name);

		/* Reset top line index. */

	LastTopLine = -1;

		/* Up and running... */

	BufferTerminated = FALSE;

		/* Set up the startup colours for our buffer screen. */

	ColorSpec[0] . ColorIndex	= 0;
	ColorSpec[0] . Red		= (Config -> ScreenConfig -> Colours[0] >> 8) & 0xF;
	ColorSpec[0] . Green		= (Config -> ScreenConfig -> Colours[0] >> 4) & 0xF;
	ColorSpec[0] . Blue		= (Config -> ScreenConfig -> Colours[0]     ) & 0xF;

	switch(Config -> ScreenConfig -> ColourMode)
	{
		case COLOUR_EIGHT:

			SomeColour = Config -> ScreenConfig -> Colours[7];
			break;

		case COLOUR_SIXTEEN:

			SomeColour = Config -> ScreenConfig -> Colours[15];
			break;

		case COLOUR_AMIGA:
		case COLOUR_MONO:

			SomeColour = Config -> ScreenConfig -> Colours[1];
			break;
	}

	ColorSpec[1] . ColorIndex	= 1;
	ColorSpec[1] . Red		= (SomeColour >> 8) & 0xF;
	ColorSpec[1] . Green		= (SomeColour >> 4) & 0xF;
	ColorSpec[1] . Blue		= (SomeColour     ) & 0xF;

	ColorSpec[2] . ColorIndex	= -1;

		/* We'll use a fixed screen width, only the
		 * height is adapted from the main screen.
		 */

	DisplayMode = Config -> ScreenConfig -> DisplayMode;

		/* Set up the actual width of the screen we want. */

	Width = Config -> CaptureConfig -> BufferWidth * LocalTextFontWidth + ARROW_WIDTH + 1;

		/* Get the mode dimension info. */

	if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,DisplayMode))
	{
			/* Determine maximum text overscan width. */

		LONG TextWidth = DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1;

			/* Too small? */

		if(Width < DimensionInfo . MinRasterWidth)
			Width = DimensionInfo . MinRasterWidth;

			/* Far too large? */

		if(Width > DimensionInfo . MaxRasterWidth)
			Width = DimensionInfo . MaxRasterWidth;

			/* A bit too large? */

		if(Width > TextWidth)
			Width = TextWidth;

		if(LocalFont = OpenFont(&LocalTextFont))
		{
				/* Inquire the text overscan dimensions. */

			if(QueryOverscan(DisplayMode,&DisplayClip,OSCAN_TEXT))
			{
					/* Centre the buffer screen. */

				if(DisplayClip . MaxX - DisplayClip . MinX + 1 > Width)
				{
					LONG Differ = (DisplayClip . MaxX - DisplayClip . MinX + 1 - Width) / 2;

					switch(Config -> CaptureConfig -> BufferScreenPosition)
					{
						case SCREEN_LEFT:

							DisplayClip . MaxX = DisplayClip . MinX + Width;
							break;

						case SCREEN_RIGHT:

							DisplayClip . MinX = DisplayClip . MaxX - Width;
							break;

						case SCREEN_CENTRE:

							DisplayClip . MinX += Differ;
							DisplayClip . MaxX -= Differ;

							break;
					}
				}

					/* Open a single bitplane clone of the main screen. */

				if(BufferScreen = (struct Screen *)OpenScreenTags(NULL,
					SA_Title,	LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),
					SA_Depth,	1,
					SA_DClip,	&DisplayClip,
					SA_DisplayID,	DisplayMode,
					SA_Font,	&LocalUserFont,
					SA_Behind,	TRUE,
					SA_AutoScroll,	TRUE,
					SA_Colors,	ColorSpec,
				TAG_END))
				{
					if(BufferVisualInfo = GetVisualInfo(BufferScreen,TAG_DONE))
					{
						LocalizeMenu(BufferMenu,MSG_TERMBUFFER_PROJECT_MEN);

						if(BufferMenuStrip = CreateMenus(BufferMenu,TAG_DONE))
						{
							if(LayoutMenus(BufferMenuStrip,BufferVisualInfo,
								GTMN_TextAttr,		&LocalUserFont,
								GTMN_NewLookMenus,	TRUE,
							TAG_DONE))
							{
								WORD TitleOffset,Len;

								Height = (BufferScreen -> Height - (BufferScreen -> BarHeight + 2)) / LocalTextFontHeight;

								Len = strlen(LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT));

								TitleOffset = TextLength(BufferScreen -> BarLayer -> rp,LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),Len) + TextLength(BufferScreen -> BarLayer -> rp," ",1) + 4;

									/* Open a cute window on our buffer screen. */

								if(BufferWindow = OpenWindowTags(NULL,
									WA_Top,		BufferScreen -> BarHeight + 2,
									WA_Left,	0,
									WA_Width,	BufferScreen -> Width,
									WA_Height,	Height * LocalTextFontHeight,
									WA_Backdrop,	TRUE,
									WA_Borderless,	TRUE,
									WA_SmartRefresh,FALSE,
									WA_CustomScreen,BufferScreen,
									WA_RMBTrap,	TRUE,
									WA_NewLookMenus,TRUE,
									WA_RptQueue,	1,
									WA_IDCMP,	IDCMP_IDCMPUPDATE | IDCMP_RAWKEY | IDCMP_INACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP_MENUPICK | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE,
								TAG_DONE))
								{
									if(BufferLineWidths = (UWORD *)AllocVec(2 * sizeof(UWORD) * (BufferWindow -> Height / LocalTextFontHeight + 1) + sizeof(UWORD) * (BufferWindow -> Width / LocalTextFontWidth + 1),MEMF_ANY | MEMF_CLEAR))
									{
										UWORD	Index;
										WORD	i;

										BufferLineOffsets	= &BufferLineWidths[BufferWindow -> Height / LocalTextFontHeight + 1];
										BufferColumnOffsets	= &BufferLineOffsets[BufferWindow -> Height / LocalTextFontHeight + 1];

										for(i = Index = 0 ; i < BufferWindow -> Height / LocalTextFontHeight + 1 ; i++)
										{
											BufferLineOffsets[i] = Index;

											Index += LocalTextFontHeight;
										}

										for(i = Index = 0 ; i < BufferWindow -> Width / LocalTextFontWidth + 1 ; i++)
										{
											BufferColumnOffsets[i] = Index;

											Index += LocalTextFontWidth;
										}

										if(CreateScroller(BufferWindow -> Height))
										{
												/* Signal our father process that
												 * we're running.
												 */

											ReplyMsg(StartupMessage);

											StartupMessage = NULL;

											SetMenuStrip(BufferWindow,BufferMenuStrip);

											AddGList(BufferWindow,Scroller,(UWORD)-1,(UWORD)-1,NULL);
											RefreshGList(Scroller,BufferWindow,NULL,(UWORD)-1);

												/* Determine maximum dimensions of
												 * the buffer screen (in rows and
												 * columns).
												 */

											NumBufferColumns	= (BufferWindow -> Width - (ARROW_WIDTH + 1)) / LocalTextFontWidth;
											NumBufferLines		= BufferWindow -> Height / LocalTextFontHeight;

											if(TopLine == -1 || !Config -> CaptureConfig -> RememberBufferScreen)
											{
												switch(Config -> CaptureConfig -> OpenBufferScreen)
												{
													case BUFFER_TOP:

														TopLine = 0;
														break;

													case BUFFER_END:

														if((TopLine = Lines - NumBufferLines) < 0)
															TopLine = 0;

														break;

													default:

														TopLine = 0;
														break;
												}
											}

											if(TopLine > Lines - NumBufferLines)
												TopLine = 0;

Restart:										BPort = BufferWindow -> RPort;

											SetFont(BPort,LocalFont);

												/* Bring the screen to the front. */

											BumpWindow(BufferWindow);

												/* Set the drawing pens for the window. */

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

												/* Initial creation of the buffer display. */

											DisplayedLines = RedrawScreen(TopLine);

											SetGadgetAttrs(Scroller,BufferWindow,NULL,
												PGA_Top,	TopLine,
												PGA_Total,	Lines,
												PGA_Visible,	NumBufferLines,
											TAG_DONE);

											BufferWindow -> Flags &= ~WFLG_RMBTRAP;

											do
											{
													/* Show where we are. */

												if(Lines)
												{
													LONG Width;

													SetAPen(BufferScreen -> BarLayer -> rp,0);
													SetBPen(BufferScreen -> BarLayer -> rp,1);
													SetDrMd(BufferScreen -> BarLayer -> rp,JAM2);

													if(LocaleBase)
														SPrintf(PercentBuffer,"%lD/%lD (%ld%%)",TopLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (TopLine + DisplayedLines)) / Lines);
													else
														SPrintf(PercentBuffer,"%ld/%ld (%ld%%)",TopLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (TopLine + DisplayedLines)) / Lines);

													Len = strlen(PercentBuffer);

													Move(BufferScreen -> BarLayer -> rp,TitleOffset,BufferScreen -> BarLayer -> rp -> Font -> tf_Baseline + 1);
													Text(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);

													Width = TextLength(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);

													if(LastWidth > Width)
													{
														SetAPen(BufferScreen -> BarLayer -> rp,1);

														RectFill(BufferScreen -> BarLayer -> rp,TitleOffset + Width,1,TitleOffset + LastWidth - 1,BufferScreen -> BarLayer -> rp -> Font -> tf_YSize);
													}

													LastWidth = Width;
												}

												SignalSet = Wait(SIG_KILL | SIG_TOFRONT | SIG_UPDATE | SIG_MOVEUP | PORTMASK(BufferWindow -> UserPort));

													/* Leave the town? */

												if(SignalSet & SIG_KILL)
													BufferTerminated = TRUE;

													/* Bring our window to the front. */

												if(SignalSet & SIG_TOFRONT)
													BumpWindow(BufferWindow);

													/* We've got one more line in the
													 * buffer.
													 */

												if(SignalSet & SIG_UPDATE)
												{
													if(BufferLines && Lines)
													{
														if(Lines - TopLine > DisplayedLines && DisplayedLines < NumBufferLines)
														{
															LONG i = TopLine + DisplayedLines;

															do
																PrintLine(BufferLines[i++],DisplayedLines++);
															while(DisplayedLines < NumBufferLines && i < Lines);
														}
													}

													SetGadgetAttrs(Scroller,BufferWindow,NULL,
														PGA_Total,	Lines,
														PGA_Visible,	DisplayedLines,
													TAG_DONE);

													Signal(ThisProcess,SIG_HANDSHAKE);
												}

													/* The contents of the buffer have moved
													 * up a line.
													 */

												if(SignalSet & SIG_MOVEUP)
												{
													if(TopLine > 0)
													{
														LastTopLine = --TopLine;

														SetGadgetAttrs(Scroller,BufferWindow,NULL,
															PGA_Top,TopLine,
														TAG_DONE);
													}
													else
													{
														LONG i;

														MarkArea(-1,-1,-1);

														for(i = 0 ; i < NumBufferLines - 1 ; i++)
															BufferLineWidths[i] = BufferLineWidths[i + 1];

														ClipBlit(BPort,0,BufferLineOffsets[1],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);

														PrintLine(BufferLines[NumBufferLines - 1],NumBufferLines - 1);
													}

													Signal(ThisProcess,SIG_HANDSHAKE);
												}

													/* Process the incoming window
													 * input.
													 */

												while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
												{
													IClass		= Massage -> Class;
													Code		= Massage -> Code;
													Qualifier	= Massage -> Qualifier;
													MouseX		= Massage -> MouseX;
													MouseY		= Massage -> MouseY;
													TagList		= (struct TagItem *)Massage -> IAddress;

														/* This hack is necessary to obtain the
														 * character codes generated for the cursor
														 * keys. A control or alternate qualifier
														 * would spoil the result (i.e. we would
														 * not get a valid key code).
														 */

													Massage -> Qualifier = NULL;

													Char = KeyConvert(Massage,NULL,NULL);

														/* Just in case anybody needs it... */

													Massage -> Qualifier = Qualifier;

													ReplyMsg((struct Message *)Massage);

													if(IClass == IDCMP_IDCMPUPDATE)
													{
														switch(GetTagData(GA_ID,0,TagList))
														{
															case GAD_UP:

																if(TopLine > 0)
																{
																	TopLine--;

																	MarkArea(-1,-1,-1);

																	SetGadgetAttrs(Scroller,BufferWindow,NULL,
																		PGA_Top,TopLine,
																	TAG_DONE);

																	DisplayedLines = RedrawScreen(TopLine);
																}

																break;

															case GAD_DOWN:

																if(TopLine + NumBufferLines < Lines)
																{
																	TopLine++;

																	MarkArea(-1,-1,-1);

																	SetGadgetAttrs(Scroller,BufferWindow,NULL,
																		PGA_Top,TopLine,
																	TAG_DONE);

																	DisplayedLines = RedrawScreen(TopLine);
																}

																break;
														}
													}

													if(IClass == IDCMP_MOUSEMOVE || IClass == IDCMP_GADGETDOWN || IClass == IDCMP_GADGETUP)
													{
														LONG Position;

														GetAttr(PGA_Top,Scroller,&Position);

														if(Position != TopLine)
														{
															MarkArea(-1,-1,-1);

															DisplayedLines = RedrawScreen(TopLine = Position);
														}
													}

													if(IClass == IDCMP_RAWKEY)
													{
														if(Code == HELP_CODE)
															GuideDisplay(CONTEXT_TEXTBUFFER);

														if(LastChar)
														{
															if((Code & IECODE_UP_PREFIX) || !(LastQualifier & IEQUALIFIER_REPEAT))
															{
																SetGadgetAttrs(Scroller,BufferWindow,NULL,
																	PGA_Top,TopLine,
																TAG_DONE);
															}
														}

														if(LastChar = Char)
														{
																/* Use the numeric keypad keys to
																 * move through the buffer.
																 */

															if(Qualifier & IEQUALIFIER_NUMERICPAD)
															{
																	/* Remove the numpad qualifier. */

																Qualifier &= ~IEQUALIFIER_NUMERICPAD;

																switch(Char - '0')
																{
																		/* Jump to bottom. */

																	case 1: Char = CDN;
																		Qualifier |= IEQUALIFIER_CONTROL;
																		break;

																		/* Jump to top. */

																	case 7: Char = CUP;
																		Qualifier |= IEQUALIFIER_CONTROL;
																		break;

																		/* Move one page down. */

																	case 3: Char = CDN;
																		Qualifier |= IEQUALIFIER_LSHIFT;
																		break;

																		/* Move one page up. */

																	case 9: Char = CUP;
																		Qualifier |= IEQUALIFIER_LSHIFT;
																		break;

																		/* Move one line down. */

																	case 2: Char = CDN;
																		break;

																		/* Move one line up. */

																	case 8: Char = CUP;
																		break;
																}
															}

																/* Check cursor keys. */

															switch(Char)
															{
																	/* Scroll the buffer up. */

																case CUP:

																	if(Qualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
																	{
																		MarkArea(-1,-1,-1);

																		if(TopLine)
																		{
																			DisplayedLines = RedrawScreen(TopLine = 0);

																			LastChar = 0;

																			SetGadgetAttrs(Scroller,BufferWindow,NULL,
																				PGA_Top,TopLine,
																			TAG_DONE);
																		}

																		break;
																	}

																	if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
																	{
																		LONG NewCurrentLine;

																		if((NewCurrentLine = TopLine - NumBufferLines) < 0)
																			NewCurrentLine = 0;

																		MarkArea(-1,-1,-1);

																		if(NewCurrentLine != TopLine)
																		{
																			DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);

																			LastChar = 0;

																			SetGadgetAttrs(Scroller,BufferWindow,NULL,
																				PGA_Top,TopLine,
																			TAG_DONE);
																		}

																		break;
																	}

																	if(TopLine)
																	{
																		MarkArea(-1,-1,-1);

																		DisplayedLines = RedrawScreen(--TopLine);
																	}

																	break;

																	/* Scroll the buffer down. */

																case CDN:

																	if(Qualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
																	{
																		LONG NewCurrentLine;

																		if((NewCurrentLine = Lines - NumBufferLines) < 0)
																			NewCurrentLine = 0;

																		MarkArea(-1,-1,-1);

																		if(TopLine != NewCurrentLine)
																		{
																			DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);

																			LastChar = 0;

																			SetGadgetAttrs(Scroller,BufferWindow,NULL,
																				PGA_Top,TopLine,
																			TAG_DONE);
																		}

																		break;
																	}

																	if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
																	{
																		LONG NewCurrentLine;

																		if((NewCurrentLine = TopLine + (2 * NumBufferLines)) > Lines)
																			NewCurrentLine = Lines;

																		if((NewCurrentLine = NewCurrentLine - NumBufferLines) < 0)
																			NewCurrentLine = 0;

																		MarkArea(-1,-1,-1);

																		if(NewCurrentLine != TopLine)
																		{
																			DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);

																			LastChar = 0;

																			SetGadgetAttrs(Scroller,BufferWindow,NULL,
																				PGA_Top,TopLine,
																			TAG_DONE);
																		}

																		break;
																	}

																	if(TopLine + NumBufferLines < Lines)
																	{
																		MarkArea(-1,-1,-1);

																		DisplayedLines = RedrawScreen(++TopLine);
																	}

																	break;
															}

															LastQualifier = Qualifier;
														}
														else
															LastQualifier = NULL;

														continue;
													}

														/* User hit a mouse button. */

													if(IClass == IDCMP_MOUSEBUTTONS && !(Code & IECODE_UP_PREFIX))
													{
														MarkArea(-1,-1,-1);

															/* Reasonable dimensions? */

														if(MouseY / LocalTextFontHeight < DisplayedLines && MouseX / LocalTextFontWidth < NumBufferColumns)
														{
															ObtainSemaphore(BufferSemaphore);

															BufferClip();

															LastTopLine = TopLine;

															ReleaseSemaphore(BufferSemaphore);

															if(Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
																Signal(ThisProcess,SIG_CLIP);

															break;
														}
													}

													if(IClass == IDCMP_MENUPICK)
													{
														struct MenuItem *MenuItem;

														while(Code != MENUNULL)
														{
															MenuItem = ItemAddress(BufferMenuStrip,Code);

															switch((ULONG)GTMENUITEM_USERDATA(MenuItem))
															{
																case MEN_SEARCH:

																	StartBufferSearch(TRUE);
																	break;

																case MEN_REPEAT:

																	StartBufferSearch(FALSE);
																	break;

																case MEN_GOTO:

																	if(Window)
																		BumpWindow(Window);

																	break;

																case MEN_QUITBUF:

																	BufferTerminated = TRUE;
																	break;

																case MEN_CLEARBUF_CONTENTS:

																	if(Lines)
																	{
																		BlockWindows();

																		BlockWindow(BufferWindow);

																		if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
																		{
																			FreeBuffer();

																			ReleaseWindow(BufferWindow);

																			ReleaseWindows();

																			FlushMsg(BufferWindow);

																			TopLine = 0;

																			goto Restart;
																		}
																		else
																		{
																			if(MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT),Lines))
																			{
																				FreeBuffer();

																				ReleaseWindow(BufferWindow);

																				ReleaseWindows();

																				FlushMsg(BufferWindow);

																				TopLine = 0;

																				goto Restart;
																			}
																		}

																		ReleaseWindow(BufferWindow);

																		ReleaseWindows();

																		FlushMsg(BufferWindow);
																	}

																	break;
															}

															Code = MenuItem -> NextSelect;
														}
													}

												}
											}
											while(!BufferTerminated);

											RemoveGList(BufferWindow,Scroller,(UWORD)-1);

											DeleteScroller();
										}

										FreeVec(BufferLineWidths);
									}

									if(Window)
										BumpWindow(Window);

									MarkArea(-1,-1,-1);

									ScreenToBack(BufferScreen);

									BufferWindow -> Flags |= WFLG_RMBTRAP;

									ClearMenuStrip(BufferWindow);

									CloseWindow(BufferWindow);
								}
							}

							FreeMenus(BufferMenuStrip);
						}

						FreeVisualInfo(BufferVisualInfo);
					}

					CloseScreen(BufferScreen);
				}
			}

			CloseFont(LocalFont);
		}
	}

		/* Release the search buffer data. */

	if(BufferSearchInfo)
	{
		DeleteSearchInfo(BufferSearchInfo);

		BufferSearchInfo = NULL;
	}

	Forbid();

	BufferProcess = NULL;

	if(StartupMessage)
		ReplyMsg(StartupMessage);
	else
		Signal(ThisProcess,SIG_HANDSHAKE);
}
