#include "exec/types.h"
#include "exec/ports.h"
#include "exec/io.h"
#include "exec/memory.h"
#include "graphics/gfx.h"
#include "devices/timer.h"
#include "libraries/dos.h"
#include "workbench/startup.h"

#include "proto/exec.h"
#include "proto/graphics.h"
#include "proto/layers.h"
#include "proto/intuition.h"
#include "proto/timer.h"
#include "proto/dos.h"

#include "string.h"
#include "ctype.h"
#include "dos.h"

#include "hp11/hp11.h"
#include "hp11/amiga/internal.h"
#include "hp11/amiga/amiga.h"
#include "hp11/amiga/menus.h"

#define MAXWIDTH 29 /* X distance between 2 keys */
#define MAXHEIGHT 29 /* Y distance bewteen 2 keys */
#define KEYWIDTH 20 /* Width of actual key */
#define KEYHEIGHT 16 /* Height of actual key */
#define TOPKEYHEIGHT 9 /* Height of top of key */
#define KEYX (19 + HP11X) /* Position of first key */
#define KEYY (61 + HP11Y)
#define CHAROFFX -1 /* offset in display for first char */
#define CHAROFFY 3
#define CHARWIDTH 14 /* Size of char */
#define CHARHEIGHT 13
#define SCRX0 (53 + HP11X) /* Limits of display for chars */
#define SCRX1 (208 + HP11X)
#define SCRY0 (11 + HP11Y)
#define SCRY1 (37 + HP11Y)
#define fX (SCRX0 + 3 * CHARWIDTH + 2) /* Position of indicators */
#define gX (SCRX0 + 4 * CHARWIDTH - 1)
#define GX (SCRX0 + (int)(6.5 * CHARWIDTH))
#define RADX (GX + 5)
#define PRGMX (SCRX0 + 10 * CHARWIDTH - 6)
#define USERX (SCRX0 + CHARWIDTH)
#define INDICY (SCRY0 + 19)

#define CR 13
#define BS 8
#define ESC 27

#define COPY 0xc0 /* minterm for straight copy */

struct Library *TimerBase; /* Base for calling timer routines */

extern struct Border *hp11char[]; /* Character descriptions (as connected lines) */
/* Indicator shapes (as bitmaps) */
extern struct Image fImage, gImage, USERImage, GImage, RADImage, PRGMImage;
extern struct Image off_image; /* Image for sleep */

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
struct LayersBase *LayersBase;

struct Window *hp11; /* The window containing the hp11 */

/* These informations are for RelKey() */
/* The method by which the latest key was obtained :
  From the menus, from the CLOSE gadget, from the keyboard, or by selecting with the mouse */
static enum {menu, gadget, keyboard, mouse} keytype;
/* The keycode of the last key read */
static short lastkey;
/* The Time at which the last key was read */
static ULONG secs, micros;
/* Path to executable */
char *hp11name;
char hp11path[PATHLEN];

static struct timerequest *timer; /* The timer which is used */
static struct NewWindow hp11new = { /* Desired window */
   0,0, /* Position of top left corner */
   HP11WIDTH + 6, HP11HEIGHT + 14, /* Width, Height */
   -1,-1, /* Use default pens to draw window */
   CLOSEWINDOW | MOUSEBUTTONS | VANILLAKEY | MENUPICK,
   WINDOWDEPTH | WINDOWCLOSE | WINDOWDRAG | SMART_REFRESH | NOCAREREFRESH,
   NULL, NULL,
   "HP11C", NULL,
   NULL,
   0, 0, 0, 0,
   WBENCHSCREEN /* It opens in the main screen */
};

static struct IntuiText canceltext = {
   AUTOFRONTPEN, AUTOBACKPEN,
   AUTODRAWMODE,
   AUTOLEFTEDGE, AUTOTOPEDGE,
   AUTOITEXTFONT,
   "Cancel",
   AUTONEXTTEXT
};

static struct IntuiText nomemtext = {
   AUTOFRONTPEN, AUTOBACKPEN,
   AUTODRAWMODE,
   20, 10,
   AUTOITEXTFONT,
   "Not enough memory",
   NULL
};

