/*
**	$Id: termHotkeys.c,v 1.1 92/04/03 20:43:18 olsen Sta Locker: olsen $
**	$Revision: 1.1 $
**	$Date: 92/04/03 20:43:18 $
**
**	Hotkey support routines
**
**	Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

enum	{	CX_TERMSCREENTOFRONT,CX_BUFFERSCREENTOFRONT,CX_SKIPDIALENTRY };

	/* Asynchronous hotkey task. */

STATIC struct Task *CxTask;

	/* Hotkey(STRPTR Code,struct MsgPort *Port,LONG ID):
	 *
	 *	A custom version of the amiga.lib supplied code.
	 */

STATIC CxObj * __regargs
CustomHotKey(STRPTR Code,struct MsgPort *Port,LONG ID)
{
	CxObj *Filter;

	if(Filter = CxFilter(Code))
	{
		CxObj *Sender;

		if(Sender = CxSender(Port,ID))
		{
			CxObj *Translator;

			AttachCxObj(Filter,Sender);

			if(Translator = CxTranslate(NULL))
			{
				AttachCxObj(Filter,Translator);

				if(!CxObjError(Filter))
					return(Filter);
			}
		}

		DeleteCxObjAll(Filter);
	}

	return(NULL);
}

	/* CreateBroker(struct MsgPort *CxPort):
	 *
	 *	Set up a CxObj commodity broker.
	 */

STATIC CxObj *
CreateBroker(struct MsgPort *CxPort)
{
	CxObj *Broker;

		/* Set the commodity priority. */

	NewTermBroker . nb_Pri = Hotkeys . CommodityPriority;

		/* Create the broker. */

	if(Broker = CxBroker(&NewTermBroker,NULL))
	{
			/* Add the hotkeys. */

		AttachCxObj(Broker,CustomHotKey(Hotkeys . termScreenToFront,	CxPort,CX_TERMSCREENTOFRONT));
		AttachCxObj(Broker,CustomHotKey(Hotkeys . BufferScreenToFront,	CxPort,CX_BUFFERSCREENTOFRONT));
		AttachCxObj(Broker,CustomHotKey(Hotkeys . SkipDialEntry,	CxPort,CX_SKIPDIALENTRY));

			/* Did an error show up? */

		if(!CxObjError(Broker))
		{
				/* Broker has been added, now activate it. */

			ActivateCxObj(Broker,Hotkeys . HotkeysEnabled);

			return(Broker);
		}

		DeleteCxObjAll(Broker);
	}

	return(NULL);
}

	/* TermCxServer():
	 *
	 *	Asynchronous hotkey server.
	 */

STATIC VOID __saveds
TermCxServer()
{
	CxObj		*Broker;
	struct MsgPort	*CxPort;
	CxMsg		*Message;

		/* Create a reply port. */

	if(CxPort = CreateMsgPort())
	{
			/* Add the port to the public list. */

		CxPort -> mp_Node . ln_Name = NewTermBroker . nb_Name;

		AddPort(CxPort);

			/* Install the port. */

		NewTermBroker . nb_Port	= CxPort;

			/* Create the broker. */

		if(Broker = CreateBroker(CxPort))
		{
			ULONG	SignalSet;
			BYTE	Terminated = FALSE;

				/* Signal father task that we're done. */

			Signal(ThisProcess,SIGBREAKF_CTRL_C);

				/* Loop and loop... */

			while(!Terminated)
			{
					/* Wait for some signal. */

				SignalSet = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | (1 << CxPort -> mp_SigBit));

					/* ^C aborts. */

				if(SignalSet & SIGBREAKF_CTRL_C)
					Terminated = TRUE;

					/* ^D removes the broker and
					 * creates a new one.
					 */

				if(SignalSet & SIGBREAKF_CTRL_D)
				{
					DeleteCxObjAll(Broker);

					Broker = CreateBroker(CxPort);
				}

					/* A commodity message. */

				if(SignalSet & (1 << CxPort -> mp_SigBit))
				{
					ULONG MessageType,MessageID;

						/* Remove all messages. */

					while(Message = (CxMsg *)GetMsg(CxPort))
					{
							/* Extract type and ID. */

						MessageType	= CxMsgID(Message);
						MessageID	= CxMsgType(Message);

						ReplyMsg((struct Message *)Message);

							/* Take a look at the type... */

						switch(MessageID)
						{
								/* A hotkey was pressed. */

							case CXM_IEVENT:	switch(MessageType)
										{
											case CX_TERMSCREENTOFRONT:	BumpWindow(TopWindow);
															break;

											case CX_BUFFERSCREENTOFRONT:	if(BufferProcess)
																Signal(BufferProcess,SIGBREAKF_CTRL_D);

															break;

											case CX_SKIPDIALENTRY:		Signal(ThisProcess,SIGBREAKF_CTRL_F);
															break;
										}

										break;

								/* An internal commodity command. */

							case CXM_COMMAND:	switch(MessageType)
										{
											case CXCMD_DISABLE:	ActivateCxObj(Broker,Hotkeys . HotkeysEnabled = FALSE);
														break;

											case CXCMD_ENABLE:	ActivateCxObj(Broker,Hotkeys . HotkeysEnabled = TRUE);
														break;

											default:		break;
										}

										break;
						}
					}
				}
			}

				/* Remove the broker. */

			DeleteCxObjAll(Broker);
		}

			/* Remove the port from the public list. */

		RemPort(CxPort);

			/* Remove all pendig messages. */

		while(Message = (CxMsg *)GetMsg(CxPort))
			ReplyMsg((struct Message *)Message);

			/* Delete the reply port. */

		DeleteMsgPort(CxPort);
	}

	Forbid();

		/* Clear the task ID. */

	CxTask = NULL;

		/* Signal father process that we're done. */

	Signal(ThisProcess,SIGBREAKF_CTRL_C);
}

	/* ShutdownCx():
	 *
	 *	Remove the hotkey task.
	 */

VOID
ShutdownCx()
{
	if(CxTask)
	{
		Signal(CxTask,SIGBREAKF_CTRL_C);

		Wait(SIGBREAKF_CTRL_C);
	}
}

	/* SetupCx():
	 *
	 *	Create the hotkey task.
	 */

BYTE
SetupCx()
{
		/* If the task is already running, tell it to
		 * update the hotkey settings.
		 */

	if(CxTask)
		Signal(CxTask,SIGBREAKF_CTRL_D);
	else
	{
		CxTask = CreateTask("term hotkey task",0,TermCxServer,4000);

		Wait(SIGBREAKF_CTRL_C);

		if(!CxTask)
			return(FALSE);
	}

	return(TRUE);
}
