source: trunk/athena/etc/xdm/xlogin/Clock.c @ 8287

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