char *mygetpath(to, l)
register char *to;
register BPTR l;
{
   register BPTR tl;
   register int notfirst = FALSE;
   register struct FileInfoBlock *fib = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock), 0);

   if (!fib) return(NULL);
   to[0] = '\0';

   do {
      if (!Examine(l, fib)) return(NULL);
      if (fib->fib_DirEntryType > 0) strins(to, "/");
      if (fib->fib_FileName[0] == '\0') strins(to, "RAM");
      else strins(to, fib->fib_FileName);
      tl = l;
      l = ParentDir(l);
      if (notfirst) UnLock(tl);
      notfirst = TRUE;
   } while (l);

   *(strchr(to, '/')) = ':';
   FreeMem((char *)fib, sizeof(struct FileInfoBlock));
   return(to);
}

void split(char *file, char *path, char **name)
{
   int l = strlen(file);

   *name = file + l;
   while (--l >= 0 && (*--*name != '/' && **name != ':')) ;
   if (l < 0)
      path[0] = '\0';
   else
   {
      ++*name;
      strncpy(path, file, l + 1);
      path[l + 1] = '\0';
   }
}

/* Delete a timer */
static void DeleteTimer(struct timerequest *tr)
{
   TimerBase = (struct Library *)(-1); /* Don't call any more ! */

   if (tr != NULL)
   {
      /* Remove the port */
      if (tr->tr_node.io_Message.mn_ReplyPort) DeletePort(tr->tr_node.io_Message.mn_ReplyPort);

      CloseDevice((struct IORequest *)tr); /* Close the device */
      DeleteExtIO((struct IORequest *)tr); /* Free the IO request */
   }
}

/* Create a timer of type unit */
static struct timerequest *CreateTimer(ULONG unit)
{
   register long error;

   register struct MsgPort *timerport;
   register struct timerequest *timermsg;

   if ((timerport = CreatePort(NULL, 0)) == NULL) /* first get a port */
      return(NULL); /* failed */

   if ((timermsg = (struct timerequest *) /* Then create an IO request for the timer */
		   CreateExtIO(timerport, sizeof(struct timerequest))) == NULL)
      return(NULL); /* failed */

   if ((error = OpenDevice(TIMERNAME, unit, (struct IORequest *)timermsg, 0)) != 0) /* Finally, open the timer device */
   { /* failed */
      DeleteTimer(timermsg);
      return(NULL);
   }

   TimerBase = (struct Library *)timermsg->tr_node.io_Device; /* Allow calls to the time arithmetic routines */
   return(timermsg);
}

/* Wait for a specified duration */
static void WaitFor(struct timeval *tv)
{
   timer->tr_node.io_Command = TR_ADDREQUEST;

   timer->tr_time = *tv;

   DoIO((struct IORequest *)timer); /* Wait for completion of request */
}

/* Obtain the system time, assume global timer contains a valid timer */
static void GetSysTime(struct timeval *tv)
{
   timer->tr_node.io_Command = TR_GETSYSTIME;
   DoIO((struct IORequest *)timer);

   *tv = timer->tr_time; /* Copy obtained time */
}

/* Reverse the key on the keyboard (as if user was holding it down) */
static void ReverseKey(int key)
{
   register int kx, ky, h;

   if (key == 30) h = KEYHEIGHT - 1; /* ON, higher than average */
   else if (key == 25) h = MAXHEIGHT + TOPKEYHEIGHT - 1; /* ENTER, even taller */
   else h = TOPKEYHEIGHT - 1;

/* -------------------- */
/* Check for bug when using short int */

   kx = (key % 10) * MAXWIDTH + KEYX; /* Calc. key position */
   ky = (key / 10) * MAXHEIGHT + KEYY;

   SetDrMd(hp11->RPort, COMPLEMENT); /* Draw in reverse */
   RectFill(hp11->RPort, (long)kx, (long)ky, (long)(kx + (KEYWIDTH - 1)), (long)(ky + h));
}

