/****************************************************************************

				Steal.c

	This file contains the main definitions of Steal 1.1 by Rick van
	Rein. Please, do not be shocked at the sight FiniteStateMachine ();
	Those goto's are the logical implementation of a finite state
	machine; This is also structured programming, only different
	from the conventional way. I thought it would suit answering
	to Intuition's messages better.

					Rick van Rein, November 4, 1990

****************************************************************************/



#include <functions.h>
#include <exec/types.h>
#include <exec/lists.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>


int OpenPrintFile ();
void ClosePrintFile ();
void mprintf ();

/* The routines that perform the real action of stealing: */

int PrintScreen ();
int PrintWindow ();
int PrintMenu ();
int PrintGadget ();


struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

struct Window *win;

struct Image *StdCheckMark;	/* For reference by the Print module */

static struct TextAttr StdTextAttr=
 {
   (UBYTE *) "topaz.font",
   8,
   FS_NORMAL,
   NULL
 };

struct TextFont *StdFont;	/* For ALL IntuiTexts; contains Topaz 8. Use it! */

static struct IntuiMessage *LastIntuiMessage=NULL;


#define TOTALIDCMP	( GADGETUP | GADGETDOWN | CLOSEWINDOW | INACTIVEWINDOW )

#define BLUE_0      0
#define WHITE_1     1
#define BLACK_2     2
#define ORANGE_3    3


SHORT xy0 []=
 {
   5,12,
   634,12,
   634,61,
   5,61,
   5,12
 };

struct Border bor0=		/* Inner border for Window */
 {
   -100,-22,					/* LeftEdge,TopEdge */
   ORANGE_3,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   5,						/* Count */
   xy0,						/* XY */
   NULL						/* NextBorder */
 };

SHORT xy1 []=
 {
   -4,-3,
   448,-3,
   448,14,
   -4,14,
   -4,-3
 };

struct Border bor1=
 {
   -80,-2,					/* LeftEdge,TopEdge */
   ORANGE_3,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   5,						/* Count */
   xy1,						/* XY */
   &bor0					/* NextBorder */
 };

SHORT xy2 []=
 {
   -1,-1,
   445,-1,
   445,12,
   -1,12,
   -1,-1
 };

struct Border bor2=
 {
   -80,-2,					/* LeftEdge,TopEdge */
   WHITE_1,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   5,						/* Count */
   xy2,						/* XY */
   &bor1					/* NextBorder */
 };

struct IntuiText itx1=
 {
   WHITE_1,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   -76,0,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "FileName:",			/* IText */
   NULL						/* NextText */
 };

struct IntuiText itx2=
 {
   BLACK_2,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   -75,1,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "FileName:",			/* IText */
   &itx1					/* NextText */
 };

char str1 [201]="";

char undo1 [201];

struct StringInfo sin1=
 {
   (UBYTE *) str1,(UBYTE *) undo1,		/* Buffer,UndoBuffer */
   0,						/* BufferPos */
   201,						/* MaxChars */
   0						/* DispPos */
	/* Intuition initializes and maintains all other variables for you */
 };

struct Gadget gad1=
 {
   NULL,					/* NextGadget */
   100,22,					/* LeftEdge,TopEdge */
   365,8,					/* Width,Height */
   GADGHCOMP,					/* Flags */
   GADGIMMEDIATE | RELVERIFY,			/* Activation */
   STRGADGET,					/* GadgetType */
   (APTR) &bor2,				/* GadgetRender (Border) */
   NULL,					/* SelectRender */
   &itx2,					/* GadgetText */
   0x00000000,					/* MutualExclude */
   (APTR) &sin1,				/* SpecialInfo (StringInfo) */
   1,						/* GadgetID */
   0x00000000,					/* UserData */
 };

SHORT xy3 []=
 {
   -4,-3,
   138,-3,
   138,14,
   -4,14,
   -4,-3
 };

struct Border bor3=
 {
   0,0,						/* LeftEdge,TopEdge */
   ORANGE_3,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   5,						/* Count */
   xy3,						/* XY */
   NULL						/* NextBorder */
 };

SHORT xy4 []=
 {
   -1,-1,
   135,-1,
   135,12,
   -1,12,
   -1,-1
 };

