/*
**	termKludge.c
**
**	A particularly nasty kludge
**
**	Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* Local data. */

STATIC struct Interrupt		*InputHandler;
STATIC struct IOStdReq		*InputRequest;
STATIC struct MsgPort		*InputPort;
STATIC struct SignalSemaphore	*InputSemaphore;

STATIC BYTE		 	 MouseMoveAllowed	= TRUE,
				 GoingDown		= FALSE;

	/* EventHandler(register __a0 struct InputEvent *EventChain):
	 *
	 *	This is a kludge. Just in case you haven't seen that
	 *	many in your life, get a close look at this one. There
	 *	is much to be learned!
	 *
	 *	This input event handler actually does nothing but
	 *	check each incoming input event to see whether the
	 *	left mouse button is currently being pressed. At this
	 *	time of writing Workbench 3.0 has the rather unnerving
	 *	habit to release any currently selected icon as soon
	 *	as the status display area of the `term' Workbench
	 *	window is to be redrawn. This kludge prevents the
	 *	status display area from getting redrawn while the
	 *	the `term' Workbench window happens to be inactive
	 *	and the user is currently pressing the left mouse
	 *	button.
	 */

STATIC struct InputEvent * __saveds __asm
EventHandler(register __a0 struct InputEvent *EventChain)
{
	register struct InputEvent	*Event		= EventChain;
	register BYTE			 PermitRefresh	= TRUE;

		/* Process the event chain... */

	do
	{
			/* Is any mouse button currently
			 * being pressed?
			 */

		if(Event -> ie_Qualifier & (IEQUALIFIER_LEFTBUTTON | IEQUALIFIER_RBUTTON))
	 		PermitRefresh = FALSE;
	}
	while(Event = Event -> ie_NextEvent);

	if(!GoingDown)
	{
			/* Update the semaphore data. */

		if(PermitRefresh != MouseMoveAllowed)
		{
			ObtainSemaphore(InputSemaphore);

			MouseMoveAllowed = PermitRefresh;

			ReleaseSemaphore(InputSemaphore);
		}
	}

		/* Return the unchanged event chain. */

	return(EventChain);
}

	/* RefreshAllowed():
	 *
	 *	Check whether the status display area is to be redrawn
	 *	or not.
	 */

BYTE
RefreshAllowed()
{
	BYTE Result = TRUE;

	if(SysBase -> LibNode . lib_Version == 39)
	{
		ObtainSemaphore(InputSemaphore);

		Result = MouseMoveAllowed;

		ReleaseSemaphore(InputSemaphore);
	}

	return(Result);
}

	/* DeleteInputHandler():
	 *
	 *	Remove the input event handler from the chain.
	 */

VOID
DeleteInputHandler()
{
	if(InputHandler)
	{
		GoingDown = TRUE;

		WaitTime(0,MILLION / 5);

		InputRequest -> io_Command	= IND_REMHANDLER;
		InputRequest -> io_Data		= InputHandler;

		DoIO(InputRequest);

		FreeVec(InputHandler);

		InputHandler = NULL;
	}

	if(InputSemaphore)
	{
		FreeVec(InputSemaphore);

		InputSemaphore = NULL;
	}

	if(InputRequest)
	{
		if(InputRequest -> io_Device)
			CloseDevice(InputRequest);

		DeleteIORequest(InputRequest);

		InputRequest = NULL;
	}

	if(InputPort)
	{
		DeleteMsgPort(InputPort);

		InputPort = NULL;
	}
}

	/* CreateInputHandler():
	 *
	 *	Link a custom input event handler into the event
	 *	handler chain. Note: cannot use commodities objects
	 *	here since the raw, unmodified events are required.
	 */

BYTE
CreateInputHandler()
{
	if(SysBase -> LibNode . lib_Version >= 39)
	{
		if(InputPort = CreateMsgPort())
		{
			if(InputRequest = (struct IOStdReq *)CreateIORequest(InputPort,sizeof(struct IOStdReq)))
			{
				if(!OpenDevice("input.device",0,InputRequest,NULL))
				{
					if(InputSemaphore = (struct SignalSemaphore *)AllocVec(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
					{
						InitSemaphore(InputSemaphore);

						if(InputHandler = (struct Interrupt *)AllocVec(sizeof(struct Interrupt),MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
						{
							GoingDown = FALSE;

							InputHandler -> is_Node . ln_Name	= "term input kludge handler";
							InputHandler -> is_Node . ln_Pri	= 51;
							InputHandler -> is_Code			= (VOID (*)())EventHandler;

							InputRequest -> io_Command		= IND_ADDHANDLER;
							InputRequest -> io_Data			= InputHandler;

							DoIO(InputRequest);

							return(TRUE);
						}
					}
				}
			}
		}

		DeleteInputHandler();

		return(FALSE);
	}
	else
		return(TRUE);
}