/* From positions x & y, deduce which key was pressed */
static int DecodeKey(int x, int y)
{
   register int kx, ky, px, py;

   kx = (x - KEYX) / MAXWIDTH; px = (x - KEYX) % MAXWIDTH;
   ky = (y - KEYY) / MAXHEIGHT; py = (y - KEYY) % MAXHEIGHT;

   if (/* first, check if in keyboard. x & y are tested (instead of kx, ky)
	  because kx & ky suffer a roundoff towards zero for negative values */
       (x >= KEYX && y >= KEYY && kx <= 9 && ky <= 3)
       &&
	  /* now the condition on width */
       (px < KEYWIDTH && px >= 0) /* same for all keys */
       &&
	 /* condition on height, 2 cases for ENTER is different */
       (
	   (kx == 5 && (ky == 2 || (ky == 3 && py < KEYHEIGHT) && (ky = 2))) /* ENTER, set ky to correct value when ky == 3 */
	   || /* condition on height */
	   (py < KEYHEIGHT && py >= 0)
       )
      ) return(ky * 10 + kx);
   else return(-1);
}

/* Mouse was pressed at x,y. Is this a key ? */
static int GetMouseKey(int x, int y)
{
   int key;

   if ((key = DecodeKey(x, y)) != -1) { /* yes */
      ReverseKey(key);
      keytype = mouse; /* info for RelKey() */
   }
   return(key);
}

/* Key keycode was pressed by the user */
static int GetKeyKey(int _keycode)
{
   register int key = -1, keycode = tolower(_keycode);

   switch (keycode) {
      case ESC: key = 30; break;
      case '7': case '8': case '9': key = keycode - ('7' - 6); break;
      case '4': case '5': case '6': key = keycode - ('4' - 16); break;
      case '1': case '2': case '3': key = keycode - ('1' - 26); break;
      case '0': key = 36; break;
      case '.': key = 37; break;
      case '^': key =  3; break;
      case '*': key = 19; break;
      case '-': key = 29; break;
      case '+': key = 39; break;
      case '/': key =  9; break;
      case '_': key =  5; break;
      case CR : key = 25; break;
      case 'f': key = 31; break;
      case 'g': key = 32; break;
      case BS : key = 24; break;
      case 's': key = 12; break;
      case 'c': key = 13; break;
      case 't': key = 14; break;
   }
   if (key != -1) { /* A valid key was given */
      ReverseKey(key);
      keytype = keyboard; /* for RelKey() */
   }
   return(key);
}

/* Get a key from the keyboard with/without waiting */
int PollKey(wait)
int wait;
{
   register int key;
   register struct IntuiMessage *msg;
   register ULONG class;
   register UWORD code;
   register WORD x, y;
   register APTR address;

   key = -1; /* no key yet */
   do {
      if (wait) WaitPort(hp11->UserPort); /* No active waits in multi-tasking ! */
      msg = (struct IntuiMessage *)GetMsg(hp11->UserPort); /* Get the message if there is one */
      if (msg) { /* yes, there is */
	 /* Copy relevant information */
	 class = msg->Class;
	 code = msg->Code;
	 address = msg->IAddress;
	 x = msg->MouseX;
	 y = msg->MouseY;
	 secs = msg->Seconds;
	 micros = msg->Micros;
	 ReplyMsg((struct Message *)msg); /* & reply to it */

	 switch (class) { /* type of message */
	    case CLOSEWINDOW: /* Window closed = Quit */
	       quit = TRUE;
	       key = BRESET;
	       keytype = gadget;
	       break;
	    case MOUSEBUTTONS: /* A mouse button was pressed */
	       if (code == SELECTDOWN)
		  key = GetMouseKey(x, y);
	       break;
	    case VANILLAKEY: /* a key was pressed */
	       key = GetKeyKey(code);
	       break;
	    case MENUPICK: /* A menu option was chosen */
	       key = MenuHandler(code); /* Call menu handler */
	       keytype = menu; /* for RelKey() */
	       break;
	 }
      }
   } while (key == -1 && (msg || wait));
   /* Exit if key read or, if not waiting, no message ready */

   lastkey = key; /* save key for RelKey() */
   return(key);
}

