;/*

;CatComp CloseWB.cd CTFILE CloseWB_xxx.ct
;CatComp CloseWB.cd CloseWB_xxx.ct CATALOG //Catalogs/xxx/CloseWB.catalog

CatComp Catalogs/CloseWB.cd CFILE CloseWB_strings.h
sc PARM=REGISTERS STRMERGE RESOPT DATA=NEAR NMINC UCHAR CONSTLIB STREQ ANSI NOSTKCHK OPTIMIZE OPTSIZE OPTPEEP IGNORE=73+84 NOSTDIO CloseWB.c
slink FROM LIB:c.o,CloseWB.o TO /CloseWB LIBRARY LIB:sc.lib,LIB:Amiga.lib SC SD NOICONS STRIPDEBUG
delete >NIL: CloseWB.o CloseWB_strings.h
quit

 CloseWB.c - Simple hot key commodity compiled with SASC 6.55

 This piece of code is Copyright © 1995 by Stefano Reksten of 3AM
 - The Three Amigos!!!

*/

#include <dos/dos.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <exec/execbase.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <libraries/commodities.h>
#include <libraries/gadtools.h>
#include <libraries/locale.h>
#include <workbench/startup.h>
#include <string.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/commodities.h>
#include <proto/dos.h>
#include <proto/icon.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/locale.h>
#include <clib/alib_protos.h>
#include <clib/alib_stdio_protos.h>

#define EVT_HOTKEY 1L
#define EVT_POPKEY 2L

#define CATCOMP_NUMBERS
#define CATCOMP_BLOCK
#define CATCOMP_CODE
#include "CloseWB_strings.h"

char *ver = "$VER: CloseWB 1.8 "__AMIGADATE__;

extern STRPTR __asm GetString(register __a0 struct LocaleInfo *li,
					register __d0 LONG stringNum);
struct LocaleInfo li;
char *str_windows, *str_shells, *str_flush, *str_hide, *str_quit, *str_wbench,
	 *key_windows, *key_shells, *key_flush, *key_hide, *key_quit;

void ProcessMsg(void);
struct Screen *FindWB(void);
void CloseWindowsOrShells(void);
void SendWindowcloseTo(struct Window *);
void SendCtrlBackslashTo(struct Window *);
BOOL ProcessCommodityMsg(void);
BOOL ProcessWindowMsg(void);
BOOL OpenWBWindow(void);
void CloseWBWindow(void);
void FlushAll(void);

struct EasyStruct warn_rq = { sizeof(struct EasyStruct),
	NULL,
	"CloseWB Request",
	"Please close all windows\nor shells before.",
	"OK|CANCEL" };

extern struct ExecBase *SysBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *CxBase, *GadToolsBase, *IconBase, *LocaleBase;
struct Window *wbwindow;
struct MsgPort *broker_mp;
CxObj *broker;

struct NewBroker newbroker = {
	NB_VERSION,
	"CloseWB",
	"CloseWB 1.8 © 1995 by Stefano Reksten of 3AM",
	NULL,
	NBU_UNIQUE | NBU_NOTIFY,
	COF_SHOW_HIDE, 0, 0, 0 };

ULONG cxsigflag;
ULONG close_windows = TRUE, close_shells = TRUE, close_wb = TRUE, flush_all = TRUE;

#define CWND_ID 1
#define CSHL_ID 2
#define CWBS_ID 3
#define FLSH_ID 4
#define HIDE_ID 5
#define QUIT_ID 6


struct Gadget *glist = NULL;


BOOL AttachFilter( STRPTR onkey, ULONG user_event )
{
register CxObj *filter, *sender, *translator;

if ( filter = CxFilter( onkey ) )
	{
	AttachCxObj( broker, filter );

	if ( sender = CxSender( broker_mp, user_event ) )
		{
		AttachCxObj( filter, sender );

		if ( translator = CxTranslate( NULL ) )
			{
			AttachCxObj( filter, translator );

			if ( !CxObjError( filter ) )
				return TRUE;
			}
		}
	}
return FALSE;
}


void EmptyMsgPort( struct MsgPort *mp )
{
struct Message *msg;

while( msg = GetMsg( mp ) )
	ReplyMsg( msg );
}


