///////////////////////////////////////////////////////////////////////////
//                                                                       //
//                     DragIt 1.01 by Steve Lemieux                       //
//  © Copyright 1992, SilverBox Software, All rights reserved, Freeware  //
//                                                                       //
///////////////////////////////////////////////////////////////////////////


#include <exec/memory.h>
#include <exec/interrupts.h>
#include <graphics/layers.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <graphics/gfxbase.h>
#include <workbench/workbench.h>
#include <libraries/commodities.h>

#include <pragmas/input_lib.h>
#include <pragmas/intuition_lib.h>
#include <pragmas/icon_lib.h>
#include <pragmas/graphics_lib.h>
#include <pragmas/layers_lib.h>
#include <pragmas/commodities_lib.h>
#include <pragmas/dos_lib.h>
#include <pragmas/exec_lib.h>

#define LIBVERSION 36

struct LayersBase *LayersBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct MsgPort *InputMP;
struct MsgPort *Port;
struct IOStdReq *InputIO;
struct Library *InputBase;
struct Interrupt Handler;
struct Window *Window;
struct Screen *scr;
struct DOSBase *DOSBase;
struct Library *IconBase;
struct RastPort *rp;
struct RDArgs *RDArgs;
struct MsgPort *CxPort;
struct Library *CxBase;

CxObj *Broker;
ULONG *ArgsArray[7];
WORD PosX,PosY,OldPosX,OldPosY,WinPosX,WinPosY;
WORD SizeX,SizeY,dx,dy,ScrX,ScrY,Enable = TRUE;

LONG Device = -1;
ULONG peek;

struct InputEvent *handler();
struct NewBroker NewBroker =
	{
	NB_VERSION, "DragIt",
	"DragIt 1.01, © 1992 by Steve Lemieux",
	"Drag a window from anywhere!",
	NBU_UNIQUE,0,0,0,0
	};


void Quitter(UWORD code)
	{
	if (Broker) DeleteCxObj(Broker);
	if (CxPort) DeleteMsgPort(CxPort);
	if (RDArgs) FreeArgs(RDArgs);
	if (!Device) CloseDevice(InputIO);
	if (InputIO) DeleteExtIO(InputIO);
	if (InputMP) DeleteMsgPort(InputMP);
	if (Port) DeleteMsgPort(Port);
	if (IconBase) CloseLibrary(IconBase);
	if (CxBase) CloseLibrary(CxBase);
	if (GfxBase) CloseLibrary(GfxBase);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
	if (LayersBase) CloseLibrary(LayersBase);
	exit(code);
	}

void Ouvrir(void)
	{
	if (!(IconBase = (struct IconBase *)OpenLibrary("icon.library",LIBVERSION)))
		Quitter(10);
	if (!(LayersBase = (struct LayersBase *)OpenLibrary("layers.library",LIBVERSION)))
		Quitter(10);
	if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",LIBVERSION)))
		Quitter(10);
	if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",LIBVERSION)))
		Quitter(10);
	if (!(CxBase = (struct CxBase *)OpenLibrary("commodities.library",LIBVERSION)))
		Quitter(10);
	if (!(InputMP = (struct MsgPort *)CreateMsgPort()))
		Quitter(10);
	if (!(Port = (struct MsgPort *)CreateMsgPort()))
		Quitter(10);
	if (!(InputIO = (struct StdIOReq *)CreateExtIO(InputMP,sizeof(struct IOStdReq))))
		Quitter(10);
	if (Device = OpenDevice("input.device",NULL,InputIO,NULL))
		Quitter(10);
	InputBase = (struct Library *)InputIO->io_Device;
	if (!(CxPort = (struct MsgPort *)CreateMsgPort()))
		Quitter(10);
	NewBroker.nb_Port = CxPort;
	if (!(Broker = (CxObj *)CxBroker(&NewBroker, NULL)))
		Quitter(10);
	ActivateCxObj(Broker, TRUE);
	}

void Send(void)
	{
    struct Message *Msg;

	if (Msg = (struct Message *)AllocMem(sizeof(struct Message), MEMF_PUBLIC))
		{
		Msg->mn_ReplyPort = NULL;
		Msg->mn_Length = sizeof(struct Message);
		PutMsg(Port, Msg);
	    }
	}

