/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the authors.                                                    */
/* | o  | ||    Dave Baker     Ed Burnette  Stan Chow    Jay Denebeim        */
/* |  . |//     Gordon Keener  Jack Rouse   John Toebes  Doug Walker         */
/* ======          BBS:(919)-471-6436      VOICE:(919)-469-4210              */ 
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
 * VERY loosely based on the input.device example by Rob Peck, 12/1/85
 */

/* * * * * * * * * INCLUDE FILES * * * * * * * * * * * */
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <exec/ports.h>
#include <exec/libraries.h>
#include <exec/io.h>
#include <exec/tasks.h>
#include <exec/execbase.h>
#include <exec/devices.h>
#include <devices/timer.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <graphics/gfxmacros.h>
#include <hardware/custom.h>
#include <hardware/dmabits.h>

/* * * * * * * * * * * CONSTANTS * * * * * * * * * * * * */
#define TIMEINTERVAL 1L      /* in seconds */
#define DEFLIMIT     300     /* two minute timeout */
#define ESCAPEKEY    0x45
#define DEFCMD    "NEWCLI >NIL: <NIL:"
#define BANNER "0;33mPOPCLI II0m by John Toebes - Copyright ) 1986 The Software Distillery\n 235 Trillingham Ln, Cary NC 27511   BBS:(919)-471-6436\n"
#define BANNER1 "Usage: 1mRUN POPCLI0m [secs [command]]\nsecs is number of seconds before blanking screen\ncommand is to be executed when Left Amiga-Escape is pressed\n"
/* * * * * * * * * * * GLOBAL VARIABLES * * * * * * * * * */
typedef struct
   {
   struct task          *buddy;
   ULONG                 createclisig;
   ULONG                 unblanksig;
   ULONG                 noevents;
   struct Screen        *blankscreen;
   } GLOBAL_DATA;

/************************************************************************/
/* the handler subroutine - called through the handler stub             */
/************************************************************************/
struct InputEvent *myhandler(ev, gptr)
struct InputEvent *ev;      /* and a pointer to a list of events */
register GLOBAL_DATA *gptr;      /* Everything we need to know about */
   {
   register struct InputEvent *ep, *laste;

   /* run down the list of events to see if they pressed the magic button */
   for (ep = ev, laste = NULL; ep != NULL; ep = ep->ie_NextEvent)
      {
      if ((ep->ie_Class == IECLASS_RAWKEY) &&
          (ep->ie_Code  == ESCAPEKEY)         &&
          (ep->ie_Qualifier & IEQUALIFIER_LCOMMAND))
         {
         /* we can handle this event so take it off the chain */
         if (laste == NULL)
            ev = ep->ie_NextEvent;
         else
            laste->ie_NextEvent = ep->ie_NextEvent;
         /* now tell him to create the new cli */
         Signal(gptr->buddy, gptr->createclisig);
         }
      else
         laste = ep;

      if (ep->ie_Class != IECLASS_TIMER)
         {
         gptr->noevents = 0;
         if (gptr->blankscreen != NULL)
            Signal(gptr->buddy, gptr->unblanksig);
         }
      }

   /* pass on the pointer to the event */
   return(ev);
   }

/* * * * * * * * * * * EXTERNAL ROUTINES * * * * * * * * * */
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase       *GfxBase = NULL;
long                  DOSBase = 0;
extern struct Custom custom;
struct NewScreen      NewScreen = 
   { 0, 0, 320, 30, 1, 0, 1, NULL, CUSTOMSCREEN, NULL, NULL, NULL, NULL };

extern APTR             AllocMem();
extern struct MsgPort  *CreatePort();
extern struct IOStdReq *CreateStdIO();
extern struct Screen   *OpenScreen();
extern void             HandlerInterface();
extern struct task     *FindTask();

/************************************************************************/
/* Queue a timer to go off in a given number of seconds                 */
/************************************************************************/
void QueueTimer(tr,seconds)
struct timerequest *tr;
ULONG seconds;
   {
   tr->tr_node.io_Command = TR_ADDREQUEST;   /* add a new timer request */
   tr->tr_time.tv_secs =  seconds;        	/* seconds */
   tr->tr_time.tv_micro = 0;
   SendIO( tr );
   }