void __main( void )
{
UBYTE hotkey[30], popkey[30];
BOOL popup;

li.li_Catalog = NULL;
if ( LocaleBase = OpenLibrary( "locale.library", 38L ) )
	{
	li.li_LocaleBase = LocaleBase;
	li.li_Catalog = OpenCatalogA( NULL, "CloseWB.catalog", NULL );

	warn_rq.es_Title = GetString( &li, MSG_CLOSEWBREQUESTTITLE );
	warn_rq.es_TextFormat = GetString( &li, MSG_PLEASECLOSEALL );
	warn_rq.es_GadgetFormat = GetString( &li, MSG_REQUESTGADGETS );

	newbroker.nb_Descr = GetString( &li, MSG_NEWBROKER );

	str_windows = GetString( &li, MSG_WINDOWS );
	key_windows = GetString( &li, MSG_WINDOWS_KEY );
	str_shells = GetString( &li, MSG_SHELLS );
	key_shells = GetString( &li, MSG_SHELLS_KEY );
	str_flush = GetString( &li, MSG_FLUSH );
	key_flush = GetString( &li, MSG_FLUSH_KEY );
	str_hide = GetString( &li, MSG_HIDE );
	key_hide = GetString( &li, MSG_HIDE_KEY );
	str_quit = GetString( &li, MSG_QUIT );
	key_quit = GetString( &li, MSG_QUIT_KEY );
	str_wbench = "_Workbench";
	}
else
	{
	str_windows = "Windows";
	key_windows = "I";
	str_shells = "Shells";
	key_shells = "S";
	str_flush = "Flush";
	key_flush = "F";
	str_hide = "Hide";
	key_hide = "H";
	str_quit = "Quit";
	key_quit = "Q";
	str_wbench = "Workbench";
	}

if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 37L))
	{
	if (CxBase = OpenLibrary("commodities.library", 37L))
		{
		if (broker_mp = CreateMsgPort())
			{
			newbroker.nb_Port = broker_mp;
			cxsigflag = 1L << broker_mp->mp_SigBit;

			hotkey[0] = popkey[0] = NULL;

			if (IconBase = OpenLibrary("icon.library",37))
				{
				char **ttypes;
				struct DiskObject *ob;

				if ( ob = GetDiskObject( "CloseWB" ) )
					{
					ttypes = ob->do_ToolTypes;

					newbroker.nb_Pri = (BYTE)ArgInt(ttypes, "CX_PRIORITY", 0);

					close_windows = MatchToolValue( FindToolType(ttypes, "CLOSEWINDOWS"), "TRUE" );
					close_shells = MatchToolValue( FindToolType(ttypes, "CLOSESHELLS"), "TRUE");
					close_wb = MatchToolValue( FindToolType(ttypes, "CLOSEWORKBENCH"), "TRUE");
					flush_all = MatchToolValue( FindToolType(ttypes, "FLUSH"), "TRUE");

					popup = MatchToolValue(FindToolType(ttypes, "CX_POPUP"), "YES");

					strcpy( hotkey, FindToolType(ttypes, "CX_HOTKEY") );
					strcpy( popkey, FindToolType(ttypes, "CX_POPKEY") );

					FreeDiskObject( ob );
					}
				CloseLibrary(IconBase);
				}

			if (!(hotkey[0]))
				strcpy( hotkey, "lalt w" );
			if (!(popkey[0]))
				strcpy( popkey, "ctrl lalt w" );

			if (broker = CxBroker(&newbroker, NULL))
				{
				if ( AttachFilter( hotkey, EVT_HOTKEY ) &&
					 AttachFilter( popkey, EVT_POPKEY ) )
					{
					ActivateCxObj(broker, 1L);
					if (popup)
						OpenWBWindow();
					ProcessMsg();
					}
				DeleteCxObjAll(broker);
				}
			EmptyMsgPort( broker_mp );
			DeletePort( broker_mp );
			}
		CloseLibrary( CxBase );
		}
	CloseWBWindow();
	CloseLibrary( (struct Library *)IntuitionBase );
	}

if ( LocaleBase )
	{
	if ( li.li_Catalog )
		 CloseCatalog( li.li_Catalog );
	CloseLibrary( LocaleBase );
	}
}


void ProcessMsg(void)
{
BOOL stay = TRUE;
ULONG sigrcvd, waitmask;

while(stay)
	{
	waitmask = cxsigflag | SIGBREAKF_CTRL_C;
	if (wbwindow) waitmask |= 1L<<wbwindow->UserPort->mp_SigBit;
	sigrcvd = Wait(waitmask);

	if (sigrcvd & SIGBREAKF_CTRL_C)
		stay = FALSE;
	else
	if (sigrcvd & cxsigflag)
		stay = ProcessCommodityMsg();
	else
		stay = ProcessWindowMsg();
	}
}