void __asm HandlerCode(register __a0 struct InputEvent *Ev)
	{
	struct InputEvent *ev;
	UWORD Qual;

    for (ev = Ev; ev; ev = ev->ie_NextEvent)
		if (ev->ie_Class == IECLASS_RAWMOUSE)
			if (ev->ie_Code == IECODE_LBUTTON)
				if (Enable)
					{
					Qual = PeekQualifier();
					if ((Qual & peek) == peek)
						{
						ev->ie_Class = IECLASS_NULL;
						Send();
						}
					}
	}

void TestPos(WORD X,WORD Y)
	{
	dx = X - WinPosX;
	dy = Y - WinPosY;

	if (dx < 0) dx = 0;
	if (dy < 0) dy = 0;
	if (dx > ScrX) dx = ScrX;
	if (dy > ScrY) dy = ScrY;
	}

void DrawRectangle(WORD X,WORD Y)
	{
	TestPos(X,Y);
	SetDrMd(rp,COMPLEMENT);
	Move(rp,dx,dy);
	Draw(rp,dx+SizeX,dy);
	Draw(rp,dx+SizeX,dy+SizeY);
	Draw(rp,dx,dy+SizeY);
	Draw(rp,dx,dy+1);
	Move(rp,dx+1,dy+1);
	Draw(rp,dx+1,dy+SizeY-1);
	Move(rp,dx+SizeX-1,dy+1);
	Draw(rp,dx+SizeX-1,dy+SizeY-1);
	}

void GetPos(void)
	{
	PosX = IntuitionBase->MouseX;
	PosY = IntuitionBase->MouseY;
	if (!(scr->ViewPort.Modes & LACE))
	    PosY >>= 1;
	if (!(scr->ViewPort.Modes & HIRES))
	    PosX >>= 1;
	}

void Scroll(void)
	{
	UBYTE *Button;
	WORD PosX2,PosY2;

	SizeX = Window->Width - 1;
	SizeY = Window->Height - 1;
	ScrX = scr->Width - SizeX - 1;
	ScrY = scr->Height - SizeY - 1;

	GetPos();

	PosX2 = OldPosX = PosX;
	PosY2 = OldPosY = PosY;
	WinPosX = PosX - Window->LeftEdge;
	WinPosY = PosY - Window->TopEdge;

	Button = (UBYTE *)0xbfe001;
	rp = &(scr->RastPort);

	LockLayerInfo(&(scr->LayerInfo));
	LockLayers(&(scr->LayerInfo));
	DrawRectangle(PosX,PosY);
	do
		{
		GetPos();
		if (PosX != OldPosX || PosY != OldPosY)
			{
			DrawRectangle(OldPosX,OldPosY);
			OldPosX = PosX;
			OldPosY = PosY;
			DrawRectangle(PosX,PosY);
			WaitTOF();
			}
		}
	while(!((*Button) & 64));
	DrawRectangle(OldPosX,OldPosY);
	TestPos(PosX,PosY);
	UnlockLayers(&(scr->LayerInfo));
	UnlockLayerInfo(&(scr->LayerInfo));
	if (PosX != PosX2 || PosY != PosY2)
		ChangeWindowBox(Window,dx,dy,Window->Width,Window->Height);
	}

UWORD TraiterCx(void)
	{
	CxMsg *CxMsg;
	UWORD Quit = FALSE;
	ULONG msgid, msgtype;

	while(CxMsg = (LONG *)GetMsg(CxPort))
		{
		msgid = CxMsgID(CxMsg);
		msgtype = CxMsgType(CxMsg);
		ReplyMsg((struct Message *)CxMsg);

		if (msgtype == CXM_COMMAND)
			switch(msgid)
				{
				case CXCMD_DISABLE:
					Enable = FALSE;
					ActivateCxObj(Broker, FALSE);
					break;
				case CXCMD_ENABLE:
					Enable = TRUE;
					ActivateCxObj(Broker, TRUE);
					break;
				case CXCMD_KILL:
					Quit = TRUE;
					break;
				}
		}
	return(Quit);
	}

