From: rokicki@polya.STANFORD.EDU (Tomas G. Rokicki)
Newsgroups: comp.sys.amiga
Subject: Re: Dmouse "feature"
Message-ID: <2852@polya.STANFORD.EDU>
Date: 19 May 88 02:49:59 GMT
Organization: Stanford University
Reply-To: rokicki@polya.Stanford.EDU (Tomas G. Rokicki)
References: <EWYTMzy00VAAA-Xlpy@andrew.cmu.edu>
Lines: 351
 
> If you use interlace, the ledclock by Ali Ozer is really cool.
 
I've hacked it ever so slightly to make it work on non-interlace.
It's so short, that here it is!  (Manx only.)
 
/* LedClock (C)1987 Ali T. Ozer. A clock program for interlaced screens. */
 
#include <exec/types.h>
#include <functions.h>
#include <intuition/intuition.h>
#include <exec/devices.h>
#include <devices/timer.h>
#include <graphics/gfxmacros.h>
 
/* LedClock is freely distributable and NOT for sale.
**
** Author: Ali T. Ozer, ARPA: ali@score.stanford.edu,
**                      REAL: Box 7703, Stanford, CA 94309
**
** A clock program for interlaced screens. This one uses
** numbers that resemble the numbers used in 7-segment LED and LCD
** clock displays. Various options are provided as compile time "#define"s:
**
** TWENTYFOURHOUR  0 or 1, determines if the clock is 24-hour or not
** WINDOWXLOC      starting X location for the window in the WB screen
** WINDOWYLOC      starting Y location for the window in the WB screen
** FANCYPANIC      0 or 1, determines if a error message box is shown in
**                 case the clock can't run...
**
** LedClock works best with interlaced screens --- It will look ugly on a
** "normal" WorkBench screen. (It will probably look fine on a lo-res, non
** interlaced screen, except it will be too big, way too big.)
**
** LedClock can be compiled by Manx 3.40a. Use the "+c" and "+d" switches
** while linking to assure that the static images go into CHIP ram:
**
**   cc ledclock.c
**   ln +cd ledclock.o -lc
**   run ledclock
**
** During linking you'll get warnings about _cli_parse and _wb_parse being
** redefined; you can safely ignore these messages.
**
** Various corners have been cut from this program to make the executable small.
** With Manx 3.40a, the executable is somewhere around 3.1 Kbytes. One can
** probably achieve half that size in assembly.
**
** Programmers might wish to fool around with the code to customize the
** clock. It's amazing how many parameters one can think of if one tries
** to make a general program... So, rather than trying to provide zillions
** of command line arguments, I took the easy way out and just threw out
** all generality... If you wish to create your customized clocks from
** this code, feel free to do so --- but please keep my original copyright
** notice (in the screen title bar) intact, along with any additional
** copyright notices you might add.
*/
 
/* The next few define's can be changed for different runtime parameters... */
 
#define TWENTYFOURHOUR 1
#define FANCYPANIC     0
#define WINDOWXLOC     450
#define WINDOWYLOC     0
 
#define COPYRIGHT "LedClock 1.0 (C)1987 Ali T. Ozer"
 
#if FANCYPANIC
#define Panic(arg)  WarnUser(arg)
#else
#define Panic(arg)  CloseThings(1)
#endif
 
#define DIGITMAXX 18
#define DIGITMAXY 16
 
#define WINDOWX 0
#define WINDOWY 9
#define DIGIT1X (WINDOWX + 3)
#define DIGIT2X (DIGIT1X + DIGITMAXX + 3)
#define DIGIT3X (DIGIT2X + DIGITMAXX + 10)
#define DIGIT4X (DIGIT3X + DIGITMAXX + 3)
#define DIGITY  (WINDOWY + 3)
#define WINDOWWIDTH  (DIGIT4X + DIGITMAXX + 3)
#define WINDOWHEIGHT (DIGITY + DIGITMAXY + 3)
#define COLONX  (DIGIT3X - 6)
#define COLONY  (DIGITY  + 5)
 
/* The "leds" (the segments making up the digits) are named in the standard
** (clockwise) fashion, with a = top led, b = right top, ... f = left top, and
** g = middle.
**
** The following describes the vertical leds ("b", "c", "e", and "f")
*/
USHORT vled [] = {
 0xdfff, 0x8fff, 0x8fff, 0x8fff, 0x1fff, 0x1fff, 0x1fff };
 
/* The following is the bitmap description of leds a and d.
*/
USHORT hled [] = {0x807f, 0x807f};
 
/* The following is the bitmap description of the middle ("g") led.
*/
USHORT mled [] = {0x80ff, 0x80ff};
 
