
/************************************************************************
 *									*
 * Clock v1.4								*
 *									*
 *   © Stuart Mitchell - November 1990					*
 *									*
 *   A simple clock with optional pop-to-front & memory display 	*
 *									*
 * NB: 1) Should be linked with cback.o instead of c.o to provide a LSR *
 *    program which then allows original CLI to be closed.		*
 *     2) To enable pop-to-front compile with -dPOPUP option		*
 *     3) To enable memory display compile with -dMEMCLOCK option	*
 *									*
 * v1.0 - Initial release						*
 * v1.1 - fixed timing bug (minclock woken up 4 times too often!!)      *
 * v1.2 - Added code to call RawDoFmt					*
 * v1.3 - Fixed memory loss bug (call _exit instead of Exit)            *
 * v1.4 - Altered to use ARP's resource tracking,cached libraries...    *
 *									*
 ************************************************************************/

#include <stdio.h>
#include <exec/types.h>
#include <exec/exec.h>
#include <devices/timer.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/arpbase.h>
#include <proto/arp.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/exec.h>

void do_exit(int);

#ifdef MEMCLOCK
#define PROGNAME "Memclock v1.4"
#else
#define PROGNAME "MinClock v1.4"
#endif

long _stack=2000;			/* Definitions for cback.o */
char *_procname=PROGNAME;
long _priority=0;
long _BackGroundIO=0;

static struct IntuitionBase    *IntuitionBase;
static struct GfxBase	       *GfxBase;
struct ArpBase		       *ArpBase;
static struct Window	       *Window;
static struct timerequest      Time_Req;
static struct MsgPort	       *Timer_Port;
static struct DateStamp        Date;
static struct IntuiMessage     *Msg;

char date[LEN_DATSTRING],time[LEN_DATSTRING],day[LEN_DATSTRING];
static struct DateTime datetime={ {0},FORMAT_CDN,0,NULL,date,time };

#ifdef MEMCLOCK
#define BUFSIZE         32
#define WIDTH           250
#define XPOS            337
#else
#define BUFSIZE         18
#define WIDTH           140
#define XPOS            447
#endif

static BYTE Buffer[26];		/* holds time string */

static struct NewWindow nw={
  XPOS,0,WIDTH,10,2,1,CLOSEWINDOW,SMART_REFRESH|WINDOWCLOSE|WINDOWDRAG,
  NULL,NULL,(UBYTE *)PROGNAME,NULL,NULL,0,0,0,0,WBENCHSCREEN };

static struct IntuiText Date_Text={
  2,1,JAM2,0,0,NULL,Buffer,NULL };

void _main()
{
#ifdef POPUP
  long lock;
#endif
  if(!(ArpBase=(struct ArpBase *)OpenLibrary("arp.library",39)))
    do_exit(1);

  IntuitionBase=(struct IntuitionBase *)ArpBase->IntuiBase;
  GfxBase=(struct GfxBase *)ArpBase->GfxBase;

  if(Getenv("dateformat",Buffer,5)==NULL)
    datetime.dat_Format=FORMAT_DOS;
  else
    datetime.dat_Format=Atol(Buffer);

  if(datetime.dat_Format==FORMAT_DOS) {
    nw.LeftEdge-=8;
    nw.Width+=8;
  };

  if((Timer_Port=CreatePort("Timer Port",0))==NULL)
    do_exit(1);

  if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)&Time_Req,0)!=NULL)
    do_exit(1) ;

  Time_Req.tr_node.io_Message.mn_ReplyPort=Timer_Port;
  Time_Req.tr_node.io_Command=TR_ADDREQUEST;
  Time_Req.tr_node.io_Flags=0;
  Time_Req.tr_node.io_Error=0;

  if((Window=OpenWindow((struct NewWindow *)&nw))==NULL)
    do_exit(20);

  SetRast(Window->RPort,1);

  for(;;) {

/* calculate time from system clock */

    DateStamp((struct DateStamp *)&datetime.dat_Stamp);
    StamptoStr(&datetime);

#ifdef MEMCLOCK
    SPrintf(Buffer,"C:%04ld F:%04ld %s %s",AvailMem(MEMF_CHIP)>>10,
		    AvailMem(MEMF_FAST)>>10,date,time);
#else
    SPrintf(Buffer,"%s %s",date,time);
#endif

    PrintIText(Window->RPort,&Date_Text,2,1);   /* put into window */

/* NB : Window only 'pops to front' if Workbench screen is also at the
  front, otherwise Dpaint (& others?) get very upset */

#ifdef POPUP
    lock=LockIBase(0);
    if(IntuitionBase->FirstScreen==Window->WScreen)
      WindowToFront(Window);
    UnlockIBase(lock);
#endif

/* set up next wakeup time */

    Time_Req.tr_time.tv_secs=1;
    Time_Req.tr_time.tv_micro=0;
    SendIO(&Time_Req.tr_node);

/* sleep until woken either by Close Gadget selection or timer event */

    Wait(1<<Window->UserPort->mp_SigBit | 1<<Timer_Port->mp_SigBit);

    while((Msg=(struct IntuiMessage *)GetMsg(Window->UserPort))!=NULL) {
      if(Msg->Class==CLOSEWINDOW) {
	ReplyMsg((struct Message *)Msg);
	do_exit(0);
      }
      ReplyMsg((struct Message *)Msg);
    }
    GetMsg(Timer_Port);         /* must be timer wakeup ... */
  }
}

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

void do_exit(code)
int code;
{
  AbortIO(&Time_Req.tr_node);
  if(Window)
    CloseWindow(Window);
  if(Time_Req.tr_node.io_Message.mn_ReplyPort)
    CloseDevice((struct IORequest *)&Time_Req);
  if(Timer_Port)
    DeletePort((struct MsgPort *)Timer_Port);
  if(ArpBase)
    CloseLibrary((struct Library *)ArpBase);
  _exit(code);
}

void MemCleanup() {}