struct Border bor4=
 {
   0,0,						/* LeftEdge,TopEdge */
   WHITE_1,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   5,						/* Count */
   xy4,						/* XY */
   &bor3					/* NextBorder */
 };

struct IntuiText itx3=
 {
   WHITE_1,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   19,2,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Steal Screen",			/* IText */
   NULL						/* NextText */
 };

struct IntuiText itx4=
 {
   BLACK_2,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   20,3,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Steal Screen",			/* IText */
   &itx3					/* NextText */
 };

struct Gadget gad2=
 {
   &gad1,					/* NextGadget */
   20,42,					/* LeftEdge,TopEdge */
   135,12,					/* Width,Height */
   GADGHCOMP,					/* Flags */
   RELVERIFY,					/* Activation */
   BOOLGADGET,					/* GadgetType */
   (APTR) &bor4,				/* GadgetRender (Border) */
   NULL,					/* SelectRender */
   &itx4,					/* GadgetText */
   0x00000000,					/* MutualExclude */
   NULL,					/* SpecialInfo (BoolInfo) */
   2,						/* GadgetID */
   0x00000000,					/* UserData */
 };

struct IntuiText itx5=
 {
   WHITE_1,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   19,2,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Steal Window",			/* IText */
   NULL						/* NextText */
 };

struct IntuiText itx6=
 {
   BLACK_2,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   20,3,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Steal Window",			/* IText */
   &itx5					/* NextText */
 };

struct Gadget gad3=
 {
   &gad2,					/* NextGadget */
   175,42,					/* LeftEdge,TopEdge */
   135,12,					/* Width,Height */
   GADGHCOMP,					/* Flags */
   RELVERIFY,					/* Activation */
   BOOLGADGET,					/* GadgetType */
   (APTR) &bor4,				/* GadgetRender (Border) */
   NULL,					/* SelectRender */
   &itx6,					/* GadgetText */
   0x00000000,					/* MutualExclude */
   NULL,					/* SpecialInfo (BoolInfo) */
   3,						/* GadgetID */
   0x00000000,					/* UserData */
 };

struct IntuiText itx7=
 {
   WHITE_1,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   23,2,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Steal Menu",			/* IText */
   NULL						/* NextText */
 };

struct IntuiText itx8=
 {
   BLACK_2,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   24,3,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Steal Menu",			/* IText */
   &itx7					/* NextText */
 };

struct Gadget gad4=
 {
   &gad3,					/* NextGadget */
   330,42,					/* LeftEdge,TopEdge */
   135,12,					/* Width,Height */
   GADGHCOMP,					/* Flags */
   RELVERIFY,					/* Activation */
   BOOLGADGET,					/* GadgetType */
   (APTR) &bor4,				/* GadgetRender (Border) */
   NULL,					/* SelectRender */
   &itx8,					/* GadgetText */
   0x00000000,					/* MutualExclude */
   NULL,					/* SpecialInfo (BoolInfo) */
   4,						/* GadgetID */
   0x00000000,					/* UserData */
 };

struct IntuiText itx9=
 {
   WHITE_1,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   19,2,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Steal Gadget",			/* IText */
   NULL						/* NextText */
 };

struct IntuiText itx10=
 {
   BLACK_2,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   20,3,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Steal Gadget",			/* IText */
   &itx9					/* NextText */
 };

struct Gadget gad5=
 {
   &gad4,					/* NextGadget */
   485,42,					/* LeftEdge,TopEdge */
   135,12,					/* Width,Height */
   GADGHCOMP,					/* Flags */
   RELVERIFY,					/* Activation */
   BOOLGADGET,					/* GadgetType */
   (APTR) &bor4,				/* GadgetRender (Border) */
   NULL,					/* SelectRender */
   &itx10,					/* GadgetText */
   0x00000000,					/* MutualExclude */
   NULL,					/* SpecialInfo (BoolInfo) */
   5,						/* GadgetID */
   0x00000000,					/* UserData */
 };

struct IntuiText itx11=
 {
   WHITE_1,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   19,2,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Cancel action",			/* IText */
   NULL						/* NextText */
 };