/* The following describes the bitmap for the colon and the image.
*/
USHORT colondata [] = {
0x8fff, 0x8fff, 0xffff, 0xffff, 0x1fff, 0x1fff };
 
struct Image colon = { 0,  0,  4, 6, 1, colondata, 1, 0, NULL};
 
/* The following describes the Image structures for all 7 leds, "a".."g"
*/
struct Image leds [] = {
{ 6,  0, 10,  2, 1, &hled[0], 1, 0, NULL},
{15,  1,  4,  7, 1, &vled[0], 1, 0, NULL},
{13,  8,  4,  7, 1, &vled[0], 1, 0, NULL},
{ 3, 15, 10,  2, 1, &hled[0], 1, 0, NULL},
{ 0,  8,  4,  7, 1, &vled[0], 1, 0, NULL},
{ 2,  1,  4,  7, 1, &vled[0], 1, 0, NULL},
{ 5,  7,  9,  2, 1, &mled[0], 1, 0, NULL}
};
 
/* In the following each byte determines what leds are lit for the
** corresponding digit. The bits are ordered "xgfedcba" and a 1 means the
** led is lit.
*/
UBYTE lled [] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
 
struct Window      *MyWin;
struct RastPort    *MyRP;
struct Library     *IntuitionBase;
struct Library     *GfxBase;
struct timerequest  MyTR;
unsigned long      WindowSig, TimerSig;
int                curminutes;
 
/* Draw digit puts a 7-segment digit at the specified location. If digit is
** negative, then the area is erased but nothing is drawn.
*/
DrawDigit (rp, digit, xloc, yloc)
struct RastPort *rp;
int digit, xloc, yloc;
{
  register int ledmask, ledcnt = 0;
 
  /* First erase it */
  RectFill (rp, (long)xloc, (long)yloc,
                (long)(xloc + DIGITMAXX), (long)(yloc + DIGITMAXY));
 
  if (digit >= 0) {
    ledmask = lled[digit];
    while (ledcnt != 7) {
      if (ledmask & 1) DrawImage (rp, &leds[ledcnt], (long)xloc, (long)yloc);
      ledcnt++; ledmask >>= 1;
    }
  }
}
 
/* OpenTimer will open the timer device and also do all the initialization
** necessary to send timer requests...
*/
OpenTimer (tr)
struct timerequest *tr;
{
  struct MsgPort *timerport;
 
  while ((timerport = CreatePort (NULL, 0L)) == NULL) Panic ("No port");
 
  OpenDevice (TIMERNAME, UNIT_VBLANK, tr, 0L);
  tr->tr_node.io_Message.mn_ReplyPort = timerport;
  tr->tr_node.io_Command = TR_ADDREQUEST;
 
}
 
/* OpenThings opens the Amiga libraries, the window. and the timer.
** If something goes wrong, a requester will pop up to warn the user.
** (If FANCYPANIC is defined as zero, then no requester pops up --- the
** program just quits.)
*/
OpenThings ()
{
  static struct NewWindow MyWinInfo =
  { WINDOWXLOC, WINDOWYLOC, WINDOWWIDTH, WINDOWHEIGHT, /* Lft,Top,Wd,Hgt */
    -1,-1,                   /* Detail pen, Block pen (-1 = use screens) */
    CLOSEWINDOW,                                           /* IDCMPflags */
    SMART_REFRESH | WINDOWDEPTH | WINDOWDRAG | WINDOWCLOSE | NOCAREREFRESH,
    NULL, NULL, NULL,              /* FirstGadget, Menu Checkmark, Title */
    NULL, NULL,                                        /* Screen, Bitmap */
    0, 0, 0, 0,                     /* Min Width/Height Max Width/Height */
    WBENCHSCREEN                                                 /* Type */
  };
 
  if (((IntuitionBase = OpenLibrary("intuition.library",0L)) == NULL) ||
      ((GfxBase = OpenLibrary("graphics.library",0L)) == NULL)) CloseThings (1);
 
  while (!(MyWin = OpenWindow(&MyWinInfo))) Panic ("No window");
  SetWindowTitles (MyWin, NULL, COPYRIGHT);
 
  MyRP = MyWin->RPort;
  WindowSig = 1L << MyWin->UserPort->mp_SigBit;
 
  SetOPen (MyRP, 1L);
  SetAPen (MyRP, 1L);
 
  OpenTimer(&MyTR);
  TimerSig = 1L << MyTR.tr_node.io_Message.mn_ReplyPort->mp_SigBit;
}
 