/* Wait for latest key to be released, returns true if button released
  over key (valid only for mouse) */
BOOL RelKey()
{
   register WORD x, y;
   register BOOL Released;
   register struct IntuiMessage *msg;
   struct timeval event, now, delay;
   register int key = lastkey; /* key last pressed */

   lastkey = -1; /* Only release it once ! */

   if (key != -1)
      switch (keytype) {

	 case keyboard: /* Key reversed for a max of .08 secs
	    (There is no easy way to wait for its release on the keyboard) */
	    event.tv_secs = secs; event.tv_micro = micros;
	    GetSysTime(&now);
	    SubTime(&now, &event); /* Time elapsed since key pressed */
	    delay.tv_secs = 0; delay.tv_micro = 80000;
	    if (CmpTime(&now, &delay) == 1) { /* now < delay */
	       SubTime(&delay, &now);
	       WaitFor(&delay); /* Wait long enough */
	    }
	    ReverseKey(key); /* un-reverse key */
	    return(TRUE);

	 case mouse:
	    Released = FALSE;
	    do { /* Wait for mouse button to be released */
	       WaitPort(hp11->UserPort);
	       msg = (struct IntuiMessage *)GetMsg(hp11->UserPort);
	       x = msg->MouseX;
	       y = msg->MouseY;
	       Released = (msg->Class == MOUSEBUTTONS && msg->Code == SELECTUP);
	       ReplyMsg((struct Message *)msg);
	    } while (!Released);
	    ReverseKey(key); /* un-reverse key */

	    return((BOOL)(DecodeKey(x, y) == key)); /* Button released over key? */
      }
   return(TRUE); /* if already released */
}

/* load picture from open file file, width pixel wide, height pixels high,
  depth bitplanes deep into bitmap bm & colormap cols (if non-null) */
static BOOL LoadBitMap(LONG file, struct BitMap *bm, int width, int height,
		       int depth)
{
   register int i;
   register LONG nb, plsize;

   InitBitMap(bm, (long)depth, (long)width, (long)height);
   plsize = bm->BytesPerRow * bm->Rows; /* size of 1 plane */
   /* Allocate enough memory for all planes, initialise plane pointers */
   if (!(bm->Planes[0] = (PLANEPTR)AllocMem(plsize * depth, MEMF_CHIP))) return((BOOL) FALSE);
   for (i = 1; i < depth; i++) bm->Planes[i] = bm->Planes[0] + plsize * i;

   /* Read data from disk */
   for (i = 0; i < bm->Depth; i++) {
      nb = Read(file, bm->Planes[i], plsize);
      if (nb < plsize) return((BOOL) FALSE);
   }

   return((BOOL) TRUE);
}

void alert(struct Window *win, char *msg1, char *msg2)
{
    static struct TextAttr alert_attr = { "topaz.font", 8 };
    struct TextFont *alert_font;
    struct IntuiText text1, text2, negative;
    const static struct IntuiText template = {
	0, 1, JAM1,
	8, 0,
	&alert_attr
    };
    int width, height;
    int ysize;

    alert_font = OpenFont(&alert_attr);

    ysize = alert_font ? alert_font->tf_YSize : 8;

    text1 = text2 = negative = template;
    text1.TopEdge = 8;
    text1.IText = msg1;
    width = IntuiTextLength(&text1) + 40;
    height = 37 + 2 * ysize;
    if (msg2 != NULL)
    {
	int w;

	text1.NextText = &text2;
	text2.TopEdge = text1.TopEdge + ysize;
	text2.IText = msg2;

	height += ysize;
	w = IntuiTextLength(&text2) + 20;
	if (w > width) width = w;
    }
    negative.LeftEdge = 6;
    negative.TopEdge = 4;
    negative.IText = "Ok";

    AutoRequest(win, &text1, NULL, &negative, 0L, 0L, width, height);
}