void _main(void)
	{
	long sig,sigport,sigcx;
	struct Message *msg;
	struct Layer *layer = NULL;
	struct Task *Task;
	struct DiskObject *diskobj;

	Ouvrir();

	if (Cli())
		{
		PutStr("\33[33mDragIt 1.01 by Steve Lemieux\33[31m\n© Copyright 1992, SilverBox Software, All rights reserved, Freeware\33[31m\n");
		if (RDArgs = (struct RDArgs *)ReadArgs("LSHIFT/S,RSHIFT/S,CONTROL/S,LALT/S,RALT/S,LCOMMAND/S,RCOMMAND/S",ArgsArray,NULL))
			{
			if (ArgsArray[0])
				peek |= IEQUALIFIER_LSHIFT;
			if (ArgsArray[1])
				peek |= IEQUALIFIER_RSHIFT;
			if (ArgsArray[2])
				peek |= IEQUALIFIER_CONTROL;
			if (ArgsArray[3])
				peek |= IEQUALIFIER_LALT;
			if (ArgsArray[4])
				peek |= IEQUALIFIER_RALT;
			if (ArgsArray[5])
				peek |= IEQUALIFIER_LCOMMAND;
			if (ArgsArray[6])
				peek |= IEQUALIFIER_RCOMMAND;
			}
		else
			{
			PutStr("Invalid parameters!\n");
			Quitter(10);
			}
		}
	else
		{
		Task = (struct Task *)FindTask(NULL);
		if (diskobj = (struct DiskObject *)GetDiskObjectNew(Task -> tc_Node.ln_Name))
			{
			if (FindToolType(diskobj->do_ToolTypes,"LSHIFT"))
				peek |= IEQUALIFIER_LSHIFT;
			if (FindToolType(diskobj->do_ToolTypes,"RSHIFT"))
				peek |= IEQUALIFIER_RSHIFT;
			if (FindToolType(diskobj->do_ToolTypes,"CONTROL"))
				peek |= IEQUALIFIER_CONTROL;
			if (FindToolType(diskobj->do_ToolTypes,"LALT"))
				peek |= IEQUALIFIER_LALT;
			if (FindToolType(diskobj->do_ToolTypes,"RALT"))
				peek |= IEQUALIFIER_RALT;
			if (FindToolType(diskobj->do_ToolTypes,"LCOMMAND"))
				peek |= IEQUALIFIER_LCOMMAND;
			if (FindToolType(diskobj->do_ToolTypes,"RCOMMAND"))
				peek |= IEQUALIFIER_RCOMMAND;
			FreeDiskObject(diskobj);
			}
		}

	if (!peek) peek |= IEQUALIFIER_LSHIFT;

	Handler.is_Code = (APTR)handler;
	Handler.is_Data = NULL;
	Handler.is_Node.ln_Pri = 100;
	Handler.is_Node.ln_Name = "DragIt Handler";
	InputIO->io_Data = &Handler;
	InputIO->io_Command = IND_ADDHANDLER;
	DoIO(InputIO);

	sigport = 1<<Port->mp_SigBit;
	sigcx = 1<<CxPort->mp_SigBit;
	while(TRUE)
		{
		sig = Wait(sigcx|sigport|SIGBREAKF_CTRL_C);
		if (sig & sigport)
			while (msg = (struct Message *)GetMsg(Port))
				{
				FreeMem(msg, msg->mn_Length);

				for (scr = IntuitionBase->FirstScreen; scr; scr = scr->NextScreen)
					{
					GetPos();
					if (layer = (struct Layer *)WhichLayer(&(scr->LayerInfo), PosX - scr->ViewPort.DxOffset, PosY - scr->ViewPort.DyOffset))
					    break;
					if (PosY >= scr->ViewPort.DyOffset)
					    break;
				    }
				if (layer)
					if (Window = layer->Window)
						if (!(Window->Flags & BACKDROP))
							Scroll();
				}
		if (sig & sigcx)
			if (TraiterCx()) break;
		if (sig & SIGBREAKF_CTRL_C)
			break;
		}

	InputIO->io_Data = &Handler;
	InputIO->io_Command = IND_REMHANDLER;
	DoIO(InputIO);

	Quitter(0);
	}