/* SendTimerRequest sends a timer request for the indicated amount of seconds.
** Assumes the timer request block pointed to by tr has already been properly
** setup --- including the io_Command field.
*/
SendTimerRequest (tr, seconds)
struct timerequest *tr;
unsigned long seconds;
{
  tr->tr_time.tv_micro = 0L;
  tr->tr_time.tv_secs  = seconds;
  SendIO (tr);
}
 
#if FANCYPANIC
 
/* WarnUser is called when something goes wrong during initialization.
** WarnUser assumes Intuition is opened! (Now if that's not the case,
** then you're in trouble...)
*/
 
WarnUser (reason)
UBYTE *reason;
{
  static struct IntuiText postxt  =
                          {3,1,COMPLEMENT,4,4,NULL,(UBYTE*)"Retry",NULL};
  static struct IntuiText negtxt  =
                          {3,1,COMPLEMENT,4,4,NULL,(UBYTE*)"Sigh",NULL};
  static struct IntuiText bodytxt = {3,1,COMPLEMENT,4,6,NULL,NULL,NULL};
 
  bodytxt.IText = reason;
  if (AutoRequest (NULL,&bodytxt,&postxt,&negtxt,0L,0L,300L,60L) == FALSE)
     CloseThings (1);
}
 
#endif
 
/* CloseTimer closes the timer pointed to by tr. If no reply port is present,
** then CloseTimer assumes the timer was never opened.
*/
CloseTimer (tr)
struct timerequest *tr;
{
  struct MsgPort *msgp;
  if (msgp = tr->tr_node.io_Message.mn_ReplyPort) {
    DeletePort (msgp);
    CloseDevice (tr);
  }
}
 
/* CloseThings releases all the resources obtained by the program.
*/
CloseThings(error_code)
int error_code;
{
  CloseTimer(&MyTR);
  if (MyWin)         CloseWindow(MyWin);
  if (GfxBase)       CloseLibrary(GfxBase);
  if (IntuitionBase) CloseLibrary(IntuitionBase);
  exit (error_code);
}
 
static int ht = -1, ho = -1, mt = -1, mo = -1;
 
/* WriteTime writes out the new time.
*/
WriteTime (minutes)
int minutes;
{
  int hours, htens, hones, mtens, mones;
 
#if TWENTYFOURHOUR
  hours = minutes / 60;
#else
  hours = (minutes / 60 + 11) % 12 + 1;
#endif
 
  /* AM if minutes < 720, but we don't worry about this... */
 
  if ((htens = hours / 10) != ht)
    DrawDigit (MyRP, ((ht = htens) ? ht : -1), DIGIT1X, DIGITY);
  if ((hones = hours % 10) != ho)
    DrawDigit (MyRP, ho = hones, DIGIT2X, DIGITY);
  if ((mtens = (minutes % 60) / 10) != mt)
    DrawDigit (MyRP, mt = mtens, DIGIT3X, DIGITY);
  if ((mones = (minutes % 10)) != mo)
    DrawDigit (MyRP, mo = mones, DIGIT4X, DIGITY);
}
 
/* ShowTheTime reads the time, updates the display, and sends a new timer
** request.
*/
ShowTheTime ()
{
  long timevec[3];
 
  DateStamp (&timevec[0]);
  curminutes = (int)(timevec[1]);
  WriteTime (curminutes);
  /* Timer request for the next top of minute */
  SendTimerRequest (&MyTR, 60L - (long)(timevec[2] / 50L));
}
 
main ()
{
  struct Task *me;
 
  OpenThings  ();
 
  /* Bump the priority up to 5. Not too serious, as under normal conditions
  ** this program will wake up only every 60 seconds.
  */
  if (me = FindTask (NULL)) SetTaskPri (me, 5L);
 
  /* Clear the window and draw in the ":".
  */
  RectFill  (MyRP, (long)WINDOWX, (long)WINDOWY,
                    WINDOWWIDTH-1L, WINDOWHEIGHT-1L);
  DrawImage (MyRP, &colon, (long)COLONX, (long)COLONY);
 
  /* Now sit down, relax, and wait for either an IDCMP or a timer event...
  */
  while (1) {
    ShowTheTime ();
    if (Wait (WindowSig | TimerSig) & TimerSig)
       (void) GetMsg (MyTR.tr_node.io_Message.mn_ReplyPort);
    else {
       AbortIO(&MyTR); /* Don't even get the message, assume it's CLOSEWINDOW */
       CloseThings (0);
    }
  }
}
 
 
 
/* Including the following two lines prevents the linker from bringing in
** the two functions _wb_parse and _cli_parse called by the initialization
** code in _main. Reduces code size by about 900 bytes for Manx 3.40a.
*/
void _wb_parse () {}
void _cli_parse () {}