struct Screen *FindWB(void)
{
register struct Screen *scr = IntuitionBase->FirstScreen;

while(scr && (!(scr->DefaultTitle) || strcmp(scr->DefaultTitle, "Workbench Screen")))
	scr = scr->NextScreen;
return(scr);
}


void CloseWindowsOrShells()
{
register struct Window *window, *next;
register struct Screen *wbs = FindWB();

if (close_windows && wbwindow && wbwindow->WScreen == wbs)
	CloseWBWindow();

if (close_windows)
	{
	window = wbs->FirstWindow;
	while(window)
		{
		next = window->NextWindow;
		if (window->UserPort)
			{
			if (window->Title && strcmp(window->Title, "Workbench"))
				SendWindowcloseTo(window);
			}
		window = next;
		}
	}

if (close_shells)
	{
	window = wbs->FirstWindow;
	while(window)
		{
		next = window->NextWindow;

		ActivateWindow(window);
		SendCtrlBackslashTo(window);
		Delay( 5 );

		window = next;
		}
	}
}


void SendWindowcloseTo(struct Window *window)
{
register struct IntuiMessage *imsg;

if (imsg = (struct IntuiMessage *)AllocVec(sizeof(struct IntuiMessage), MEMF_ANY|MEMF_CLEAR))
	{
	imsg->ExecMessage.mn_ReplyPort = broker_mp;
	imsg->ExecMessage.mn_Length = sizeof(struct IntuiMessage);
	imsg->Class = IDCMP_CLOSEWINDOW;
	imsg->ExecMessage.mn_Node.ln_Type = NT_MESSAGE;
	imsg->IDCMPWindow = window;
	PutMsg(window->UserPort, (struct Message *)imsg);
	WaitPort(broker_mp);
	GetMsg(broker_mp);
	FreeVec(imsg);
	}
}


void SendCtrlBackslashTo(struct Window *window)
{
register struct InputEvent *fakeev;
register struct IOStdReq *ioreq;

if (fakeev = AllocVec(sizeof(struct InputEvent),MEMF_PUBLIC|MEMF_CLEAR))
	{
	if (ioreq = CreateIORequest(broker_mp,sizeof(struct IOStdReq)))
		{
		if ( !OpenDevice("input.device",NULL,(struct IORequest *)ioreq,NULL))
			{
			fakeev->ie_Class = IECLASS_RAWKEY;
			fakeev->ie_Code = 0x0D;
			fakeev->ie_Qualifier = IEQUALIFIER_CONTROL;

			ioreq->io_Data = (APTR)fakeev;
			ioreq->io_Length = sizeof(struct InputEvent);
			ioreq->io_Command = IND_WRITEEVENT;

			DoIO((struct IORequest *)ioreq);
			CloseDevice((struct IORequest *)ioreq);
			}
		DeleteIORequest(ioreq);
		}
	FreeVec(fakeev);
	}
}

struct IntuiText it = { 0, 0, 0, 0, 0, NULL, NULL, NULL };
struct NewGadget ng = { 0, 0, 50, 0, NULL, NULL, 0, 0, NULL, NULL };
struct VisualInfo *vi;
struct Gadget *gad;
UWORD textw, wleft = (UWORD)~0, wtop = (UWORD)~0;
struct Gadget *windows_gad, *shells_gad, *workbench_gad, *flush_gad;

/* Some other routines to make it shorter */

UWORD MaxBetween( STRPTR text, UWORD prev )
{
register UWORD ilength, max;

it.IText = text;
ilength = IntuiTextLength( &it );
max = ( ilength > prev ? ilength : prev );
return max;
}

struct Gadget *AddCheckboxGadget( STRPTR name, ULONG ID, BOOL selected )
{
ng.ng_TopEdge += ng.ng_Height + 1;
ng.ng_GadgetText = name;
ng.ng_GadgetID = ID;
gad = CreateGadget(CHECKBOX_KIND,gad,&ng,GTCB_Checked,selected,GTCB_Scaled,TRUE,GT_Underscore,'_',TAG_END);
textw = MaxBetween( name, textw );
return gad;
}


