/***************************************************************************
 *
 *	MacWin.c    - routines for making OpenWindow & CloseWindow
 *		      behave like a Macintosh	    10-Jan-88
 *
 *	Version 1.3 18-Jun-88 Copyright (c) 1988 - Steven Sweeting
 *
 *	Note: if the OpenWindow vector gets in before mwb
 *	      (ie run mwb first) then the opening of the window
 *	      is done on the real WBENCH screen.
 *
 ***************************************************************************/

#include <intuition/intuitionbase.h>
#include "wicon.h"

extern	struct IntuitionBase   *IntuitionBase;

struct	Box
{
	LONG   Left, Right;
	LONG   Top, Bottom;
};

#define REC_FIRST	1
#define REC_LAST	2
#define REC_HIRES	4

#define MIN(a,b)        ((a)<(b) ? (a):(b))
#define MAX(a,b)        ((a)>(b) ? (a):(b))


/*************************************************************************
 *  SizeRec - resizes a rectangle on the given Screen
 *
 * 03-Jan-88
 */
void
SizeRec(Screen, From, To)
struct	Screen	*Screen;
struct	BoxInfo *From, *To;
{
	struct	Box	Box1, Box2, Box3;
	short		inc;
	long		Left, Right, Top, Bottom;
	int		Flags;
	long		factor, curr = 0, i;
	struct RastPort *RastPort = &(Screen->RastPort);
	static	WORD	ox1, oy1, ox2, oy2; /* Save them for redraw */

	Box1.Left   = MAX( From->LeftEdge,          0              );
	Box1.Right  = MIN( Box1.Left + From->Width, Screen->Width  );
	Box1.Top    = MAX( From->TopEdge,           0              );
	Box1.Bottom = MIN( Box1.Top + From->Height, Screen->Height );

	Box2.Left   = MAX( To->LeftEdge,            0              );
	Box2.Right  = MIN( Box2.Left + To->Width,   Screen->Width  );
	Box2.Top    = MAX( To->TopEdge,             0              );
	Box2.Bottom = MIN( Box2.Top + To->Height,   Screen->Height );

	if (Screen->Flags | HIRES)
		Flags = REC_HIRES;
	else
		Flags = 0;

	SetDrMd(RastPort, (LONG)COMPLEMENT);

	if (Arg_Boxes)
	{
	    SetDrMd(RastPort, (LONG)COMPLEMENT);

	    LockLayers(&(Screen->LayerInfo));

	    inc = 256/Arg_Boxes;

	    DrawRec(RastPort, ox1 = Box1.Left, oy1 = Box1.Top,
			      ox2 = Box1.Right, oy2 = Box1.Bottom );
	    inc = 256/Arg_Boxes;

	    for (i=0; i<256; i += inc )
	    {
		WaitTOF();

		DrawRec(RastPort, ox1, oy1, ox2, oy2 );

		DrawRec(
			RastPort,
			ox1 = (WORD)((Box1.Left   *(255-i) + Box2.Left   *i) >>8),
			oy1 = (WORD)((Box1.Top    *(255-i) + Box2.Top    *i) >>8),
			ox2 = (WORD)((Box1.Right  *(255-i) + Box2.Right  *i) >>8),
			oy2 = (WORD)((Box1.Bottom *(255-i) + Box2.Bottom *i) >>8)
		       );
	    }

	    DrawRec(RastPort, ox1, oy1, ox2, oy2);


	    UnlockLayers(&(Screen->LayerInfo));
	}

}

/*************************************************************************
 * DrawRec - draws an XOR rectangle on a given RastPort
 *
 * 03-Jan-88
 */
int
DrawRec(RastPort, x1, y1, x2, y2, status)
struct	RastPort	*RastPort;
WORD	x1, y1, x2, y2;
WORD	status;
{
	Move(RastPort, (LONG)x1, (LONG)y1);
	Draw(RastPort, (LONG)x2, (LONG)y1);
	Draw(RastPort, (LONG)x2, (LONG)y2);
	Draw(RastPort, (LONG)x1, (LONG)y2);
	Draw(RastPort, (LONG)x1, (LONG)y1);

	if (status & REC_HIRES)
	{
		Move(RastPort, (LONG)x1+1, (LONG)y1);
		Draw(RastPort, (LONG)x1+1, (LONG)y2);
		Move(RastPort, (LONG)x2-1, (LONG)y1);
		Draw(RastPort, (LONG)x2-1, (LONG)y2);
	}
}

/*************************************************************************
 * M_Open - opens a window - called from the OpenWindow vector
 *	    hence it is always run by the task that called it
 *
 */
struct	BoxInfo SmallBox =   { 0, 0, 0, 0 };

struct Window *
M_Open( NewWindow )
struct NewWindow *NewWindow;
{
	extern	struct	Window *OldOpenWindow();

	struct Screen	*Screen;

	if ((NewWindow->Type & SCREENTYPE) == WBENCHSCREEN)
	    Screen = WorkBenchScreen;
	else
	    Screen = NewWindow->Screen;

	SmallBox.LeftEdge = Screen->MouseX;
	SmallBox.TopEdge  = Screen->MouseY;

	if (Arg_AllScreens || (Screen == WiconScreen))
	    SizeRec(Screen, &SmallBox, &(NewWindow->LeftEdge));

	return (OldOpenWindow(NewWindow));
}

/*************************************************************************
 * UnSetFunction - this routine handles properly
 *		   the opposite to SetFunction() which
 *		   replaces an AmigaDOS `OldVector'
 *		   with its own `NewVector'. This function
 *		   may never exit because the `NewVector'
 *		   may be lost by a newer function which
 *		   also does a SetFunction()
 *  10-Jan-87
 */

void UnSetFunction(LibraryBase, FunctionOffset, LibVector, PresentVector)
struct	Library *LibraryBase;
LONG		FunctionOffset;
VOID		(*PresentVector)(),(*LibVector)();
{
	extern	void	(*SetFunction())();     /* AmigaDOS routine */
	extern	void	(*GetFunction())();     /* Sweeting routine */

	Forbid();

	while (GetFunction( LibraryBase, FunctionOffset ) != PresentVector)
	{
		Permit();

		Delay(50L);     /* a second */

		Forbid();
	}

	    /* It may be illegal to do this within a Forbid()/Permit() */
	    /* But it seems to work OK	*/

	SetFunction( LibraryBase, FunctionOffset, LibVector );

	Permit();

}