struct IntuiText itx12=
 {
   BLACK_2,BLUE_0,				/* FrontPen, BackPen */
   JAM1,					/* DrawMode */
   20,3,					/* LeftEdge, TopEdge */
   NULL,					/* ITextFont */
   (UBYTE *) "Cancel action",			/* IText */
   &itx11					/* NextText */
 };

struct Gadget gad6=
 {
   &gad5,					/* NextGadget */
   485,20,					/* LeftEdge,TopEdge */
   135,12,					/* Width,Height */
   GADGHCOMP,					/* Flags */
   RELVERIFY,					/* Activation */
   BOOLGADGET,					/* GadgetType */
   (APTR) &bor4,				/* GadgetRender (Border) */
   NULL,					/* SelectRender */
   &itx12,					/* GadgetText */
   0x00000000,					/* MutualExclude */
   NULL,					/* SpecialInfo (BoolInfo) */
   6,						/* GadgetID */
   0x00000000,					/* UserData */
 };

struct NewWindow nwin=
 {
   0,12,					/* LeftEdge,TopEdge */
   640,64,					/* Width,Height */
   BLUE_0,WHITE_1,				/* DetailPen,BlockPen */
   TOTALIDCMP,					/* IDCMPFlags */
   WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SIMPLE_REFRESH | ACTIVATE | WINDOWACTIVE | WINDOWTICKED,
						/* Flags */
   &gad6,					/* FirstGadget */
   NULL,					/* CheckMark */
   (UBYTE *) "Steal 1.1 --- Copyright 1990 Rick van Rein ",
   						/* Title */
   NULL,					/* Screen */
   NULL,					/* BitMap */
   640,64,					/* MinWidth,MinHeight */
   640,64,					/* MaxWidth,MaxHeight */
   WBENCHSCREEN					/* Type */
 };
#define filename str1



/***** Report an error, that was given as a string: */

char REPORT_COPYRIGHT []="Steal 1.1 --- Copyright 1990 Rick van Rein ";
char REPORT_BUSY []="Steal 1.1 --- Sneaking into Intuition right now - Hold your breath ";
char REPORT_SEL_SCREEN []="Steal 1.1 --- Select a Screen or Cancel ";
char REPORT_SEL_WINDOW []="Steal 1.1 --- Select a Window or Cancel ";
char REPORT_SEL_MENU []="Steal 1.1 --- Select a Window with a Menu or Cancel ";
char REPORT_SEL_GADGET []="Steal 1.1 --- Select a Gadget or Cancel ";

char ERR_CANCEL []="Steal 1.1 --- Cancel selected ";
char ERR_NOWINDOW []="Steal 1.1 --- No Window at mouse position ";
char ERR_NOMENU []="Steal 1.1 --- That Window does not bear a Menu ";
char ERR_NOGADGET []="Steal 1.1 --- No Gadget at mouse position ";
char ERR_NOFILE []="Steal 1.1 --- Can't open file - Try again please ";
char ERR_NOSCREEN []="Steal 1.1 --- No Screen is available (?) ";

void Error (str)
   char *str;
 {
   SetWindowTitles (win,str,-1L);	/* Leave Screens title alone */
   ActivateWindow (win);		/* To make title better readable */
   ScreenToFront (win->WScreen);
   DisplayBeep (0L);
 }

void Report (str)
   char *str;
 {
   SetWindowTitles (win,str,-1L);
 }

/***** The GADGETUP have internal names, see below. Decode an IMsg and find the internal type: */

#define GUP_STR		0x01000000L
#define GUP_SCREEN	0x02000000L
#define GUP_WINDOW	0x04000000L
#define GUP_MENU	0x08000000L
#define GUP_GADGET	0x10000000L
#define GUP_CANCEL	0x20000000L
#define GUP_STEAL	( GUP_SCREEN | GUP_WINDOW | GUP_MENU | GUP_GADGET )

long DecodeIDCMP (imsg)
   struct IntuiMessage *imsg;
 {
   long class=imsg->Class;

   if (class & GADGETUP)
      class=GUP_STR << (((struct Gadget *) imsg->IAddress)->GadgetID -1);
   return class;
 }


