#ifdef AZTEC_C
#include <functions.h>
#else
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#endif

#include <stdlib.h>
#include <exec/ports.h>
#include <intuition/intuition.h>

/*
 * Simple blanking skeleton. This demonstrates a simply way to implement your
 * own screen blanker that receives messages from MachIV. This eliminates
 * the need for you to create an input handler or timer routines.
 *
 * Feel free to create your own customized screen blanker. While this code is
 * Copyright 1991 by Brian Moats, you may use it and distibute both this code
 * and yours anywhere that you want. When distributing this code, please do
 * not alter it in anyway.
 *
 * This program is a bare bones skeleton. It merely opens and closes a screen
 * when told to by MachIV. The screen is red so that you know that it is not
 * MachIV's own blanker. You need only add your screen opening where it says
 * // INSERT YOUR SCREEN OPENING HERE!
 * Add you graphics drawing routines where it says
 * // INSERT YOUR GRAPHIC ROUTINES HERE!
 *
 * MachIV will execute a macro named "Blank" when the timeout says to blank
 * the screen. It also executes a macro named "Unblank" when screen blanking
 * should terminate and a macro named "MachIVQuit" when MachIV is quiting.
 * These macros could anything, but to communicate with SimpleBlanker, they
 * would be something like this:
 *
 * MSC_PUTMSG"MyScreenBlanker,1"     - Name this macro Blank.
 * MSC_PUTMSG"MyScreenBlanker,2"     - Name this macro Unblank.
 * MSC_PUTMSG"MyScreenBlanker,3"     - Name this macro MachIVQuit.
 *
 * SimpleBlanker waits on its port named "MyScreenBlanker" for one of three
 * signals. When it receives a BLANK (1) signal, it loops doing whatever
 * graphics on the screen that you program in. In this loop it also checks
 * for an UNBLANK (2) or QUIT (3) signal. Messages sent are actually
 * IntuiMessages structs but only Class, Code and Qualifier are filled in by
 * MachIV. Only Class is used in this program.
 *
 * SimpleBlanker also quits when you execute it a second time.
 *
 * Compiles under Aztec 5.2a and SAS/C 5.10a.
 *
 * Aztec:
 *
 *     cc SimpleBlanker
 *     ln SimpleBlanker.o -lc
 *
 * Lattice:
 *
 *     lc SimpleBlanker
 *     blink from lib:c.o SimpleBlanker.o to SimpleBlanker LIB lib:lc.lib \
 *           lib:amiga.lib SC SD
 *
 * Both compilers allow the // comment and I've used it here. If you are
 * using an older compiler, you will need to change them to the standard
 * comment form which I can't even show you here or it would be a nested
 * comment!
 */

// Signals sent from MachIV to your port.

#define BLANK   1
#define UNBLANK 2
#define QUIT    3

// Screen blanking constants.

#define SCREEN_DEPTH 1
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 200

// Proto declaration.

static void die(void);


// Local vars

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

char *portname = "MyScreenBlanker";

struct NewScreen newScreen = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_DEPTH,
                              -1,-1,0,CUSTOMSCREEN,NULL,NULL,NULL,NULL};
struct Screen *s;

struct MsgPort      *portptr,*rp;
struct IntuiMessage *imsg, quitmsg;

ULONG action;  // Will receive the IntuiMessage Class value.


main(int argc, char **argv)
{
  // First see if we are already running. If so, Put a message telling it
  // to quit. Wait for SimpleBlanker to Reply.

  if ((portptr = FindPort((STRPTR)portname)) != NULL) {
    if (rp = CreateMsgPort()) {   // Create a reply port for us.
      quitmsg.ExecMessage.mn_Node.ln_Type = NT_MESSAGE;
      quitmsg.ExecMessage.mn_ReplyPort = rp;
      quitmsg.ExecMessage.mn_Length = 32;
      quitmsg.Class = QUIT;
      PutMsg(portptr,(struct Message*)&quitmsg);
      WaitPort(rp); // Wait for SimpleBlanker does a ReplyMsg();
      GetMsg(rp);
      DeleteMsgPort(rp);
      exit(0);
    }
  }
  // Port not found so create and add our port.

  if ((portptr = CreateMsgPort()) == NULL)
    exit(0);

  portptr->mp_Node.ln_Pri = 1;         // Will be searched for.
  portptr->mp_Node.ln_Name = portname;

  AddPort(portptr);

  IntuitionBase = (struct IntuitionBase *) OpenLibrary((UBYTE*)"intuition.library",37L);
  GfxBase = (struct GfxBase *) OpenLibrary((UBYTE*)"graphics.library",37L);

  for (;;) {
    WaitPort(portptr); // Waiting for BLANK or QUIT
    while (imsg = (struct IntuiMessage *)GetMsg(portptr)) {
      action = imsg->Class;
      ReplyMsg((struct Message *)imsg);

      switch (action) {
        case BLANK:

// INSERT YOUR SCREEN OPENING HERE!

          // MachIV says to blank so insert your own stuff here. You can do
          // pretty much want you want, just be sure to check every so often
          // for an UNBLANK or QUIT message.
          // For demonstration purposes only, I just open a screen and set
          // it to red.

          if ((s = OpenScreen(&newScreen)) == NULL)
            break;
          SetRGB4(&s->ViewPort,0L,15L,0L,0L); // Simply displays a red screen.
          SetRGB4(&s->ViewPort,1L,15L,0L,0L);
          SetRast(&s->RastPort,0L);

          // Check for any messages.

          while ((imsg = (struct IntuiMessage *)GetMsg(portptr)) == NULL) {

// INSERT YOUR GRAPHIC ROUTINES HERE!

            // You can put you drawing or animation routines calls here.
            // A little Delay() here is nice to the system.

            Delay(5L);
          }
          // Got a message.

          action = imsg->Class;
          ReplyMsg((struct Message *)imsg);
          if (action == QUIT)
            die();                    // Will never return.
          else if (action != UNBLANK)
            break;                   // UNBLANK falls through!!
        case UNBLANK:
          if (s)
            CloseScreen(s);
          s = NULL;
          break;
        case QUIT:
          die();
          break;
      }
    }
  }
}

// This deletes and closes up everything.

static void die(void)
{
  RemPort(portptr);  // portptr must be valid or we wouldn't be here.

  DeleteMsgPort(portptr);

  if (s)
    CloseScreen(s);

  if (IntuitionBase)
    CloseLibrary((struct Library*)IntuitionBase);
  if (GfxBase)
    CloseLibrary((struct Library*)GfxBase);
  exit(0);
}
