;/*
sc DATA=FAR NMINC STRMERGE NOSTKCHK OPTSIZE NOSTDIO IGNORE=73 DEBUG=LINE CloseWB.c
slink FROM LIB:c.o,CloseWB.o TO CloseWB LIBRARY LIB:sc.lib,LIB:Amiga.lib SC SD NOICONS STRIPDEBUG
delete CloseWB.o
quit

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

 This piece of code is Copyright © 1994 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 <workbench/startup.h>
#include <string.h>

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/alib_protos.h>
#include <clib/alib_stdio_protos.h>
#include <clib/commodities_protos.h>
#include <clib/intuition_protos.h>
#include <clib/dos_protos.h>
#include <clib/icon_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>

#define EVT_HOTKEY 1L
#define EVT_POPKEY 2L

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;
struct Window *wbwindow;
struct MsgPort *broker_mp;
CxObj *broker;

struct NewBroker newbroker = {
    NB_VERSION,
    "CloseWB",
    "CloseWB 1.6 © 1994 by Stefano Reksten of 3AM",
    "Closes or re-opens Workbench screen",
    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;

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",36L))
                {
                    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 );
    }
}


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;

    if (close_windows && wbwindow)
        CloseWBWindow();
	
    window = (FindWB())->FirstWindow;

    while(window)
    {
        next = window->NextWindow;
        if (window->UserPort && close_windows)
        {
            if (window->Title && strcmp(window->Title, "Workbench"))
                SendWindowcloseTo(window);
        }
        else if (close_shells)
        {
			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;

/* 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;
}

void AddCheckboxGadget( STRPTR name, ULONG ID, BOOL selected )
{
ng.ng_TopEdge += ng.ng_Height;
ng.ng_GadgetText = name;
ng.ng_GadgetID = ID;
gad = CreateGadget(CHECKBOX_KIND,gad,&ng,GTCB_Checked,selected,TAG_END);
textw = MaxBetween( name, textw );
}


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->WBorTop + fonth * 6 + 4 + wbs->WBorBottom;
        ng.ng_Height = fonth;
        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->WBorTop + fonth;

                gad = CreateContext(&glist);
                if (gad)
                {
                    ng.ng_TopEdge -= fonth;
                    ng.ng_Flags = PLACETEXT_RIGHT;

                    AddCheckboxGadget( "Windows", CWND_ID, close_windows );
                    AddCheckboxGadget( "Shells", CSHL_ID, close_shells );
                    AddCheckboxGadget( "Workbench", CWBS_ID, close_wb );
                    AddCheckboxGadget( "Flush", FLSH_ID, flush_all );

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

                    ng.ng_TopEdge += fonth + 2;
                    ng.ng_Width = (textw>>1) + 18;
                    ng.ng_Flags = PLACETEXT_IN;
                    ng.ng_GadgetText = "Hide";
                    ng.ng_GadgetID = HIDE_ID;
                    gad = CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

                    ng.ng_LeftEdge += ng.ng_Width + 4;
                    ng.ng_GadgetText = "Quit";
                    ng.ng_GadgetID = QUIT_ID;
                    gad = CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

                    if (gad && (wbwindow = OpenWindowTags( NULL,
                        WA_Left, (wbs->Width - wwidth)>>1,
		    		    WA_Top, (wbs->Height - wheight)>>1,
                        WA_Width, wwidth,
                        WA_Height, wheight,
                        WA_Title, "CloseWB",
                        WA_ScreenTitle, "CloseWB 1.6 © 1994 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_REFRESHWINDOW|BUTTONIDCMP,
                        TAG_END )))
                    {
                        WBenchToFront();
                        UnlockPubScreen(NULL,wbs);
                        return TRUE;
                    }
                }
                FreeVisualInfo(vi);
            }
            CloseLibrary(GadToolsBase);
        }
    }
    UnlockPubScreen(NULL,wbs);
    return FALSE;
}


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

    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 ((BOOL)FindWB())
                        {
                            if (close_wb && wbwindow)
                                CloseWBWindow();

                            if (close_windows || close_shells)
                                CloseWindowsOrShells();
                            cont = TRUE;
                            while (cont && close_wb)
                                {
                                cont = !CloseWorkBench();
                                if (cont)
                                    {
                                    DisplayBeep(NULL);
                                    cont = EasyRequest(NULL, &warn_rq, 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;
        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;
        }
    }
    return returnvalue;
}


void CloseWBWindow(void)
{
    if(wbwindow)
    {
        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);
    Permit();
	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);
    }
}