/***** Get an IntuiMessage that suits us right now; sel uses internal IDCMP-codes: */


       /* NOTE: Before we return an IntuiMessage, we first ReplyMsg the last one we returned, if any */

struct IntuiMessage *GetIDCMP (sel)
   long sel;
 {
   struct Node *this,*next;

   if (LastIntuiMessage)
    {
      ReplyMsg (LastIntuiMessage);
      LastIntuiMessage=NULL;
    }

   do
    {
      WaitPort (win->UserPort);
      this=(struct Node *) GetMsg (win->UserPort);
      if (sel & DecodeIDCMP (this))
         return (LastIntuiMessage=(struct IntuiMessage *) this);	/* Indeed an assignment! */
      else
	 ReplyMsg (this);
    }
   while (1);				/* Escape this loop with return */
 }



/***** Find the Gadget on which the mouse is currently; Also give the Error if needed: */

struct Gadget *FindActiveGadget ()
 {
   struct Gadget *gad;
   struct Window *wdw;
   struct Screen *scr;
   int x,y,relx,rely;

   wdw=IntuitionBase->ActiveWindow;
   if (!wdw)
    {
      Error (ERR_NOWINDOW);
      return NULL;
    }
   scr=wdw->WScreen;	/* Of course it's there! What else should contain this window? */

   x=scr->MouseX - wdw->LeftEdge;	/* MouseX relative to Window */
   y=scr->MouseY - wdw->TopEdge;	/* MouseY relative to Window */

   gad=wdw->FirstGadget;
   while (gad)
    {
      relx=x - gad->LeftEdge;		/* MouseX relative to Gadget */
      rely=y - gad->TopEdge;		/* MouseY relative to Gadget */
      if (gad->Flags & GRELRIGHT)
         relx-=wdw->Width-1;
      if (gad->Flags & GRELBOTTOM)
         rely-=wdw->Height-1;

      if (relx>=0 && rely>=0 && relx<gad->Width && rely<gad->Height)
         return gad;			/* Found it!!! */

      gad=gad->NextGadget;
    }

   Error (ERR_NOGADGET);
   return NULL;
 }



/***** The finite state machine: */