BOOL OpenWBWindow(void)
{
struct Screen *wbs = LockPubScreen(NULL);
register UWORD fonth, wheight, wwidth;

if (!wbwindow)
	{
	fonth = wbs->Font->ta_YSize;
	if ( fonth < 12 )
		fonth = 12;
	it.ITextFont = wbs->Font;
	textw = 0;
	wheight = wbs->BarHeight + fonth * 5 + 5 + wbs->WBorBottom;
	if (GadToolsBase = OpenLibrary("gadtools.library",37L))
		{
		if (vi = GetVisualInfo(wbs,NULL))
			{
			ng.ng_VisualInfo = vi;
			ng.ng_LeftEdge = wbs->WBorLeft + 4;
			ng.ng_TopEdge = wbs->BarHeight;
			ng.ng_TextAttr = wbs->Font;

			gad = CreateContext(&glist);
			if (gad)
				{
				ng.ng_TopEdge -= fonth - 2;
				ng.ng_Flags = PLACETEXT_RIGHT;
				ng.ng_Height = fonth - 1;
				ng.ng_Width = 26;

				windows_gad = AddCheckboxGadget( str_windows, CWND_ID, close_windows );
				shells_gad = AddCheckboxGadget( str_shells, CSHL_ID, close_shells );
				workbench_gad = AddCheckboxGadget( str_wbench, CWBS_ID, close_wb );
				flush_gad = AddCheckboxGadget( str_flush, FLSH_ID, flush_all );

				wwidth = textw + wbs->WBorLeft + wbs->WBorRight + 48;

				textw = MaxBetween( str_hide, MaxBetween( str_quit, 0 ) );
				if ( ( textw * 2 + wbs->WBorLeft + wbs->WBorRight + 48 ) > wwidth )
				wwidth = ( textw * 2 + wbs->WBorLeft + wbs->WBorRight + 48 );
				textw = ( wwidth - wbs->WBorLeft - wbs->WBorRight - 10) >> 1;

				ng.ng_Height = fonth + 2;
				ng.ng_TopEdge += fonth;
				ng.ng_Width = textw;
				ng.ng_Flags = PLACETEXT_IN;
				ng.ng_GadgetText = str_hide;
				ng.ng_GadgetID = HIDE_ID;
				gad = CreateGadget(BUTTON_KIND,gad,&ng,GT_Underscore,'_',TAG_END);

				ng.ng_LeftEdge += ng.ng_Width + 2;
				ng.ng_GadgetText = str_quit;
				ng.ng_GadgetID = QUIT_ID;
				gad = CreateGadget(BUTTON_KIND,gad,&ng,GT_Underscore,'_',TAG_END);

				if ( wtop == ~0 )
					wtop = (wbs->Height - wheight)>>1;
				if ( wleft == ~0 )
					wleft = (wbs->Width - wwidth)>>1;

				if (gad && (wbwindow = OpenWindowTags( NULL,
					WA_Left, wleft,
					WA_Top, wtop,
					WA_Width, wwidth,
					WA_Height, wheight,
					WA_Title, "CloseWB",
					WA_ScreenTitle, "CloseWB 1.8 © 1995 by Stefano Reksten of 3AM",
					WA_Flags, WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|WFLG_DRAGBAR|WFLG_ACTIVATE|WFLG_RMBTRAP,
					WA_Gadgets, glist,
					WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_GADGETDOWN|IDCMP_VANILLAKEY|IDCMP_REFRESHWINDOW|BUTTONIDCMP,
					TAG_END )))
					{
					ScreenToFront(wbs);
					UnlockPubScreen(NULL,wbs);
					return TRUE;
					}
				}
			FreeVisualInfo(vi);
			}
		CloseLibrary(GadToolsBase);
		}
	}

UnlockPubScreen(NULL,wbs);
return FALSE;
}


