home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Appls / klok / klok.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-23  |  16.6 KB  |  875 lines  |  [TEXT/????]

  1. /* Analog clock with alarm.
  2.    
  3.    Displays the date at the top, a circular clock in the middle,
  4.    and the alarm time at the bottom of the window.
  5.    The clock has two hands.
  6.    
  7.    Resizing the window recomputes the items' positions and sizes.
  8.    
  9.    When the alarm goes off, the clock window is made current,
  10.    the clock face is inverted for 5 minutes, and a beep is emitted
  11.    each minute.  The alarm can be acknowledged explicitly, which
  12.    silences it until the next time the alarm goes off.
  13.    
  14.    Dragging the hands of the clock can be used to set the time
  15.    (and the date, if you care to drag around several times).
  16.    The alarm is currently set through a dialog only.
  17.  
  18.    TO DO:
  19.        - make the display prettier (how??? everything I design gets ugly :-( )
  20.     - display alarm time as tick mark?
  21.     - improve the alarm setting procedure
  22.     - add more general 'nag' and 'calendar'-like facilities
  23.     - add a button to allow/disallow setting the time
  24.     - add a way to change the date directly
  25.     - turn it into a subroutine package like VT or editwin
  26.     - organize the code top-down instead of bottom-up
  27. */
  28.  
  29. #include "tools.h"
  30. #include "stdwin.h"
  31.  
  32. #include <ctype.h>
  33. #include <math.h>
  34. #include <time.h>
  35. #include <sys/types.h>        /* For time_t, on some systems */
  36.  
  37. #ifndef PI
  38. #define PI 3.14159265359
  39. #endif
  40.  
  41. /* Alarm parametrizations */
  42.  
  43. #ifndef DEF_ALARM
  44. #define DEF_ALARM    -1    /* Initial setting of alarm */
  45. #endif
  46. #ifndef ALARMTIME
  47. #define ALARMTIME    5    /* Alarm goes for this many minutes */
  48. #endif
  49.  
  50. /* Relative hand sizes */
  51.  
  52. #define LITPERC        60    /* Little hand size (percent of radius) */
  53. #define BIGPERC        80    /* Big hand size */
  54. #define SECPERC        100    /* Seconds hand size */
  55.  
  56. /* Menu items */
  57.  
  58. #define SETALARM    0
  59. #define CLEARALARM    1
  60. #define OKALARM        2
  61. #define SECONDSHAND    4
  62. #define QUIT        6
  63.  
  64. /* Global variables */
  65.  
  66. char *progname = "klok";    /* Program name (for error messages) */
  67. char *title;            /* Menu title (default capitalized progname) */
  68. WINDOW *win;            /* Clock window */
  69. MENU *mp;            /* Menu pointer */
  70. int centh, centv;        /* Clock center */
  71. int radius;            /* Clock radius */
  72. struct tm curtime;        /* Current time/date */
  73. int alarm = DEF_ALARM;        /* Alarm time (hh*60 + mm); -1 if off */
  74. bool alarmed;            /* Is it alarm time? */
  75. bool okayed;            /* Has the current alarm been OK'ed? */
  76. bool excited;            /* == (alarmed && !okayed) */
  77. bool do_seconds;        /* Set if drawing 'seconds' hand */
  78.  
  79. /* Force a redraw of the entire window */
  80.  
  81. changeall()
  82. {
  83.     wchange(win, 0, 0, 10000, 10000);
  84. }
  85.  
  86. /* Compute the sine of an angle given in clock units
  87.    (zero at 12 o'clock, full circle is 60).
  88.    We cache the sine values in a table,
  89.    since calling sin is too slow on some systems. */
  90.  
  91. double
  92. sine(i)
  93.     int i;
  94. {
  95.     static double sines[15+1];
  96.     static bool inited;
  97.     
  98.     if (!inited) {
  99.         int k;
  100.         inited = TRUE;
  101.         for (k = 0; k <= 15; ++k)
  102.             sines[k] = sin(k * PI/30);
  103.     }
  104.     i = i % 60;
  105.     if (i < 0)
  106.         i += 60;
  107.     if (i <= 15)
  108.         return sines[i];
  109.     if (i <= 30)
  110.         return sines[30-i];
  111.     if (i <= 45)
  112.         return -sines[i-30];
  113.     return -sines[60-i];
  114. }
  115.  
  116. /* Compute the cosine (from the sine) */
  117.  
  118. double
  119. cosine(i)
  120.     int i;
  121. {
  122.     return sine(i+15);
  123. }
  124.  
  125. /* Compute the absolute position of the endpoint of a line drawn at
  126.    i minutes, whose length is a certain percentage of the radius */
  127.  
  128. void
  129. endpoint(i, perc, ph, pv)
  130.     int i;        /* Minutes */
  131.     int perc;    /* Percentage of length */
  132.     int *ph, *pv;    /* Return values */
  133. {
  134.     double s = sine(i), c = cosine(i);
  135.     
  136.     *ph = centh + s*perc*radius/100 + 0.5;
  137.     *pv = centv - c*perc*radius/100 + 0.5;
  138. }
  139.  
  140. /* Draw a mark at i minutes.
  141.    Marks at hour positions are longer, every 3 hours even longer. */
  142.  
  143. void
  144. drawmark(i)
  145.     int i;
  146. {
  147.     int begh, begv;
  148.     int endh, endv;
  149.     int len;
  150.     
  151.     endpoint(i, 100, &endh, &endv);
  152.     if (i % 5 != 0)
  153.         len = 3;
  154.     else if (i % 15 != 0)
  155.         len = 8;
  156.     else
  157.         len = 19;
  158.     endpoint(i, 100-len, &begh, &begv);
  159.     wdrawline(begh, begv, endh, endv);
  160. }
  161.  
  162. /* Draw a hand at i minutes, whose length is a given percentage
  163.    of the radius */
  164.  
  165. void
  166. drawhand(i, perc)
  167.     int i;
  168.     int perc;
  169. {
  170.     int endh, endv;
  171.     endpoint(i, perc, &endh, &endv);
  172.     wdrawline(centh, centv, endh, endv);
  173. }
  174.  
  175. /* Draw a hand in XOR mode */
  176.  
  177. void
  178. xorhand(i, perc)
  179.     int i;
  180.     int perc;
  181. {
  182.     int endh, endv;
  183.     endpoint(i, perc, &endh, &endv);
  184.     wxorline(centh, centv, endh, endv);
  185. }
  186.  
  187. /* Draw the date in the top left corner */
  188.  
  189. void
  190. drawdate(tp)
  191.     struct tm *tp;
  192. {
  193.     char buf[100];
  194.     
  195.     sprintf(buf, "%02d/%02d/%02d", tp->tm_year % 100,
  196.         tp->tm_mon+1, tp->tm_mday);
  197.     werase(0, 0, 10000, centv - radius);
  198.     wdrawtext(0, centv - radius - wlineheight(), buf, -1);
  199. }
  200.  
  201. /* Draw the alarm time in the bottom left corner */
  202.  
  203. void
  204. drawalarm()
  205. {
  206.     char buf[100];
  207.     
  208.     sprintf(buf, "*%02d:%02d", alarm/60, alarm%60);
  209.     wdrawtext(0, centv + radius, buf, -1);
  210. }
  211.  
  212. /* Compute the AM/MP/Noon/Midnight indicator character */
  213.  
  214. int
  215. ampm(tp)
  216.     struct tm *tp;
  217. {
  218.     if (tp->tm_min == 0 && tp->tm_hour%12 == 0) {
  219.         if (tp->tm_hour == 12)
  220.             return 'N';
  221.         else
  222.             return 'M';
  223.     }
  224.     else if (tp->tm_hour < 12)
  225.         return 'A';
  226.     else
  227.         return 'P';
  228. }
  229.  
  230. /* Draw the AM/PM/Noon/Midnight indicator in the top right corner */
  231.  
  232. void
  233. drawampm(c)
  234.     int c;
  235. {
  236.     int dh = wcharwidth('M');
  237.     int dv = wlineheight();
  238.     int h = centh + radius - dh;
  239.     int v = centv - radius - dv;
  240.     
  241.     werase(h, v, h+dh, v+dv);
  242.     wdrawchar(h, v, c);
  243. }
  244.  
  245. #ifdef UGLY
  246.  
  247. /* Draw a shaded square around the clock */
  248.  
  249. #define SHOFF 4
  250.  
  251. void
  252. drawborder()
  253. {
  254.     int d = radius * 10/9;
  255.     int left = centh-d, top = centv-d, right = centh+d, bottom = centv+d;
  256.     wdrawbox(left, top, right, bottom);
  257.     wshade(right, top+4, right+4, bottom+4, 50);
  258.     wshade(left+4, bottom, right, bottom+4, 50);
  259. }
  260.  
  261. /* Draw a shaded circle around the clock's face;
  262.    the shadow is on the top left side, so the face appeares to
  263.    be slightly *lower* than the surrounding material.
  264.    Also a thin vertical line to indicate 6 and 12 o'clock. */
  265.  
  266. void
  267. drawoutline()
  268. {
  269.     wdrawcircle(centh-1, centv-1, radius+2);
  270.     wdrawelarc(centh-1, centv-1, radius+1, radius+1, 45-10, 45+180+10);
  271.     wdrawelarc(centh-1, centv-1, radius  , radius  , 45+10, 45+180-10);
  272.     wdrawline(centh, centv-radius, centh, centv+radius);
  273. }
  274.  
  275. #endif /*UGLY*/
  276.  
  277. /* Compute the little hand position from hour, min */
  278.  
  279. int
  280. littlehand(hour, min)
  281.     int hour, min;
  282. {
  283.     return (hour*5 + (min+6)/12) % 60;
  284. }
  285.  
  286. /* Draw procedure */
  287.  
  288. void
  289. drawproc(win, left, top, right, bottom)
  290.     WINDOW *win;
  291. {
  292.     int i;
  293.  
  294.     /* Draw the fixed elements of the clock */
  295. #ifdef UGLY
  296.     drawborder();
  297.     drawoutline();
  298. #else
  299.     wdrawcircle(centh+1, centv+1, radius+1);
  300.     for (i = 0; i < 12; ++i)
  301.         drawmark(i*5);            /* Hour marks */
  302. #endif
  303.     
  304.     /* Draw the hands */
  305.     drawhand(curtime.tm_min, BIGPERC);
  306.     i = littlehand(curtime.tm_hour, curtime.tm_min);
  307.     if (i != curtime.tm_min)
  308.         xorhand(i, LITPERC);
  309.     if (do_seconds)
  310.         xorhand(curtime.tm_sec, SECPERC);
  311.     
  312.     /* Draw the other elements */
  313.     drawdate(&curtime);
  314.     drawampm(ampm(&curtime));
  315.     if (alarm >= 0)
  316.         drawalarm();
  317.  
  318.     /* Invert if the alarm is going */
  319.     if (excited)
  320.         winvert(0, 0, 10000, 10000);
  321. }
  322.  
  323. /* Compute the nearest clock angle corresponding to
  324.    absolute position (h, v) */
  325.  
  326. int
  327. whereis(h, v)
  328.     int h, v;
  329. {
  330.     double dnew;
  331.     
  332.     h -= centh;
  333.     v -= centv;
  334.     if (h == 0 && v == 0)
  335.         return 0;
  336.     dnew = atan2((double)h, (double)(-v)) * 30.0 / PI;
  337.     if (dnew < 0)
  338.         dnew += 60.0;
  339.     return ((int)(dnew + 0.5)) % 60;
  340. }
  341.  
  342. /* Show a change in time with minimal redrawing */
  343.  
  344. showchange(old, new)
  345.     struct tm *old, *new;
  346. {
  347.     int litold = littlehand(old->tm_hour, old->tm_min);
  348.     int litnew = littlehand(new->tm_hour, new->tm_min);
  349.     int newampm = ampm(new);
  350.     
  351.     wbegindrawing(win);
  352.     
  353.     if (do_seconds && old->tm_sec != new->tm_sec) {
  354.         xorhand(old->tm_sec, SECPERC);
  355.         xorhand(new->tm_sec, SECPERC);
  356.     }
  357.     
  358.     if (old->tm_min != new->tm_min) {
  359.         xorhand(old->tm_min, BIGPERC);
  360.         xorhand(new->tm_min, BIGPERC);
  361.     }
  362.     
  363.     if (litold != litnew ||
  364.         litold == old->tm_min || litnew == new->tm_min) {
  365.         if (litold != old->tm_min)
  366.             xorhand(litold, LITPERC);
  367.         if (litnew != new->tm_min)
  368.             xorhand(litnew, LITPERC);
  369.     }
  370.     
  371.     if (old->tm_mday != new->tm_mday)
  372.         drawdate(new);
  373.     
  374.     if (newampm != ampm(old))
  375.         drawampm(newampm);
  376.     
  377.     wenddrawing(win);
  378.  
  379. }
  380.  
  381. /* Leap year calculation.  Input is year - 1900 (but may be >= 100). */
  382.  
  383. int
  384. isleap(year)
  385.     int year;
  386. {
  387.     year += 1900;
  388.     
  389.     return year%4 == 0 && (year%100 != 0 || year%400 == 0);
  390. }
  391.  
  392. /* Increment a time variable in minutes, and show the change */
  393.  
  394. void
  395. incrshowtime(tp, incr)
  396.     struct tm *tp;
  397.     int incr;
  398. {
  399.     struct tm old;
  400.     static int mdays[12]=
  401.         {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  402.     
  403.     mdays[1] = 28 + isleap(tp->tm_year);
  404.     
  405.     old = *tp;
  406.     
  407.     tp->tm_min += incr;
  408.     
  409.     while (tp->tm_min >= 60) {
  410.         tp->tm_min -= 60;
  411.         tp->tm_hour++;
  412.         if (tp->tm_hour >= 24) {
  413.             tp->tm_hour -= 24;
  414.             tp->tm_mday++;
  415.             tp->tm_wday = (tp->tm_wday + 1) % 7;
  416.             if (tp->tm_mday > mdays[tp->tm_mon]) {
  417.                 tp->tm_mday = 1;
  418.                 tp->tm_mon++;
  419.                 if (tp->tm_mon >= 12) {
  420.                     tp->tm_mon = 0;
  421.                     tp->tm_year++;
  422.                     mdays[1] = 28 + isleap(tp->tm_year);
  423.                 }
  424.             }
  425.         }
  426.     }
  427.     
  428.     while (tp->tm_min < 0) {
  429.         tp->tm_min += 60;
  430.         tp->tm_hour--;
  431.         if (tp->tm_hour < 0) {
  432.             tp->tm_hour += 24;
  433.             tp->tm_mday--;
  434.             tp->tm_wday = (tp->tm_wday + 6) % 7;
  435.             if (tp->tm_mday < 1) {
  436.                 tp->tm_mon--;
  437.                 if (tp->tm_mon < 0) {
  438.                     tp->tm_mon = 11;
  439.                     tp->tm_year--;
  440.                     mdays[1] = 28 + isleap(tp->tm_year);
  441.                 }
  442.                 tp->tm_mday = mdays[tp->tm_mon];
  443.             }
  444.         }
  445.     }
  446.     
  447.     showchange(&old, tp);
  448. }
  449.  
  450. /* Drag the little hand */
  451.  
  452. void
  453. draglittlehand(h, v)
  454.     int h, v;
  455. {
  456.     EVENT e;
  457.     struct tm newtime;
  458.     int i;
  459.     
  460.     newtime = curtime;
  461.     wsettimer(win, 0);
  462.     
  463.     do {
  464.         wgetevent(&e);
  465.         if (e.type != WE_MOUSE_MOVE && e.type != WE_MOUSE_UP) {
  466.             showchange(&newtime, &curtime);
  467.             wungetevent(&e);
  468.             return;
  469.         }
  470.         i = whereis(e.u.where.h, e.u.where.v) / 5;
  471.         if ((i - newtime.tm_hour) % 12 != 0) {
  472.             int diff = i - newtime.tm_hour;
  473.             while (diff > 6)
  474.                 diff -= 12;
  475.             while (diff < -6)
  476.                 diff += 12;
  477.             incrshowtime(&newtime, diff*60);
  478.         }
  479.     } while (e.type != WE_MOUSE_UP);
  480.     setdatetime(&newtime, FALSE);
  481.     curtime = newtime;
  482. }
  483.  
  484. /* Drag the big hand */
  485.  
  486. void
  487. dragbighand(h, v)
  488.     int h, v;
  489. {
  490.     EVENT e;
  491.     struct tm newtime;
  492.     int i;
  493.     
  494.     newtime = curtime;
  495.     wsettimer(win, 0);
  496.     
  497.     do {
  498.         wgetevent(&e);
  499.         if (e.type != WE_MOUSE_MOVE && e.type != WE_MOUSE_UP) {
  500.             showchange(&newtime, &curtime);
  501.             wungetevent(&e);
  502.             return;
  503.         }
  504.         i = whereis(e.u.where.h, e.u.where.v);
  505.         if (i != newtime.tm_min) {
  506.             int diff = i - newtime.tm_min;
  507.             if (diff > 30)
  508.                 diff -= 60;
  509.             else if (diff < -30)
  510.                 diff += 60;
  511.             incrshowtime(&newtime, diff);
  512.         }
  513.     } while (e.type != WE_MOUSE_UP);
  514.     setdatetime(&newtime, TRUE);
  515.     curtime = newtime;
  516. }
  517.  
  518. /* Test whether the given position lies on the hand at the
  519.    given clock angle with the given length percentage */
  520.  
  521. bool
  522. testhand(h, v, pos, perc)
  523.     int h, v;
  524.     int pos;
  525.     int perc;
  526. {
  527.     long dist2 = (h-centh)*(h-centh)+ (v-centv)*(v-centv);
  528.     long length2 = ((long)radius*perc/100) * ((long)radius*perc/100);
  529.     
  530.     if (dist2 > length2)
  531.         return FALSE;
  532.     if ((whereis(h, v) - pos) % 60 != 0)
  533.         return FALSE;
  534.     return TRUE;
  535. }
  536.  
  537. /* Recompute the time and the alarm parameters.
  538.    Called every minute, and when other parameters may have changed. */
  539.  
  540. void
  541. newtime(flash)
  542.     bool flash;
  543. {
  544.     struct tm oldtime;
  545.     time_t now;
  546.     bool wasalarmed;
  547.     
  548.     /* Save the old time displayed */
  549.     oldtime = curtime;
  550.     
  551.     /* Get the current time */
  552.     time(&now);
  553.     curtime = *localtime(&now);
  554.     
  555.     /* Set the window timer to go off at the next tick */
  556.     if (do_seconds) {
  557.         wsettimer(win, 10);
  558.     }
  559.     else {
  560.         if (curtime.tm_sec >= 59) {
  561.             /* When we wake up just at the end of the minute,
  562.                (which may happen if STDWIN isn't very precise),
  563.                pretend it's a bit later, to avoid waking up
  564.                again in a second */
  565.             curtime.tm_sec -= 60;
  566.             curtime.tm_min += 1;
  567.         }
  568.         wsettimer(win, 10 * (60 - curtime.tm_sec));
  569.     }
  570.     
  571.     /* Check whether the alarm should go off */
  572.     wasalarmed = alarmed;
  573.     if (!wasalarmed)
  574.         okayed = FALSE;
  575.     if (alarm >= 0) {
  576.         int a = alarm;
  577.         int hhmm = curtime.tm_hour*60 + curtime.tm_min;
  578.         if (hhmm < 60 && a >= 23*60)
  579.             hhmm += 24*60; /* Correct for wrap-around */
  580.         alarmed = hhmm >= a && hhmm < a+ALARMTIME;
  581.     }
  582.     else {
  583.         alarmed = okayed = FALSE;
  584.     }
  585.     excited = alarmed && !okayed;
  586.     if (excited) {
  587.         if (!wasalarmed)
  588.             wsetactive(win);
  589.         wfleep();
  590.     }
  591.     if (excited || wasalarmed && !okayed)
  592.         flash = TRUE;
  593.     wmenuenable(mp, OKALARM, excited);
  594.     
  595.     /* Redraw the clock face or schedule a redraw */
  596.     if (flash) {
  597.         changeall();
  598.     }
  599.     else {
  600.         showchange(&oldtime, &curtime);
  601.     }
  602. }
  603.  
  604. /* Time-setting procedure by dragging the hands around */
  605.  
  606. void
  607. changehand(h, v)
  608.     int h, v;
  609. {
  610.     /* Test the little hand first, so that if the hands
  611.        overlap, a click near the center implies the little
  612.        hand and a click further away implies the big hand */
  613.     if (testhand(h, v,
  614.         littlehand(curtime.tm_hour, curtime.tm_min), LITPERC)) {
  615.         /* Drag the little hand -- minutes stay unchanged */
  616.         draglittlehand(h, v);
  617.     }
  618.     else if (testhand(h, v, curtime.tm_min, BIGPERC)) {
  619.         /* Drag the big hand -- hours may change, too */
  620.         dragbighand(h, v);
  621.     }
  622.     else {
  623.         /* No hit -- make some noise */
  624.         wfleep();
  625.     }
  626.     newtime(FALSE);
  627. }
  628.  
  629. /* Recompute the clock size and position
  630.    and the time/alarm information.
  631.    Called initially and when the window is resized. */
  632.  
  633. void
  634. getallinfo()
  635. {
  636.     int width, height;
  637.     
  638.     wgetwinsize(win, &width, &height);
  639.     centh = width/2;
  640.     centv = height/2;
  641.     radius = centv - wlineheight();
  642.     CLIPMAX(radius, centh-2);
  643.     newtime(TRUE);
  644. }
  645.  
  646. /* Set the alarm time from a string formatted as hhmm */
  647.  
  648. bool
  649. setalarm(str)
  650.     char *str;
  651. {
  652.     int al;
  653.     
  654.     if (str[0] == EOS || str[0] == '-' && str[1] == EOS) {
  655.         alarm = -1;
  656.         wmenuenable(mp, CLEARALARM, FALSE);
  657.         return TRUE;
  658.     }
  659.     al = atoi(str);
  660.     if (al < 0 || al > 2400 || al%60 >= 60)
  661.         return FALSE;
  662.     if (al == 2400)
  663.         al = 0;
  664.     alarm = (al/100)*60 + al%100;
  665.     wmenuenable(mp, CLEARALARM, TRUE);
  666.     return TRUE;
  667. }
  668.  
  669. /* Set up the menu */
  670.  
  671. void
  672. buildmenu()
  673. {
  674.     wmenusetdeflocal(TRUE);
  675.     mp = wmenucreate(1, "Klok");
  676.     
  677.     wmenuadditem(mp, "Set alarm...", 'S');
  678.     wmenuadditem(mp, "Clear alarm", 'C');
  679.     wmenuadditem(mp, "OK alarm", 'O');
  680.     wmenuadditem(mp, "", -1);
  681.     wmenuadditem(mp, "Seconds Hand", 'H');
  682.     wmenuadditem(mp, "", -1);
  683.     wmenuadditem(mp, "Quit", 'Q');
  684.     
  685.     wmenuenable(mp, CLEARALARM, alarm >= 0);
  686.     wmenucheck(mp, SECONDSHAND, do_seconds);
  687. }
  688.  
  689. /* Handle a menu selection */
  690.  
  691. void
  692. domenu(item)
  693.     int item;
  694. {
  695.     bool flash = FALSE;
  696.     
  697.     switch (item) {
  698.     case SETALARM: {
  699.         char buf[6];
  700.         if (alarm < 0)
  701.             buf[0] = EOS;
  702.         else
  703.             sprintf(buf, "%02d%02d", alarm/60, alarm%60);
  704.         if (!waskstr("Set alarm:", buf, sizeof buf))
  705.             return;
  706.         if (!setalarm(buf))
  707.             wmessage("Invalid alarm (must be hhmm)");
  708.         okayed = FALSE;
  709.         flash = TRUE;
  710.         break;
  711.         }
  712.     case CLEARALARM:
  713.         if (alarm >= 0) {
  714.             setalarm("");
  715.             flash = TRUE;
  716.         }
  717.         break;
  718.     case OKALARM:
  719.         if (excited) {
  720.             flash = okayed = TRUE;
  721.         }
  722.         break;
  723.     case SECONDSHAND:
  724.         do_seconds = !do_seconds;
  725.         wmenucheck(mp, SECONDSHAND, do_seconds);
  726.         wbegindrawing(win);
  727.         xorhand(curtime.tm_sec, SECPERC);
  728.         wenddrawing(win);
  729.         break;
  730.     case QUIT:
  731.         wclose(win);
  732.         wdone();
  733.         exit(0);
  734.         break;
  735.     }
  736.     newtime(flash);
  737. }
  738.  
  739. #ifndef macintosh
  740. /* Print usage message and exit; called for command line errors */
  741.  
  742. void
  743. usage()
  744. {
  745.     wdone();
  746.     fprintf(stderr,
  747.         "usage: %s [-s] [-m] [-a hhmm] [-t title]\n", progname);
  748.     exit(2);
  749. }
  750. #endif
  751.  
  752. /* Main program */
  753.  
  754. main(argc, argv)
  755.     int argc;
  756.     char **argv;
  757. {
  758.     /* Initialize */
  759.     winitargs(&argc, &argv);
  760.     wsetdefscrollbars(0, 0);
  761.     buildmenu(); /* Must be done before setalarm is called */
  762.     
  763.     /* Find out program name */
  764.     if (argc > 0) {
  765.         progname = strrchr(argv[0], '/');
  766.         if (progname == NULL)
  767.             progname = argv[0];
  768.         else
  769.             ++progname;
  770.     }
  771.     
  772. #ifndef macintosh
  773.     /* Parse command line */
  774.     for (;;) {
  775.         int c = getopt(argc, argv, "msa:t:");
  776.         if (c == EOF)
  777.             break;
  778.         switch (c) {
  779.         case 's':
  780.             do_seconds = TRUE;
  781.             break;
  782.         case 'm':
  783.             do_seconds = FALSE;
  784.             break;
  785.         case 'a':
  786.             if (!setalarm(optarg))
  787.                 usage();
  788.             break;
  789.         case 't':
  790.             title = optarg;
  791.             break;
  792.         default:
  793.             usage();
  794.             /*NOTREACHED*/
  795.         }
  796.     }
  797.     wmenucheck(mp, SECONDSHAND, do_seconds);
  798. #endif
  799.     
  800.     /* Create the window */
  801.     wsetdefwinsize(120, 120);
  802.     win = wopen(title == NULL ? progname : title, drawproc);
  803.     wmenuattach(win, mp);
  804.     
  805.     /* Main loop */
  806.     getallinfo();
  807.     for (;;) {
  808.         EVENT e;
  809.         wgetevent(&e);
  810.         
  811.         switch (e.type) {
  812.         
  813.         case WE_MOUSE_DOWN:
  814.             if (excited)
  815.                 domenu(OKALARM);
  816.             else
  817.                 changehand(e.u.where.h, e.u.where.v);
  818.             break;
  819.         
  820.         case WE_MENU:
  821.             if (e.u.m.id == 1)
  822.                 domenu(e.u.m.item);
  823.             break;
  824.         
  825.         case WE_CHAR:
  826.             if (excited)
  827.                 break;
  828.             switch (e.u.character) {
  829.             case 's':
  830.             case 'S':
  831.                 domenu(SETALARM);
  832.                 break;
  833.             case 'c':
  834.             case 'C':
  835.                 domenu(CLEARALARM);
  836.                 break;
  837.             case 'h':
  838.             case 'H':
  839.                 domenu(SECONDSHAND);
  840.                 break;
  841.             case 'q':
  842.             case 'Q':
  843.                 domenu(QUIT);
  844.                 break;
  845.             }
  846.             break;
  847.         
  848.         case WE_COMMAND:
  849.             switch (e.u.command) {
  850.             case WC_RETURN:
  851.                 newtime(FALSE);
  852.                 break;
  853.             case WC_CLOSE:
  854.             case WC_CANCEL:
  855.                 domenu(QUIT);
  856.                 break;
  857.             }
  858.             break;
  859.  
  860.         case WE_CLOSE:
  861.             domenu(QUIT);
  862.             break;
  863.         
  864.         case WE_SIZE:
  865.             getallinfo();
  866.             break;
  867.         
  868.         case WE_TIMER:
  869.             newtime(FALSE);
  870.             break;
  871.         
  872.         }
  873.     }
  874. }
  875.