void FiniteStateMachine ()
 {
   ULONG IBaseLock;
   struct IntuiMessage *im;
   long oldclass;
   struct Window *wdw;
   struct Screen *scr;
   struct Gadget *gad;
   int nr;

	/* State 0: Activate the string and start inputing it: */
   ACT_START:
      ActivateGadget (&gad1,win,0L);

	/* State 1: Input a string in the (now active) string-Gadget */
   START:
      im=GetIDCMP (GADGETDOWN | CLOSEWINDOW | GUP_STR | GUP_STEAL | GUP_CANCEL);
      if (im->Class==GADGETDOWN)
	 goto START;
      if (im->Class==CLOSEWINDOW)
         goto EXIT;
      if (DecodeIDCMP (im)==GUP_CANCEL)
	 DisplayBeep (0L);

	/* Test if the file with the given stringname can be opened: */
      if (!OpenPrintFile (filename))
       {
         Error (ERR_NOFILE);
         goto ACT_START;
       }
      Report (REPORT_COPYRIGHT);

      if (DecodeIDCMP (im) & (GUP_STEAL | CLOSEWINDOW))
         goto LOOPTEST;

	/* State 2: Wait for some signal from the IDCMP in this main WAIT-STATE */
   LOOP:
      im=GetIDCMP (CLOSEWINDOW | GADGETDOWN | GUP_STEAL);

      	/* State 3: Process the signal that was last read: */
   LOOPTEST:
      oldclass=DecodeIDCMP (im);
      if (oldclass==CLOSEWINDOW)
         goto CLOSE_EXIT;
      if (oldclass==GADGETDOWN)		/* Only string reports GADGETDOWN */
         goto NEWSTRING;

	/* State 4: We now have to steal. Wait for INACTIVEWINDOW to tell us what to steal: */
   STEAL:
      switch (oldclass)				/* Ask user to click item to be stolen */
       {
         case GUP_SCREEN:
	    Report (REPORT_SEL_SCREEN);
	    break;
         case GUP_WINDOW:
	    Report (REPORT_SEL_WINDOW);
            break;
         case GUP_MENU:
	    Report (REPORT_SEL_MENU);
            break;
         case GUP_GADGET:
	    Report (REPORT_SEL_GADGET);
            break;
       }

       		/* Now, before looking at what item the user selected, first be sure all IntuiMsgs
		   that were still pending are gone: */
      while (im = (struct IntuiMessage *) GetMsg (win->UserPort))
         ReplyMsg (im);
      im=GetIDCMP (CLOSEWINDOW | INACTIVEWINDOW | GUP_CANCEL | GUP_STEAL | GADGETDOWN);
      if (im->Class==CLOSEWINDOW)
         goto CLOSE_EXIT;
      if (im->Class==GADGETUP)			/* Must be a GUP_CANCEL or some GUP_STEAL */
       {
         if (DecodeIDCMP (im) & GUP_STEAL)
	    goto LOOPTEST;
	 else
	  {
            Error (ERR_CANCEL);
	    goto LOOP;
          }
       }
      if (im->Class==GADGETDOWN)		/* This must have been the string-Gadget. Timing ??? */
         goto NEWSTRING;

      Report (REPORT_BUSY);
      IBaseLock = LockIBase (0L);
      switch (oldclass)
       {
         case GUP_SCREEN:
            goto STEALSCREEN;
         case GUP_WINDOW:
            goto STEALWINDOW;
         case GUP_MENU:
            goto STEALMENU;
         case GUP_GADGET:
            goto STEALGADGET;
       }

   STEALSCREEN:
      if (scr=IntuitionBase->ActiveScreen)
       {
         nr=PrintScreen (scr);
	 goto REPORT;
       }
      Error (ERR_NOSCREEN);
      goto JUSTLOOP;

   STEALWINDOW:
      if (wdw=IntuitionBase->ActiveWindow)
       {
         nr=PrintWindow (wdw,0);
	 goto REPORT;
       }
      Error (ERR_NOWINDOW);
      goto JUSTLOOP;

   STEALMENU:
      if (wdw=IntuitionBase->ActiveWindow)
       {
         if (!wdw->MenuStrip)
	  {
	    Error (ERR_NOMENU);
	    goto JUSTLOOP;
	  }
         nr=PrintMenu (wdw->MenuStrip);
	 goto REPORT;
       }
      Error (ERR_NOWINDOW);
      goto JUSTLOOP;

   STEALGADGET:
      if (gad=FindActiveGadget ())
       {
         nr=PrintGadget (gad,0);
	 goto REPORT;
       }
      goto JUSTLOOP;

   NEWSTRING:
      ClosePrintFile ();
      goto START;

   REPORT:
      Error (REPORT_COPYRIGHT);

   JUSTLOOP:
      UnlockIBase (IBaseLock);
      goto LOOP;

   CLOSE_EXIT:
      ClosePrintFile ();

   EXIT:
      ;
 }


int main ()
 {
   if (!(IntuitionBase=(struct IntuitionBase *) OpenLibrary ("intuition.library",0L)))
    {
      puts ("\tSteal: Can't open intuition.library somehow (?)");
      exit (0);
    }
   if (!(GfxBase=(struct GfxBase *) OpenLibrary ("graphics.library",0L)))
    {
      puts ("\tSteal: Can't open graphics.library somehow (?)");
      CloseLibrary (IntuitionBase);
      exit (0);
    }

   strcpy (filename,"Stolen.c");

   if (win=OpenWindow (&nwin))
    {
      StdCheckMark=win->CheckMark;
      StdFont=(struct TextFont *) OpenFont (&StdTextAttr);
      win->IFont=StdFont;
      SetFont (win->RPort,StdFont);
      SetFont (win->BorderRPort,StdFont);

      FiniteStateMachine ();

      if (LastIntuiMessage)
         ReplyMsg (LastIntuiMessage);

      if (StdFont)
         CloseFont (StdFont);
      CloseWindow (win);
    }
   else
      puts ("\tSteal: Couldn't open window");

   CloseLibrary (GfxBase);
   CloseLibrary (IntuitionBase);
   return 0;
 }