BOOL ProcessCommodityMsg(void)
{
CxMsg *msg;
ULONG msgid, msgtype;
BOOL cont, returnvalue = TRUE;

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

	switch(msgtype)
		{
		case CXM_IEVENT:
			switch(msgid)
				{
				case EVT_HOTKEY:
					if (FindWB())
						{
						if (close_windows || close_shells)
							CloseWindowsOrShells();
						cont = TRUE;
						while (cont && close_wb)
								{
							cont = !CloseWorkBench();
							if (cont)
									{
								DisplayBeep(NULL);
								cont = EasyRequestArgs(NULL, &warn_rq, NULL, NULL);
									}
								}
						if (flush_all)
							FlushAll();
						}
					else
						OpenWorkBench();
					break;
				case EVT_POPKEY:
					OpenWBWindow();
				default:
					break;
				}
			break;
		case CXM_COMMAND:
			switch(msgid)
				{
				case CXCMD_DISABLE:
					ActivateCxObj(broker, 0L);
					break;
				case CXCMD_ENABLE:
					ActivateCxObj(broker, 1L);
					break;
				case CXCMD_KILL:
					returnvalue = FALSE;
					break;
				case CXCMD_UNIQUE:
					OpenWBWindow();
					break;
				case CXCMD_APPEAR:
					OpenWBWindow();
					break;
				case CXCMD_DISAPPEAR:
					CloseWBWindow();
				default:
					break;
				}
			break;
		default:
			break;
		}
	}
return returnvalue;
}


BOOL ProcessWindowMsg(void)
{
register struct IntuiMessage *msg;
register BOOL returnvalue = TRUE;
register ULONG class;
register UWORD msgID;

while(wbwindow && (msg = GT_GetIMsg(wbwindow->UserPort)))
	{
	class = msg->Class;
	if (class & (BUTTONIDCMP|IDCMP_GADGETDOWN))
		msgID = ((struct Gadget *)msg->IAddress)->GadgetID;
	if (class == IDCMP_VANILLAKEY)
		msgID = msg->Code;
	GT_ReplyIMsg(msg);

	switch(class)
		{
		case IDCMP_REFRESHWINDOW:
			GT_BeginRefresh(wbwindow);
			GT_EndRefresh(wbwindow,TRUE);
			break;
		case IDCMP_CLOSEWINDOW:
			CloseWBWindow();
			break;
		case BUTTONIDCMP:
		case IDCMP_GADGETDOWN:
			if ( msgID == CWND_ID ) close_windows ^= TRUE;
			if ( msgID == CSHL_ID ) close_shells ^= TRUE;
			if ( msgID == CWBS_ID ) close_wb ^= TRUE;
			if ( msgID == FLSH_ID ) flush_all ^= TRUE;
			if ( msgID == HIDE_ID ) CloseWBWindow();
			if ( msgID == QUIT_ID ) returnvalue = FALSE;
			break;
		case IDCMP_VANILLAKEY:
			msgID ^= 32; /* To upper */
			if ( msgID == *key_windows ) { close_windows ^= TRUE; GT_SetGadgetAttrs( windows_gad, wbwindow, NULL, GTCB_Checked, close_windows, TAG_END ); 	}
			if ( msgID == *key_shells )  { close_shells ^= TRUE; GT_SetGadgetAttrs( shells_gad, wbwindow, NULL, GTCB_Checked, close_shells, TAG_END ); 	}
			if ( msgID == 'W' )          { close_wb ^= TRUE; GT_SetGadgetAttrs( workbench_gad, wbwindow, NULL, GTCB_Checked, close_wb, TAG_END ); 	}
			if ( msgID == *key_flush )   { flush_all ^= TRUE; GT_SetGadgetAttrs( flush_gad, wbwindow, NULL, GTCB_Checked, flush_all, TAG_END ); 	}
			if ( msgID == *key_hide )    CloseWBWindow();
			if ( msgID == *key_quit )    returnvalue = FALSE;
		}
	}
return returnvalue;
}


void CloseWBWindow(void)
{
if(wbwindow)
	{
	wleft = wbwindow->LeftEdge;
	wtop = wbwindow->TopEdge;
	EmptyMsgPort( wbwindow->UserPort );
	CloseWindow(wbwindow);
	FreeGadgets(glist);
	FreeVisualInfo(vi);
	CloseLibrary(GadToolsBase);
	wbwindow = NULL;
	}
}


void FlushAll(void)
{
register struct Node *node;

Forbid();
for(node = SysBase->LibList.lh_Head; node->ln_Succ; node = node->ln_Succ)
	RemLibrary((struct Library *)node);
for(node = SysBase->DeviceList.lh_Head; node->ln_Succ; node = node->ln_Succ)
	RemDevice((struct Device *)node);
if (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L))
	{
	for(node = GfxBase->TextFonts.lh_Head; node->ln_Succ; node = node->ln_Succ)
		RemFont((struct TextFont *)node);
	}
Permit();
}