/* Amiga specific initialisation */
#define argw ((struct WBStartup *)argv)
BOOL AmigaInit(argc, argv)
int argc;
APTR argv;
{
   register LONG file;
   register BOOL loaded;
   struct BitMap hp11bitmap;
   BPTR hp11dir, old;
   char filename[PATHLEN + 8];

   if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 33))) /* Open graphics library (1.2) */
      return(FALSE);

   if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 33))) /* Open intuition library (1.2) */
      return(FALSE);

   if (!(LayersBase = (struct LayersBase *)OpenLibrary("layers.library", 0)))
      return(FALSE);

   /* Find path to command (if possible) */
   if (argc == 0) /* WB */
   {
      old = CurrentDir(argw->sm_ArgList[0].wa_Lock);
      split(argw->sm_ArgList[0].wa_Name, hp11path, &hp11name);
      hp11dir = Lock(hp11path, ACCESS_READ);
      if (!mygetpath(hp11path, hp11dir)) hp11path[0] = '\0';
      CurrentDir(old);
      UnLock(hp11dir);
   }
   else
   { /* CLI */
      split(((char **)argv)[0], hp11path, &hp11name);
   }

   /* Read the picture */
   if (!(file = Open(strcat(strcpy(filename, hp11path), "hp11.pic"), MODE_OLDFILE)))
      if (!(file = Open("hp11.pic", MODE_OLDFILE)))
      {
	 alert(NULL, "Can't find hp11.pic", NULL);
	 return(FALSE);
      }
   loaded = LoadBitMap(file, &hp11bitmap, HP11WIDTH, HP11HEIGHT, 2);
   Close(file);
   if (!loaded) return(FALSE);

   /* Open the window */
   if (!(hp11 = OpenWindow(&hp11new))) return(FALSE);

   /* Move picture into window */
   BltBitMapRastPort(&hp11bitmap, 0, 0, hp11->RPort, HP11X, HP11Y, HP11WIDTH, HP11HEIGHT, COPY);
   FreeMem(hp11bitmap.Planes[0], (long)(hp11bitmap.BytesPerRow * hp11bitmap.Rows * hp11bitmap.Depth));

   /* Create timer */
   if ((timer = CreateTimer(UNIT_MICROHZ)) == NULL) return(FALSE);

   /* Init menus */
   return(MenusInit(argc, argv));
}
#undef argw

void AmigaCleanUp()
{
   MenusCleanUp();
   if (timer) DeleteTimer(timer); /* Close timer */
   if (hp11) CloseWindow(hp11);
   if (LayersBase) CloseLibrary((struct Library *)LayersBase);
   if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase); /* Close libraries */
   if (GfxBase) CloseLibrary((struct Library *)GfxBase);
}

/* Display s */
void Display(s)
register char *s;
{
   register int posx;
   register int chr;
   register struct RastPort *rport = hp11->RPort;

   /* Clear display */
   SetDrMd(rport, JAM1); SetAPen(rport, 2);
   RectFill(rport, SCRX0 + 1, SCRY0, SCRX1 - 1, SCRY1);

   /* Initial position */
   posx = SCRX0 + CHAROFFX;

   while (*s) {
      switch (*s) { /* Position of char in char array */
	 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
	 case '7': case '8': case '9': chr = *s - '0'; break;
	 case '-': chr = 10; break;
	 case 'E': chr = 11; break;
	 case 'r': chr = 12; break;
	 case 'o': chr = 13; break;
	 case 'R': chr = 14; break;
	 case 'u': chr = 15; break;
	 case 'n': chr = 16; break;
	 case 'i': chr = 17; break;
	 case 'g': chr = 18; break;
	 case '.': chr = 19; break;
	 case ',': chr = 20; break;
	 case 'P': chr = 21; break;
	 default:  chr = -1; break;
      }
      if (chr != -1)
	 DrawBorder(rport, hp11char[chr], (long)posx, SCRY0 + CHAROFFY);

      if (*s != '.' && *s != ',') posx += CHARWIDTH;

      s++;
   }
}

/* Set image to be drawn/erased according to on */
static void SetCol(struct Image *im, int on)
{
   if (on) {
      im->PlanePick = 3;
      im->PlaneOnOff = 0;
   }
   else {
      im->PlanePick = 0;
      im->PlaneOnOff = 2;
   }
}

