/* PatchWindows.c ***********************************************************
*
*	PatchWindows --	Patches the OpenWindow() function to send
*			windows to a custom screen instead to the
*			workbench screen. This works only with
*			windows with one single window title.
*
*			The functions of the routines were
*			transferred from Matt Dillons's "MWB" program.
*			Now here is a very useful application for
*			Matt's routines: any program which
*			requires a CLI window and uses a custom screen,
*			such as ACCESS! or Diga!, can open the CLI
*			window on its own screen. This keeps the user
*			from clicking around on the depth gadgets of
*			the various screens.
*
*	Rewritten by --	Olaf Barthel, ED Electronic Design Hannover
*			Brabeckstrasse 35
*			D-3000 Hannover 71
*
*			Federal Republic of Germany
*
****************************************************************************/

#include <intuition/intuitionbase.h>
#include <exec/memory.h>

	/* Forward declarations. */

extern struct MsgPort	*FindPort(),*CreatePort();
extern struct Message	*GetMsg();
extern struct Library	*OpenLibrary();
extern struct Screen	*OpenScreen();
extern void		*AllocMem();

	/* The "custom" Workbench screen we will open. */

struct NewScreen NewScreen =
{
	0,0,0,0,0,
	-1,-1,
	NULL,
	CUSTOMSCREEN | SCREENBEHIND,
	(struct TextAttr *) NULL,
	(STRPTR) NULL,
	(struct Gadget *) NULL,
	(struct BitMap *) NULL
};

	/* Some more global definitions. */

struct IntuitionBase	*IntuitionBase;
struct Screen		*FakeWB = NULL;

	/* Global definitions for detach function. */

long  _stack		= 8000;
long  _priority		= 0;
long  _BackGroundIO	= 0;
char *_procname		= "PatchWindows";

	/* Replacement for the OpenWindow function. */

extern void NewOpenWindow();
long OldOpenWindow;

#asm

_NewOpenWindow:	MOVEM.L	D2/D3/A4/A6,-(SP)	; Save some registers

		MOVE.L	A0,-(SP)		; Push NewWindow onto stack

		JSR	_geta4#			; Call our routine
		JSR	_ModifiedOpenWindow

		ADD.W	#4,SP			; Corrent the stack
		MOVE.L  D0,A0			; Move return code into argument

		MOVE.L  _OldOpenWindow,A1	; Call old routine

		MOVEM.L	(SP)+,D2/D3/A4/A6	; Restore some registers

		JMP	(A1)			; Jump...
#endasm

	/* ModifiedOpenWindow(NewWindow) :
	 *
	 *	This routine checks the NewWindow structure an application
	 *	passes to OpenWindow(). This can also be AmigaDOS,
	 *	and that's our chance to move the window.
	 */

struct NewWindow *
ModifiedOpenWindow(NewWindow)
struct NewWindow *NewWindow;
{
		/* Move the window to our custom screen, but only if...
		 * the title matches a special title,
		 * our custom screen is already open and
		 * the new window type is WBENCHSCREEN.
		 */

	if(!strcmp(NewWindow -> Title,"MyCLI sample window") && FakeWB && NewWindow -> Type == WBENCHSCREEN)
	{
			/* Move it... */

		NewWindow -> Type	= CUSTOMSCREEN;
		NewWindow -> Screen	= FakeWB;

			/* Bring the screen to the front. */

		ScreenToFront(FakeWB);
	}

	return(NewWindow);
}

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

void
main()
{
	struct MsgPort	*PatchPort,*ReplyPort;	/* Are we already running? */
	struct Message	WakeUp,*Terminate;
	struct Screen	RealWB;			/* The real Workbench screen. */

		/* If we are still running, send the other task
		 * a message to close down.
		 */

	if(PatchPort = (struct MsgPort *)FindPort("PatchPort"))
	{
		if(!(ReplyPort = (struct MsgPort *)CreatePort(NULL,0)))
			exit(20);

		WakeUp . mn_Node . ln_Type	= NT_MESSAGE;
		WakeUp . mn_Length		= sizeof(struct Message);
		WakeUp . mn_ReplyPort		= ReplyPort;

		PutMsg(PatchPort,&WakeUp);
		Wait(1 << ReplyPort -> mp_SigBit);

		DeletePort(ReplyPort);

		exit(0);
	}
	else
	{
		if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",LIBRARY_VERSION)))
			exit(20);

			/* Try to get some information on the Workbench screen. */

		GetScreenData(&RealWB,sizeof(struct Screen),WBENCHSCREEN,NULL);

			/* Adjust the data in the NewScreen structure. */

		NewScreen . LeftEdge	= RealWB . LeftEdge;
		NewScreen . TopEdge	= RealWB . TopEdge;
		NewScreen . Height	= RealWB . Height;
		NewScreen . Width	= RealWB . Width;
		NewScreen . Depth	= RealWB . BitMap . Depth;
		NewScreen . DetailPen	= RealWB . DetailPen;
		NewScreen . BlockPen	= RealWB . BlockPen;
		NewScreen . ViewModes	= RealWB . ViewPort . Modes;
		NewScreen . DefaultTitle= RealWB . Title;

			/* Open a fake Workbench screen. */

		if(!(FakeWB = (struct Screen *)OpenScreen(&NewScreen)))
		{
			CloseLibrary(IntuitionBase);

			exit(20);
		}

			/* Open our "Mailbox". */

		if(!(PatchPort = (struct MsgPort *)CreatePort("PatchPort",0)))
		{
			CloseScreen(FakeWB);
			CloseLibrary(IntuitionBase);

			exit(20);
		}

			/* Patch the OpenWindow() function. */

		Forbid();
		OldOpenWindow = SetFunction(IntuitionBase,-0x00CC,NewOpenWindow);
		Permit();

			/* Wait for a message to wake us up. */

		Wait(1 << PatchPort -> mp_SigBit);
		Terminate = GetMsg(PatchPort);
		ReplyMsg(Terminate);

			/* Reset the function vector. */

		Forbid();
		SetFunction(IntuitionBase,-0x00CC,OldOpenWindow);
		Permit();

			/* Remove the "Mailbox". */

		DeletePort(PatchPort);

			/* And close the rest. */

		CloseScreen(FakeWB);
		CloseLibrary(IntuitionBase);

		exit(0);
	}
}
