home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / Clock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-22  |  24.8 KB  |  838 lines

  1. /* $XConsortium: Clock.c,v 1.65 91/08/14 12:12:56 rws Exp $ */
  2.  
  3. /***********************************************************
  4. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  5. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  6.  
  7.                         All Rights Reserved
  8.  
  9. Permission to use, copy, modify, and distribute this software and its 
  10. documentation for any purpose and without fee is hereby granted, 
  11. provided that the above copyright notice appear in all copies and that
  12. both that copyright notice and this permission notice appear in 
  13. supporting documentation, and that the names of Digital or MIT not be
  14. used in advertising or publicity pertaining to distribution of the
  15. software without specific, written prior permission.  
  16.  
  17. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  18. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  19. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  20. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  22. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  23. SOFTWARE.
  24.  
  25. ******************************************************************/
  26.  
  27. #include <X11/Xlib.h>
  28. #include <X11/StringDefs.h>
  29. #include <X11/IntrinsicP.h>
  30. #include <X11/Xaw/XawInit.h>
  31. #include <X11/Xaw/ClockP.h>
  32. #include <X11/Xosdefs.h>
  33.  
  34. #if __STDC__
  35. #define Const const
  36. #else
  37. #define Const /**/
  38. #endif
  39.  
  40. #ifdef X_NOT_STDC_ENV
  41. extern struct tm *localtime();
  42. #endif
  43.  
  44. static void clock_tic(), DrawHand(), DrawSecond(), SetSeg(), DrawClockFace();
  45. static erase_hands(), round();
  46.     
  47. /* Private Definitions */
  48.  
  49. #define VERTICES_IN_HANDS    6    /* to draw triangle */
  50. #define PI            3.14159265358979
  51. #define TWOPI            (2. * PI)
  52.  
  53. #define SECOND_HAND_FRACT    90
  54. #define MINUTE_HAND_FRACT    70
  55. #define HOUR_HAND_FRACT        40
  56. #define HAND_WIDTH_FRACT    7
  57. #define SECOND_WIDTH_FRACT    5
  58. #define SECOND_HAND_TIME    30
  59.  
  60. #define ANALOG_SIZE_DEFAULT    164
  61.  
  62. #define max(a, b) ((a) > (b) ? (a) : (b))
  63. #define min(a, b) ((a) < (b) ? (a) : (b))
  64. #define abs(a) ((a) < 0 ? -(a) : (a))
  65.  
  66.  
  67. /* Initialization of defaults */
  68.  
  69. #define offset(field) XtOffsetOf(ClockRec, clock.field)
  70. #define goffset(field) XtOffsetOf(WidgetRec, core.field)
  71.  
  72. static XtResource resources[] = {
  73.     {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  74.     goffset(width), XtRImmediate, (XtPointer) 0},
  75.     {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  76.     goffset(height), XtRImmediate, (XtPointer) 0},
  77.     {XtNupdate, XtCInterval, XtRInt, sizeof(int), 
  78.         offset(update), XtRImmediate, (XtPointer) 60 },
  79.     {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  80.         offset(fgpixel), XtRString, XtDefaultForeground},
  81.     {XtNhand, XtCForeground, XtRPixel, sizeof(Pixel),
  82.         offset(Hdpixel), XtRString, XtDefaultForeground},
  83.     {XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel),
  84.         offset(Hipixel), XtRString, XtDefaultForeground},
  85.     {XtNanalog, XtCBoolean, XtRBoolean, sizeof(Boolean),
  86.         offset(analog), XtRImmediate, (XtPointer) TRUE},
  87.     {XtNchime, XtCBoolean, XtRBoolean, sizeof(Boolean),
  88.     offset(chime), XtRImmediate, (XtPointer) FALSE },
  89.     {XtNpadding, XtCMargin, XtRInt, sizeof(int),
  90.         offset(padding), XtRImmediate, (XtPointer) 8},
  91.     {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
  92.         offset(font), XtRString, XtDefaultFont},
  93.     {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
  94.         offset (backing_store), XtRString, "default"},
  95. };
  96.  
  97. #undef offset
  98. #undef goffset
  99.  
  100. static void ClassInitialize();
  101. static void Initialize(), Realize(), Destroy(), Resize(), Redisplay();
  102. static Boolean SetValues();
  103.  
  104. ClockClassRec clockClassRec = {
  105.     { /* core fields */
  106.     /* superclass        */    (WidgetClass) &simpleClassRec,
  107.     /* class_name        */    "Clock",
  108.     /* widget_size        */    sizeof(ClockRec),
  109.     /* class_initialize        */    ClassInitialize,
  110.     /* class_part_initialize    */    NULL,
  111.     /* class_inited        */    FALSE,
  112.     /* initialize        */    Initialize,
  113.     /* initialize_hook        */    NULL,
  114.     /* realize            */    Realize,
  115.     /* actions            */    NULL,
  116.     /* num_actions        */    0,
  117.     /* resources        */    resources,
  118.     /* resource_count        */    XtNumber(resources),
  119.     /* xrm_class        */    NULLQUARK,
  120.     /* compress_motion        */    TRUE,
  121.     /* compress_exposure    */    TRUE,
  122.     /* compress_enterleave    */    TRUE,
  123.     /* visible_interest        */    FALSE,
  124.     /* destroy            */    Destroy,
  125.     /* resize            */    Resize,
  126.     /* expose            */    Redisplay,
  127.     /* set_values        */    SetValues,
  128.     /* set_values_hook        */    NULL,
  129.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  130.     /* get_values_hook        */    NULL,
  131.     /* accept_focus        */    NULL,
  132.     /* version            */    XtVersion,
  133.     /* callback_private        */    NULL,
  134.     /* tm_table            */    NULL,
  135.     /* query_geometry           */    XtInheritQueryGeometry,
  136.     /* display_accelerator      */    XtInheritDisplayAccelerator,
  137.     /* extension                */    NULL
  138.     },
  139.     { /* simple fields */
  140.     /* change_sensitive         */      XtInheritChangeSensitive
  141.     },
  142.     { /* clock fields */
  143.     /* ignore                   */      0
  144.     }
  145. };
  146.  
  147. WidgetClass clockWidgetClass = (WidgetClass) &clockClassRec;
  148.  
  149. /****************************************************************
  150.  *
  151.  * Private Procedures
  152.  *
  153.  ****************************************************************/
  154.  
  155. static void ClassInitialize()
  156. {
  157.     XawInitializeWidgetSet();
  158.     XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
  159.             NULL, 0 );
  160. }
  161.  
  162. /* ARGSUSED */
  163. static void Initialize (request, new)
  164.     Widget request, new;
  165. {
  166.     ClockWidget w = (ClockWidget)new;
  167.     XtGCMask        valuemask;
  168.     XGCValues    myXGCV;
  169.     int min_height, min_width;
  170.  
  171.     valuemask = GCForeground | GCBackground | GCFont | GCLineWidth;
  172.     if (w->clock.font != NULL)
  173.         myXGCV.font = w->clock.font->fid;
  174.     else
  175.         valuemask &= ~GCFont;    /* use server default font */
  176.  
  177.     min_width = min_height = ANALOG_SIZE_DEFAULT;
  178.     if(!w->clock.analog) {
  179.        char *str;
  180.        struct tm tm;
  181.        long time_value;
  182.        (void) time(&time_value);
  183.        tm = *localtime(&time_value);
  184.        str = asctime(&tm);
  185.        if (w->clock.font == NULL)
  186.           w->clock.font = XQueryFont( XtDisplay(w),
  187.                       XGContextFromGC(
  188.                        DefaultGCOfScreen(XtScreen(w))) );
  189.        min_width = XTextWidth(w->clock.font, str, strlen(str)) +
  190.       2 * w->clock.padding;
  191.        min_height = w->clock.font->ascent +
  192.       w->clock.font->descent + 2 * w->clock.padding;
  193.     }
  194.     if (w->core.width == 0)
  195.     w->core.width = min_width;
  196.     if (w->core.height == 0)
  197.     w->core.height = min_height;
  198.  
  199.     myXGCV.foreground = w->clock.fgpixel;
  200.     myXGCV.background = w->core.background_pixel;
  201.     if (w->clock.font != NULL)
  202.         myXGCV.font = w->clock.font->fid;
  203.     else
  204.         valuemask &= ~GCFont;    /* use server default font */
  205.     myXGCV.line_width = 0;
  206.     w->clock.myGC = XtGetGC((Widget)w, valuemask, &myXGCV);
  207.  
  208.     valuemask = GCForeground | GCLineWidth ;
  209.     myXGCV.foreground = w->core.background_pixel;
  210.     w->clock.EraseGC = XtGetGC((Widget)w, valuemask, &myXGCV);
  211.  
  212.     myXGCV.foreground = w->clock.Hipixel;
  213.     w->clock.HighGC = XtGetGC((Widget)w, valuemask, &myXGCV);
  214.  
  215.     valuemask = GCForeground;
  216.     myXGCV.foreground = w->clock.Hdpixel;
  217.     w->clock.HandGC = XtGetGC((Widget)w, valuemask, &myXGCV);
  218.  
  219.     if (w->clock.update <= 0)
  220.     w->clock.update = 60;    /* make invalid update's use a default */
  221.     w->clock.show_second_hand = (w->clock.update <= SECOND_HAND_TIME);
  222.     w->clock.numseg = 0;
  223.     w->clock.interval_id = 0;
  224. }
  225.  
  226. static void Realize (gw, valueMask, attrs)
  227.      Widget gw;
  228.      XtValueMask *valueMask;
  229.      XSetWindowAttributes *attrs;
  230. {
  231.      ClockWidget    w = (ClockWidget) gw;
  232. #ifdef notdef
  233.      *valueMask |= CWBitGravity;
  234.      attrs->bit_gravity = ForgetGravity;
  235. #endif
  236.      switch (w->clock.backing_store) {
  237.      case Always:
  238.      case NotUseful:
  239.      case WhenMapped:
  240.          *valueMask |=CWBackingStore;
  241.     attrs->backing_store = w->clock.backing_store;
  242.     break;
  243.      }
  244.      (*clockWidgetClass->core_class.superclass->core_class.realize)
  245.      (gw, valueMask, attrs);
  246.      Resize(gw);
  247. }
  248.  
  249. static void Destroy (gw)
  250.      Widget gw;
  251. {
  252.      ClockWidget w = (ClockWidget) gw;
  253.      if (w->clock.interval_id) XtRemoveTimeOut (w->clock.interval_id);
  254.      XtReleaseGC (gw, w->clock.myGC);
  255.      XtReleaseGC (gw, w->clock.HighGC);
  256.      XtReleaseGC (gw, w->clock.HandGC);
  257.      XtReleaseGC (gw, w->clock.EraseGC);
  258. }
  259.  
  260. static void Resize (gw) 
  261.     Widget gw;
  262. {
  263.     ClockWidget w = (ClockWidget) gw;
  264.     /* don't do this computation if window hasn't been realized yet. */
  265.     if (XtIsRealized(gw) && w->clock.analog) {
  266.     /* need signed value since Dimension is unsigned */
  267.     int radius = ((int) min(w->core.width, w->core.height) - (int) (2 * w->clock.padding)) / 2;
  268.         w->clock.radius = (Dimension) max (radius, 1);
  269.  
  270.         w->clock.second_hand_length = (int)(SECOND_HAND_FRACT * w->clock.radius) / 100;
  271.         w->clock.minute_hand_length = (int)(MINUTE_HAND_FRACT * w->clock.radius) / 100;
  272.         w->clock.hour_hand_length = (int)(HOUR_HAND_FRACT * w->clock.radius) / 100;
  273.         w->clock.hand_width = (int)(HAND_WIDTH_FRACT * w->clock.radius) / 100;
  274.         w->clock.second_hand_width = (int)(SECOND_WIDTH_FRACT * w->clock.radius) / 100;
  275.  
  276.         w->clock.centerX = w->core.width / 2;
  277.         w->clock.centerY = w->core.height / 2;
  278.     }
  279. }
  280.  
  281. /* ARGSUSED */
  282. static void Redisplay (gw, event, region)
  283.     Widget gw;
  284.     XEvent *event;        /* unused */
  285.     Region region;        /* unused */
  286. {
  287.     ClockWidget w = (ClockWidget) gw;
  288.     if (w->clock.analog) {
  289.     if (w->clock.numseg != 0)
  290.         erase_hands (w, (struct tm *) 0);
  291.         DrawClockFace(w);
  292.     } else {
  293.     w->clock.prev_time_string[0] = '\0';
  294.     }
  295.     clock_tic((XtPointer)w, (XtIntervalId)0);
  296. }
  297.  
  298. /* ARGSUSED */
  299. static void clock_tic(client_data, id)
  300.         XtPointer client_data;
  301.         XtIntervalId *id;
  302. {
  303.         ClockWidget w = (ClockWidget)client_data;    
  304.     struct tm tm; 
  305.     long    time_value;
  306.     char    *time_ptr;
  307.         register Display *dpy = XtDisplay(w);
  308.         register Window win = XtWindow(w);
  309.  
  310.     if (id || !w->clock.interval_id)
  311.         w->clock.interval_id =
  312.         XtAppAddTimeOut( XtWidgetToApplicationContext( (Widget) w),
  313.                 w->clock.update*1000, clock_tic, (XtPointer)w );
  314.     (void) time(&time_value);
  315.     tm = *localtime(&time_value);
  316.     /*
  317.      * Beep on the half hour; double-beep on the hour.
  318.      */
  319.     if (w->clock.chime == TRUE) {
  320.         if (w->clock.beeped && (tm.tm_min != 30) &&
  321.         (tm.tm_min != 0))
  322.           w->clock.beeped = FALSE;
  323.         if (((tm.tm_min == 30) || (tm.tm_min == 0)) 
  324.         && (!w->clock.beeped)) {
  325.         w->clock.beeped = TRUE;
  326.         XBell(dpy, 50);    
  327.         if (tm.tm_min == 0)
  328.           XBell(dpy, 50);
  329.         }
  330.     }
  331.     if( w->clock.analog == FALSE ) {
  332.         int    clear_from;
  333.         int i, len, prev_len;
  334.  
  335.         time_ptr = asctime(&tm);
  336.         len = strlen (time_ptr);
  337.         if (time_ptr[len - 1] == '\n') time_ptr[--len] = '\0';
  338.         prev_len = strlen (w->clock.prev_time_string);
  339.         for (i = 0; ((i < len) && (i < prev_len) && 
  340.                  (w->clock.prev_time_string[i] == time_ptr[i])); i++);
  341.         strcpy (w->clock.prev_time_string+i, time_ptr+i);
  342.  
  343.         XDrawImageString (dpy, win, w->clock.myGC,
  344.                   (2+w->clock.padding +
  345.                    XTextWidth (w->clock.font, time_ptr, i)),
  346.                   2+w->clock.font->ascent+w->clock.padding,
  347.                   time_ptr + i, len - i);
  348.         /*
  349.          * Clear any left over bits
  350.          */
  351.         clear_from = XTextWidth (w->clock.font, time_ptr, len)
  352.                  + 2 + w->clock.padding;
  353.         if (clear_from < (int)w->core.width)
  354.         XFillRectangle (dpy, win, w->clock.EraseGC,
  355.             clear_from, 0, w->core.width - clear_from, w->core.height);
  356.     } else {
  357.             /*
  358.              * The second (or minute) hand is sec (or min) 
  359.              * sixtieths around the clock face. The hour hand is
  360.              * (hour + min/60) twelfths of the way around the
  361.              * clock-face.  The derivation is left as an excercise
  362.              * for the reader.
  363.              */
  364.  
  365.             /*
  366.              * 12 hour clock.
  367.              */
  368.             if(tm.tm_hour >= 12)
  369.                 tm.tm_hour -= 12;
  370.  
  371.             erase_hands (w, &tm);
  372.  
  373.             if (w->clock.numseg == 0 ||
  374.             tm.tm_min != w->clock.otm.tm_min ||
  375.             tm.tm_hour != w->clock.otm.tm_hour) {
  376.                 w->clock.segbuffptr = w->clock.segbuff;
  377.                 w->clock.numseg = 0;
  378.                 /*
  379.                  * Calculate the hour hand, fill it in with its
  380.                  * color and then outline it.  Next, do the same
  381.                  * with the minute hand.  This is a cheap hidden
  382.                  * line algorithm.
  383.                  */
  384.                 DrawHand(w,
  385.                 w->clock.minute_hand_length, w->clock.hand_width,
  386.                 tm.tm_min * 12
  387.                 );
  388.                 if(w->clock.Hdpixel != w->core.background_pixel)
  389.                 XFillPolygon( dpy,
  390.                     win, w->clock.HandGC,
  391.                     w->clock.segbuff, VERTICES_IN_HANDS,
  392.                     Convex, CoordModeOrigin
  393.                 );
  394.                 XDrawLines( dpy,
  395.                 win, w->clock.HighGC,
  396.                 w->clock.segbuff, VERTICES_IN_HANDS,
  397.                        CoordModeOrigin);
  398.                 w->clock.hour = w->clock.segbuffptr;
  399.                 DrawHand(w, 
  400.                 w->clock.hour_hand_length, w->clock.hand_width,
  401.                 tm.tm_hour * 60 + tm.tm_min
  402.                 );
  403.                 if(w->clock.Hdpixel != w->core.background_pixel) {
  404.                   XFillPolygon(dpy,
  405.                        win, w->clock.HandGC,
  406.                        w->clock.hour,
  407.                        VERTICES_IN_HANDS,
  408.                        Convex, CoordModeOrigin
  409.                        );
  410.                 }
  411.                 XDrawLines( dpy,
  412.                        win, w->clock.HighGC,
  413.                        w->clock.hour, VERTICES_IN_HANDS,
  414.                        CoordModeOrigin );
  415.  
  416.                 w->clock.sec = w->clock.segbuffptr;
  417.             }
  418.             if (w->clock.show_second_hand == TRUE) {
  419.                 w->clock.segbuffptr = w->clock.sec;
  420.                 DrawSecond(w,
  421.                 w->clock.second_hand_length - 2, 
  422.                 w->clock.second_hand_width,
  423.                 w->clock.minute_hand_length + 2,
  424.                 tm.tm_sec * 12
  425.                 );
  426.                 if(w->clock.Hdpixel != w->core.background_pixel)
  427.                 XFillPolygon( dpy,
  428.                     win, w->clock.HandGC,
  429.                     w->clock.sec,
  430.                     VERTICES_IN_HANDS -2,
  431.                     Convex, CoordModeOrigin
  432.                 );
  433.                 XDrawLines( dpy,
  434.                        win, w->clock.HighGC,
  435.                        w->clock.sec,
  436.                        VERTICES_IN_HANDS-1,
  437.                        CoordModeOrigin
  438.                         );
  439.  
  440.             }
  441.             w->clock.otm = tm;
  442.         }
  443. }
  444.     
  445. static erase_hands (w, tm)
  446. ClockWidget    w;
  447. struct tm    *tm;
  448. {
  449.     /*
  450.      * Erase old hands.
  451.      */
  452.     if(w->clock.numseg > 0) {
  453.     Display    *dpy;
  454.     Window    win;
  455.  
  456.     dpy = XtDisplay (w);
  457.     win = XtWindow (w);
  458.     if (w->clock.show_second_hand == TRUE) {
  459.         XDrawLines(dpy, win,
  460.         w->clock.EraseGC,
  461.         w->clock.sec,
  462.         VERTICES_IN_HANDS-1,
  463.         CoordModeOrigin);
  464.         if(w->clock.Hdpixel != w->core.background_pixel) {
  465.         XFillPolygon(dpy,
  466.             win, w->clock.EraseGC,
  467.             w->clock.sec,
  468.             VERTICES_IN_HANDS-2,
  469.             Convex, CoordModeOrigin
  470.             );
  471.         }
  472.     }
  473.     if(!tm || tm->tm_min != w->clock.otm.tm_min ||
  474.           tm->tm_hour != w->clock.otm.tm_hour)
  475.      {
  476.         XDrawLines( dpy, win,
  477.             w->clock.EraseGC,
  478.             w->clock.segbuff,
  479.             VERTICES_IN_HANDS,
  480.             CoordModeOrigin);
  481.         XDrawLines( dpy, win,
  482.             w->clock.EraseGC,
  483.             w->clock.hour,
  484.             VERTICES_IN_HANDS,
  485.             CoordModeOrigin);
  486.         if(w->clock.Hdpixel != w->core.background_pixel) {
  487.         XFillPolygon( dpy, win,
  488.                    w->clock.EraseGC,
  489.                   w->clock.segbuff, VERTICES_IN_HANDS,
  490.                   Convex, CoordModeOrigin);
  491.         XFillPolygon( dpy, win,
  492.                    w->clock.EraseGC,
  493.                   w->clock.hour,
  494.                   VERTICES_IN_HANDS,
  495.                   Convex, CoordModeOrigin);
  496.         }
  497.     }
  498.     }
  499. }
  500.  
  501. static float Const Sines[] = {
  502. .000000, .008727, .017452, .026177, .034899, .043619, .052336, .061049,
  503. .069756, .078459, .087156, .095846, .104528, .113203, .121869, .130526,
  504. .139173, .147809, .156434, .165048, .173648, .182236, .190809, .199368,
  505. .207912, .216440, .224951, .233445, .241922, .250380, .258819, .267238,
  506. .275637, .284015, .292372, .300706, .309017, .317305, .325568, .333807,
  507. .342020, .350207, .358368, .366501, .374607, .382683, .390731, .398749,
  508. .406737, .414693, .422618, .430511, .438371, .446198, .453990, .461749,
  509. .469472, .477159, .484810, .492424, .500000, .507538, .515038, .522499,
  510. .529919, .537300, .544639, .551937, .559193, .566406, .573576, .580703,
  511. .587785, .594823, .601815, .608761, .615661, .622515, .629320, .636078,
  512. .642788, .649448, .656059, .662620, .669131, .675590, .681998, .688355,
  513. .694658, .700909, .707107
  514. };
  515.  
  516. static float Const Cosines[] = {
  517. 1.00000, .999962, .999848, .999657, .999391, .999048, .998630, .998135,
  518. .997564, .996917, .996195, .995396, .994522, .993572, .992546, .991445,
  519. .990268, .989016, .987688, .986286, .984808, .983255, .981627, .979925,
  520. .978148, .976296, .974370, .972370, .970296, .968148, .965926, .963630,
  521. .961262, .958820, .956305, .953717, .951057, .948324, .945519, .942641,
  522. .939693, .936672, .933580, .930418, .927184, .923880, .920505, .917060,
  523. .913545, .909961, .906308, .902585, .898794, .894934, .891007, .887011,
  524. .882948, .878817, .874620, .870356, .866025, .861629, .857167, .852640,
  525. .848048, .843391, .838671, .833886, .829038, .824126, .819152, .814116,
  526. .809017, .803857, .798636, .793353, .788011, .782608, .777146, .771625,
  527. .766044, .760406, .754710, .748956, .743145, .737277, .731354, .725374,
  528. .719340, .713250, .707107
  529. };
  530.  
  531. static void ClockAngle(tick_units, sinp, cosp)
  532.     int tick_units;
  533.     double *sinp, *cosp;
  534. {
  535.     int reduced, upper;
  536.  
  537.     reduced = tick_units % 90;
  538.     upper = tick_units / 90;
  539.     if (upper & 1)
  540.     reduced = 90 - reduced;
  541.     if ((upper + 1) & 2) {
  542.     *sinp = Cosines[reduced];
  543.     *cosp = Sines[reduced];
  544.     } else {
  545.     *sinp = Sines[reduced];
  546.     *cosp = Cosines[reduced];
  547.     }
  548.     if (upper >= 2 && upper < 6)
  549.     *cosp = -*cosp;
  550.     if (upper >= 4)
  551.     *sinp = -*sinp;
  552. }
  553.  
  554. /*
  555.  * DrawLine - Draws a line.
  556.  *
  557.  * blank_length is the distance from the center which the line begins.
  558.  * length is the maximum length of the hand.
  559.  * Tick_units is a number between zero and 12*60 indicating
  560.  * how far around the circle (clockwise) from high noon.
  561.  *
  562.  * The blank_length feature is because I wanted to draw tick-marks around the
  563.  * circle (for seconds).  The obvious means of drawing lines from the center
  564.  * to the perimeter, then erasing all but the outside most pixels doesn't
  565.  * work because of round-off error (sigh).
  566.  */
  567. static void DrawLine(w, blank_length, length, tick_units)
  568. ClockWidget w;
  569. Dimension blank_length;
  570. Dimension length;
  571. int tick_units;
  572. {
  573.     double dblank_length = (double)blank_length, dlength = (double)length;
  574.     double cosangle, sinangle;
  575.     int cx = w->clock.centerX, cy = w->clock.centerY, x1, y1, x2, y2;
  576.  
  577.     /*
  578.      *  Angles are measured from 12 o'clock, clockwise increasing.
  579.      *  Since in X, +x is to the right and +y is downward:
  580.      *
  581.      *    x = x0 + r * sin(theta)
  582.      *    y = y0 - r * cos(theta)
  583.      *
  584.      */
  585.     ClockAngle(tick_units, &sinangle, &cosangle);
  586.  
  587.     /* break this out so that stupid compilers can cope */
  588.     x1 = cx + (int)(dblank_length * sinangle);
  589.     y1 = cy - (int)(dblank_length * cosangle);
  590.     x2 = cx + (int)(dlength * sinangle);
  591.     y2 = cy - (int)(dlength * cosangle);
  592.     SetSeg(w, x1, y1, x2, y2);
  593. }
  594.  
  595. /*
  596.  * DrawHand - Draws a hand.
  597.  *
  598.  * length is the maximum length of the hand.
  599.  * width is the half-width of the hand.
  600.  * Tick_units is a number between zero and 12*60 indicating
  601.  * how far around the circle (clockwise) from high noon.
  602.  *
  603.  */
  604. static void DrawHand(w, length, width, tick_units)
  605. ClockWidget w;
  606. Dimension length, width;
  607. int tick_units;
  608. {
  609.  
  610.     double cosangle, sinangle;
  611.     register double ws, wc;
  612.     Position x, y, x1, y1, x2, y2;
  613.  
  614.     /*
  615.      *  Angles are measured from 12 o'clock, clockwise increasing.
  616.      *  Since in X, +x is to the right and +y is downward:
  617.      *
  618.      *    x = x0 + r * sin(theta)
  619.      *    y = y0 - r * cos(theta)
  620.      *
  621.      */
  622.     ClockAngle(tick_units, &sinangle, &cosangle);
  623.     /*
  624.      * Order of points when drawing the hand.
  625.      *
  626.      *        1,4
  627.      *        / \
  628.      *           /   \
  629.      *          /     \
  630.      *        2 ------- 3
  631.      */
  632.     wc = width * cosangle;
  633.     ws = width * sinangle;
  634.     SetSeg(w,
  635.            x = w->clock.centerX + round(length * sinangle),
  636.            y = w->clock.centerY - round(length * cosangle),
  637.            x1 = w->clock.centerX - round(ws + wc), 
  638.            y1 = w->clock.centerY + round(wc - ws));  /* 1 ---- 2 */
  639.     /* 2 */
  640.     SetSeg(w, x1, y1, 
  641.            x2 = w->clock.centerX - round(ws - wc), 
  642.            y2 = w->clock.centerY + round(wc + ws));  /* 2 ----- 3 */
  643.  
  644.     SetSeg(w, x2, y2, x, y);    /* 3 ----- 1(4) */
  645. }
  646.  
  647. /*
  648.  * DrawSecond - Draws the second hand (diamond).
  649.  *
  650.  * length is the maximum length of the hand.
  651.  * width is the half-width of the hand.
  652.  * offset is direct distance from center to tail end.
  653.  * Tick_units is a number between zero and 12*60 indicating
  654.  * how far around the circle (clockwise) from high noon.
  655.  *
  656.  */
  657. static void DrawSecond(w, length, width, offset, tick_units)
  658. ClockWidget w;
  659. Dimension length, width, offset;
  660. int tick_units;
  661. {
  662.  
  663.     double cosangle, sinangle;
  664.     register double ms, mc, ws, wc;
  665.     register int mid;
  666.     Position x, y;
  667.  
  668.     /*
  669.      *  Angles are measured from 12 o'clock, clockwise increasing.
  670.      *  Since in X, +x is to the right and +y is downward:
  671.      *
  672.      *    x = x0 + r * sin(theta)
  673.      *    y = y0 - r * cos(theta)
  674.      *
  675.      */
  676.     ClockAngle(tick_units, &sinangle, &cosangle);
  677.     /*
  678.      * Order of points when drawing the hand.
  679.      *
  680.      *        1,5
  681.      *        / \
  682.      *           /   \
  683.      *          /     \
  684.      *        2<       >4
  685.      *          \     /
  686.      *           \   /
  687.      *        \ /
  688.      *    -     3
  689.      *    |
  690.      *    |
  691.      *   offset
  692.      *    |
  693.      *    |
  694.      *    -     + center
  695.      */
  696.  
  697.     mid = (int) (length + offset) / 2;
  698.     mc = mid * cosangle;
  699.     ms = mid * sinangle;
  700.     wc = width * cosangle;
  701.     ws = width * sinangle;
  702.     /*1 ---- 2 */
  703.     SetSeg(w,
  704.            x = w->clock.centerX + round(length * sinangle),
  705.            y = w->clock.centerY - round(length * cosangle),
  706.            w->clock.centerX + round(ms - wc),
  707.            w->clock.centerY - round(mc + ws) );
  708.     SetSeg(w, w->clock.centerX + round(offset *sinangle),
  709.            w->clock.centerY - round(offset * cosangle), /* 2-----3 */
  710.            w->clock.centerX + round(ms + wc), 
  711.            w->clock.centerY - round(mc - ws));
  712.     w->clock.segbuffptr->x = x;
  713.     w->clock.segbuffptr++->y = y;
  714.     w->clock.numseg ++;
  715. }
  716.  
  717. static void SetSeg(w, x1, y1, x2, y2)
  718. ClockWidget w;
  719. int x1, y1, x2, y2;
  720. {
  721.     w->clock.segbuffptr->x = x1;
  722.     w->clock.segbuffptr++->y = y1;
  723.     w->clock.segbuffptr->x = x2;
  724.     w->clock.segbuffptr++->y = y2;
  725.     w->clock.numseg += 2;
  726. }
  727.  
  728. /*
  729.  *  Draw the clock face (every fifth tick-mark is longer
  730.  *  than the others).
  731.  */
  732. static void DrawClockFace(w)
  733. ClockWidget w;
  734. {
  735.     register int i;
  736.     register int delta = (int)(w->clock.radius - w->clock.second_hand_length) / 3;
  737.     
  738.     w->clock.segbuffptr = w->clock.segbuff;
  739.     w->clock.numseg = 0;
  740.     for (i = 0; i < 60; i++)
  741.         DrawLine(w, ( (i % 5) == 0 ? 
  742.                  w->clock.second_hand_length :
  743.                  (w->clock.radius - delta) ),
  744.              w->clock.radius, i * 12);
  745.     /*
  746.      * Go ahead and draw it.
  747.      */
  748.     XDrawSegments(XtDisplay(w), XtWindow(w),
  749.               w->clock.myGC, (XSegment *) &(w->clock.segbuff[0]),
  750.               w->clock.numseg/2);
  751.     
  752.     w->clock.segbuffptr = w->clock.segbuff;
  753.     w->clock.numseg = 0;
  754. }
  755.  
  756. static int round(x)
  757. double x;
  758. {
  759.     return(x >= 0.0 ? (int)(x + .5) : (int)(x - .5));
  760. }
  761.  
  762. /* ARGSUSED */
  763. static Boolean SetValues (gcurrent, grequest, gnew)
  764.     Widget gcurrent, grequest, gnew;
  765. {
  766.       ClockWidget current = (ClockWidget) gcurrent;
  767.       ClockWidget new = (ClockWidget) gnew;
  768.       Boolean redisplay = FALSE;
  769.       XtGCMask valuemask;
  770.       XGCValues    myXGCV;
  771.  
  772.       /* first check for changes to clock-specific resources.  We'll accept all
  773.          the changes, but may need to do some computations first. */
  774.  
  775.       if (new->clock.update != current->clock.update) {
  776.       if (current->clock.interval_id)
  777.           XtRemoveTimeOut (current->clock.interval_id);
  778.       if (XtIsRealized( (Widget) new))
  779.           new->clock.interval_id = XtAppAddTimeOut( 
  780.                                          XtWidgetToApplicationContext(gnew),
  781.                      new->clock.update*1000,
  782.                          clock_tic, (XtPointer)gnew);
  783.  
  784.       new->clock.show_second_hand =(new->clock.update <= SECOND_HAND_TIME);
  785.       }
  786.  
  787.       if (new->clock.padding != current->clock.padding)
  788.        redisplay = TRUE;
  789.  
  790.       if (new->clock.analog != current->clock.analog)
  791.        redisplay = TRUE;
  792.  
  793.        if (new->clock.font != current->clock.font)
  794.        redisplay = TRUE;
  795.  
  796.       if ((new->clock.fgpixel != current->clock.fgpixel)
  797.           || (new->core.background_pixel != current->core.background_pixel)) {
  798.           valuemask = GCForeground | GCBackground | GCFont | GCLineWidth;
  799.       myXGCV.foreground = new->clock.fgpixel;
  800.       myXGCV.background = new->core.background_pixel;
  801.           myXGCV.font = new->clock.font->fid;
  802.       myXGCV.line_width = 0;
  803.       XtReleaseGC (gcurrent, current->clock.myGC);
  804.       new->clock.myGC = XtGetGC(gcurrent, valuemask, &myXGCV);
  805.       redisplay = TRUE;
  806.           }
  807.  
  808.       if (new->clock.Hipixel != current->clock.Hipixel) {
  809.           valuemask = GCForeground | GCLineWidth;
  810.       myXGCV.foreground = new->clock.fgpixel;
  811.           myXGCV.font = new->clock.font->fid;
  812.       myXGCV.line_width = 0;
  813.       XtReleaseGC (gcurrent, current->clock.HighGC);
  814.       new->clock.HighGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV);
  815.       redisplay = TRUE;
  816.           }
  817.  
  818.       if (new->clock.Hdpixel != current->clock.Hdpixel) {
  819.           valuemask = GCForeground;
  820.       myXGCV.foreground = new->clock.fgpixel;
  821.       XtReleaseGC (gcurrent, current->clock.HandGC);
  822.       new->clock.HandGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV);
  823.       redisplay = TRUE;
  824.           }
  825.  
  826.       if (new->core.background_pixel != current->core.background_pixel) {
  827.           valuemask = GCForeground | GCLineWidth;
  828.       myXGCV.foreground = new->core.background_pixel;
  829.       myXGCV.line_width = 0;
  830.       XtReleaseGC (gcurrent, current->clock.EraseGC);
  831.       new->clock.EraseGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV);
  832.       redisplay = TRUE;
  833.       }
  834.      
  835.      return (redisplay);
  836.  
  837. }
  838.