/* Display the indicators */
void Dispf(on)
int on;
{
   SetCol(&fImage, on);
   DrawImage(hp11->RPort, &fImage, fX, INDICY);
}

void Dispg(on)
int on;
{
   SetCol(&gImage, on);
   DrawImage(hp11->RPort, &gImage, gX, INDICY);
}

void DispUSER(on)
int on;
{
   SetCol(&USERImage, on);
   DrawImage(hp11->RPort, &USERImage, USERX, INDICY);
}

void DispG(on)
int on;
{
   SetCol(&GImage, on);
   DrawImage(hp11->RPort, &GImage, GX, INDICY);
}

void DispRAD(on)
int on;
{
   SetCol(&RADImage, on);
   DrawImage(hp11->RPort, &RADImage, RADX, INDICY);
}

void DispPRGM(on)
int on;
{
   SetCol(&PRGMImage, on);
   DrawImage(hp11->RPort, &PRGMImage, PRGMX, INDICY);
}

void beep(void)
{
   DisplayBeep(NULL);
}

static struct Window *MakeIcon(struct Image *image,
			       struct BitMap *bm, struct BitMap *tmpbm,
			       LONG x, LONG y, LONG w, LONG h)
{
   register struct Window *win;
   register ULONG size;
   static struct NewWindow new_win =
   { 0, 0, 0, 0, -1, -1, MOUSEBUTTONS | MOUSEMOVE | INACTIVEWINDOW | NOCAREREFRESH,
     SMART_REFRESH | BORDERLESS | REPORTMOUSE | RMBTRAP,
     NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN };

   new_win.LeftEdge = x; new_win.TopEdge = y;
   new_win.Width = w; new_win.Height = h;

   InitBitMap(bm, 2, w, h);
   size = bm->BytesPerRow * bm->Rows; /* size of 1 plane */
   bm->Planes[0] = (PLANEPTR)image->ImageData;
   bm->Planes[1] = (PLANEPTR)(image->ImageData) + size;

   InitBitMap(tmpbm, 2, w, h);
   if (!(tmpbm->Planes[0] = (PLANEPTR)AllocMem(2 * size, MEMF_CHIP)))
     return(NULL);
   tmpbm->Planes[1] = tmpbm->Planes[0] + size;

   if (win = OpenWindow(&new_win)) DrawImage(win->RPort, image, 0, 0);
   else FreeMem(tmpbm->Planes[0], 2 * size);

   return(win);
}

static void GetBounds(struct Window *win, LONG *mx, LONG *my,
		      LONG w, LONG h, LONG wx, LONG wy)
{
   struct Screen *scr = win->WScreen;

   *mx = scr->MouseX - wx; *my = scr->MouseY - wy;
   if (*mx + w > scr->Width) *mx = scr->Width - w;
   else if (*mx < 0) *mx = 0;
   if (*my + h > scr->Height) *my = scr->Height - h;
   else if (*my < 0) *my = 0;
}

static void SwapImage(struct BitMap *scrbm, struct BitMap *drawing,
		      struct BitMap *buf, LONG x, LONG y, LONG w, LONG h)
{
   BltBitMap(scrbm, x, y, buf, 0, 0, w, h, COPY, 0xff, NULL);
   BltBitMap(drawing, 0, 0, scrbm, x, y, w, h, COPY, 0xff, NULL);
   BltBitMap(buf, 0, 0, drawing, 0, 0, w, h, COPY, 0xff, NULL);
}