/************************************************************************/
/* the main program to do the popcli stuff                              */
/************************************************************************/
void _main(cmd)
char *cmd;
   {
   long  intlimit = 0, nullfh;
   ULONG sig, timersig;
   struct timerequest *timerreq;
   struct MsgPort     *timerport;
   struct MsgPort     *inputDevPort;
   struct IOStdReq    *inputRequestBlock;
   struct Interrupt      handlerStuff;
   GLOBAL_DATA global;

   global.blankscreen = NULL;

   global.buddy = FindTask(0);
   global.noevents = 0;

   if (cmd)
      {
      /* ugh we are reusing a variable here - so what - it saves bytes */
      sig = Output();
      Write(sig, BANNER, sizeof(BANNER));

      /* skip over any leading spaces in the command line */
      while(*cmd == ' ')
         cmd++;

      /* see if they specified a limit */
      if (*cmd)
         {
         while ((*cmd >= '0') && (*cmd <= '9'))
            intlimit = ((short)intlimit*(short)10) + *cmd++ - '0';
         }

      if (intlimit <= 0)
         {
         Write(sig, BANNER1, sizeof(BANNER1));
         intlimit = DEFLIMIT;
         }

      /* now skip over any more leading spaces */
      while(*cmd == ' ')
         cmd++;

      if (*cmd <= ' ')
         cmd = DEFCMD;

      if (sig != Input())
         Close(Input());
      Close(sig);
      }
   else
      {
      intlimit = DEFLIMIT;
      cmd = DEFCMD;
      }

   /* set the input and output streams to 0 so execute doen't complain */
   nullfh = Open("NIL:", MODE_NEWFILE);
   SetTaskPri( global.buddy, 20);

   if ((inputDevPort = CreatePort(0,0)) == NULL) /* for input device */
      goto abort0;

   if ((inputRequestBlock = CreateStdIO(inputDevPort)) == 0)
      goto abort1;

   if ((timerport = CreatePort(0,0)) == NULL)
      goto abort1;

   if ((timerreq = (struct timerequest *)
                    AllocMem(sizeof(struct timerequest),
                             MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
      goto abort2;

   timerreq->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
   timerreq->tr_node.io_Message.mn_Node.ln_Pri = 0;
   timerreq->tr_node.io_Message.mn_ReplyPort = timerport;

   if (OpenDevice(TIMERNAME, UNIT_VBLANK, timerreq, 0))
      goto abort;

   timersig = (1 << timerport->mp_SigBit);

   if ((sig = AllocSignal(-1)) == -1)
      goto abort;

   global.createclisig = 1 << sig;

   if ((sig = AllocSignal(-1)) == -1)
      goto abort;

   global.unblanksig = 1 << sig;

   if ((GfxBase = (struct GfxBase *)
                  OpenLibrary("graphics.library", 0)) == NULL)
      goto abort;

   if ((IntuitionBase = (struct IntuitionBase *)
                        OpenLibrary("intuition.library", 0)) == NULL)
      goto abort;

   handlerStuff.is_Data = (APTR)&global;
   handlerStuff.is_Code = HandlerInterface;
   handlerStuff.is_Node.ln_Pri = 51;

   if (OpenDevice("input.device",0,inputRequestBlock,0))
      goto abort;

   inputRequestBlock->io_Command = IND_ADDHANDLER;
   inputRequestBlock->io_Data    = (APTR)&handlerStuff;

   DoIO(inputRequestBlock);

   QueueTimer(timerreq, TIMEINTERVAL);

   for(;;)         /* FOREVER */
      {
      sig = Wait( global.createclisig | global.unblanksig | timersig );

      if ((sig & global.unblanksig) && (global.blankscreen != NULL))
         {
         (void) CloseScreen(global.blankscreen);
	 ON_DISPLAY
         global.blankscreen = NULL;
         }

      if (sig & global.createclisig)
         {
         WBenchToFront();
         (void)Execute(cmd,nullfh,nullfh);
         }

      if (sig & timersig)
         {
         /* get rid of the message */
         (void)GetMsg(timerport);
         QueueTimer(timerreq, TIMEINTERVAL);

         if ((global.noevents++ >= intlimit) && (global.blankscreen == NULL))
            {
            if ( (global.blankscreen = OpenScreen(&NewScreen)) != NULL)
               {
               SetRGB4(&(global.blankscreen->ViewPort), 0, 0, 0, 0);
               OFF_DISPLAY
               }
            }
         }
      }

abort:
   CloseDevice(timerreq);
abort3:
/* timerreq->tr_node.io_Message.mn_Node.ln_Type = 0xff;
 * timerreq->tr_node.io_Device = (struct Device *) -1;
 * timerreq->tr_node.io_Unit = (struct Unit *) -1;
 */

   FreeMem (timerreq, sizeof(struct timerequest));
abort2:
   DeletePort(timerport);
abort1:
   if (IntuitionBase != NULL)
      CloseLibrary(IntuitionBase);

   if (GfxBase != NULL)
      CloseLibrary(GfxBase);

   DeletePort(inputDevPort);
abort0:
   XCEXIT(-1);
   }