static void Iconize(struct Image *image, LONG x, LONG y)
{
   register struct Window *win;
   register struct Screen *scr;
   register struct IntuiMessage *msg;
   LONG mx, my, wx, wy;
   register LONG w, h;
   ULONG oldsecs = 0, oldmicros = 0;
   BOOL cont, moved;
   register BOOL down, wasdown;
   struct BitMap image_bm, tmpbm;

   w = image->Width; h = image->Height;
   win = MakeIcon(image, &image_bm, &tmpbm, x, y, w, h);
   if (win)
   {
      scr = win->WScreen;
      cont = TRUE;
      down = FALSE;
      do {
	 moved = FALSE; wasdown = down;
	 WaitPort(win->UserPort);
	 while (msg = (struct IntuiMessage *)GetMsg(win->UserPort))
	 {
	    switch (msg->Class)
	    {
	       case MOUSEBUTTONS:
		  if (msg->Code == SELECTUP)
		  {
		     if (DoubleClick(oldsecs, oldmicros, msg->Seconds, msg->Micros))
			cont = FALSE;
		     else {
			oldsecs = msg->Seconds;
			oldmicros = msg->Micros;
		     }
		  }
		  down = (msg->Code == SELECTDOWN);
		  break;
	       case INACTIVEWINDOW: down = FALSE; break;
	       case MOUSEMOVE: moved = TRUE; break;
	    }
	    ReplyMsg((struct Message *)msg);
	 }
	 if (!wasdown && down)
	 {
	    wx = win->MouseX; wy = win->MouseY;
	    GetBounds(win, &mx, &my, w, h, wx, wy);
	    LockLayers(&scr->LayerInfo);
	    SwapImage(&scr->BitMap, &image_bm, &tmpbm, mx, my, w, h);
	 }
	 else if (wasdown)
	    if (down)
	    {
	       if (moved)
	       {
		  SwapImage(&scr->BitMap, &image_bm, &tmpbm, mx, my, w, h);
		  GetBounds(win, &mx, &my, w, h, wx, wy);
		  SwapImage(&scr->BitMap, &image_bm, &tmpbm, mx, my, w, h);
	       }
	    }
	    else
	    {
	       SwapImage(&scr->BitMap, &image_bm, &tmpbm, mx, my, w, h);
	       UnlockLayers(&scr->LayerInfo);
	       MoveWindow(win, (long)(mx - win->LeftEdge), (long)(my - win->TopEdge));
	    }
      } while (cont || down);

      CloseWindow(win);
      FreeMem(tmpbm.Planes[0], 2 * RASSIZE(w, h));
   }
}

void sleep()
{
   struct BitMap hp11bitmap;
   struct RastPort hp11rport;
   register LONG plsize;
   register LONG x, y;

   /* Save picture in bitmap */
   InitBitMap(&hp11bitmap, 2, HP11WIDTH, HP11HEIGHT);
   plsize = hp11bitmap.BytesPerRow * hp11bitmap.Rows; /* size of 1 plane */
   /* Allocate enough memory for all planes, initialise plane pointers */
   if (!(hp11bitmap.Planes[0] = (PLANEPTR)AllocMem(plsize * 2, MEMF_CHIP)))
      Message("Not enough memory");
   else
   {
      hp11bitmap.Planes[1] = hp11bitmap.Planes[0] + plsize;
      InitRastPort(&hp11rport);
      hp11rport.BitMap = &hp11bitmap;
      ClipBlit(hp11->RPort, HP11X, HP11Y, &hp11rport, 0, 0,
	       HP11WIDTH, HP11HEIGHT, COPY);
      Forbid();
      x = hp11->LeftEdge; y = hp11->TopEdge;
      Permit();
      ClearMenuStrip(hp11);
      CloseWindow(hp11);

      Iconize(&off_image, x, y);

      /* Open the window */
      hp11new.LeftEdge = x; hp11new.TopEdge = y;
      if (!(hp11 = OpenWindow(&hp11new)))
      {
	 AutoRequest(NULL, &nomemtext, NULL, &canceltext, NULL, NULL, 250, 60);
	 quit = TRUE;
      }
      else {
	 /* Move picture into window */
	 BltBitMapRastPort(&hp11bitmap, 0, 0, hp11->RPort, HP11X, HP11Y, HP11WIDTH, HP11HEIGHT, COPY);
	 FreeMem(hp11bitmap.Planes[0], (long)(hp11bitmap.BytesPerRow * hp11bitmap.Rows * hp11bitmap.Depth));
	 SetMenuStrip(hp11, hp11menu);
	 on = TRUE;
      }
   }
}

