summaryrefslogtreecommitdiff
path: root/Clock.c
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
commit7fa20e0899cf53cbb6d386d0688127df8b6fb0c7 (patch)
tree2a47ff68a964eb21a7cb24420e7d3183bfa9720f /Clock.c
R6.6 is the Xorg base-lineXORG-MAIN
Diffstat (limited to 'Clock.c')
-rw-r--r--Clock.c882
1 files changed, 882 insertions, 0 deletions
diff --git a/Clock.c b/Clock.c
new file mode 100644
index 0000000..1a01b1b
--- /dev/null
+++ b/Clock.c
@@ -0,0 +1,882 @@
+/* $Xorg: Clock.c,v 1.4 2001/02/09 02:05:39 xorgcvs Exp $ */
+
+/***********************************************************
+
+Copyright 1987, 1988, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/StringDefs.h>
+#include <X11/IntrinsicP.h>
+#include "ClockP.h"
+#include <X11/Xosdefs.h>
+
+#if defined(__STDC__) && !defined(AIXV3) /* AIX is broken */
+#define Const const
+#else
+#define Const /**/
+#endif
+
+#ifdef X_NOT_STDC_ENV
+extern struct tm *localtime();
+#define Time_t long
+extern Time_t time ();
+#else
+#include <time.h>
+#define Time_t time_t
+#endif
+
+#ifdef XKB
+#include <X11/extensions/XKBbells.h>
+#endif
+
+static void clock_tic(), DrawHand(), DrawSecond(), SetSeg(), DrawClockFace();
+static erase_hands(), round();
+
+/* Private Definitions */
+
+#define VERTICES_IN_HANDS 6 /* to draw triangle */
+#define PI 3.14159265358979
+#define TWOPI (2. * PI)
+
+#define SECOND_HAND_FRACT 90
+#define MINUTE_HAND_FRACT 70
+#define HOUR_HAND_FRACT 40
+#define HAND_WIDTH_FRACT 7
+#define SECOND_WIDTH_FRACT 5
+#define SECOND_HAND_TIME 30
+
+#define ANALOG_SIZE_DEFAULT 164
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define abs(a) ((a) < 0 ? -(a) : (a))
+
+
+/* Initialization of defaults */
+
+#define offset(field) XtOffsetOf(ClockRec, clock.field)
+#define goffset(field) XtOffsetOf(WidgetRec, core.field)
+
+static XtResource resources[] = {
+ {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ goffset(width), XtRImmediate, (XtPointer) 0},
+ {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ goffset(height), XtRImmediate, (XtPointer) 0},
+ {XtNupdate, XtCInterval, XtRInt, sizeof(int),
+ offset(update), XtRImmediate, (XtPointer) 60 },
+ {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(fgpixel), XtRString, XtDefaultForeground},
+ {XtNhand, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(Hdpixel), XtRString, XtDefaultForeground},
+ {XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(Hipixel), XtRString, XtDefaultForeground},
+ {XtNanalog, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ offset(analog), XtRImmediate, (XtPointer) TRUE},
+ {XtNchime, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ offset(chime), XtRImmediate, (XtPointer) FALSE },
+ {XtNpadding, XtCMargin, XtRInt, sizeof(int),
+ offset(padding), XtRImmediate, (XtPointer) 8},
+ {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
+ offset(font), XtRString, XtDefaultFont},
+ {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
+ offset (backing_store), XtRString, "default"},
+};
+
+#undef offset
+#undef goffset
+
+static void ClassInitialize();
+static void Initialize(), Realize(), Destroy(), Resize(), Redisplay();
+static Boolean SetValues();
+
+ClockClassRec clockClassRec = {
+ { /* core fields */
+ /* superclass */ (WidgetClass) &simpleClassRec,
+ /* class_name */ "Clock",
+ /* widget_size */ sizeof(ClockRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* simple fields */
+ /* change_sensitive */ XtInheritChangeSensitive
+ },
+ { /* clock fields */
+ /* ignore */ 0
+ }
+};
+
+WidgetClass clockWidgetClass = (WidgetClass) &clockClassRec;
+
+/****************************************************************
+ *
+ * Private Procedures
+ *
+ ****************************************************************/
+
+static void ClassInitialize()
+{
+ XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
+ NULL, 0 );
+}
+
+/* ARGSUSED */
+static void Initialize (request, new, args, num_args)
+ Widget request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ ClockWidget w = (ClockWidget)new;
+ XtGCMask valuemask;
+ XGCValues myXGCV;
+ int min_height, min_width;
+
+ valuemask = GCForeground | GCBackground | GCFont | GCLineWidth;
+ if (w->clock.font != NULL)
+ myXGCV.font = w->clock.font->fid;
+ else
+ valuemask &= ~GCFont; /* use server default font */
+
+ min_width = min_height = ANALOG_SIZE_DEFAULT;
+ if(!w->clock.analog) {
+ char *str;
+ struct tm tm;
+ Time_t time_value;
+
+ (void) time(&time_value);
+ tm = *localtime(&time_value);
+ str = asctime(&tm);
+ if (w->clock.font == NULL)
+ w->clock.font = XQueryFont( XtDisplay(w),
+ XGContextFromGC(
+ DefaultGCOfScreen(XtScreen(w))) );
+ min_width = XTextWidth(w->clock.font, str, strlen(str)) +
+ 2 * w->clock.padding;
+ min_height = w->clock.font->ascent +
+ w->clock.font->descent + 2 * w->clock.padding;
+ }
+ if (w->core.width == 0)
+ w->core.width = min_width;
+ if (w->core.height == 0)
+ w->core.height = min_height;
+
+ myXGCV.foreground = w->clock.fgpixel;
+ myXGCV.background = w->core.background_pixel;
+ if (w->clock.font != NULL)
+ myXGCV.font = w->clock.font->fid;
+ else
+ valuemask &= ~GCFont; /* use server default font */
+ myXGCV.line_width = 0;
+ w->clock.myGC = XtGetGC((Widget)w, valuemask, &myXGCV);
+
+ valuemask = GCForeground | GCLineWidth ;
+ myXGCV.foreground = w->core.background_pixel;
+ w->clock.EraseGC = XtGetGC((Widget)w, valuemask, &myXGCV);
+
+ myXGCV.foreground = w->clock.Hipixel;
+ w->clock.HighGC = XtGetGC((Widget)w, valuemask, &myXGCV);
+
+ valuemask = GCForeground;
+ myXGCV.foreground = w->clock.Hdpixel;
+ w->clock.HandGC = XtGetGC((Widget)w, valuemask, &myXGCV);
+
+ if (w->clock.update <= 0)
+ w->clock.update = 60; /* make invalid update's use a default */
+ w->clock.show_second_hand = (w->clock.update <= SECOND_HAND_TIME);
+ w->clock.numseg = 0;
+ w->clock.interval_id = 0;
+}
+
+static void Realize (gw, valueMask, attrs)
+ Widget gw;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attrs;
+{
+ ClockWidget w = (ClockWidget) gw;
+#ifdef notdef
+ *valueMask |= CWBitGravity;
+ attrs->bit_gravity = ForgetGravity;
+#endif
+ switch (w->clock.backing_store) {
+ case Always:
+ case NotUseful:
+ case WhenMapped:
+ *valueMask |=CWBackingStore;
+ attrs->backing_store = w->clock.backing_store;
+ break;
+ }
+ (*clockWidgetClass->core_class.superclass->core_class.realize)
+ (gw, valueMask, attrs);
+ Resize(gw);
+}
+
+static void Destroy (gw)
+ Widget gw;
+{
+ ClockWidget w = (ClockWidget) gw;
+ if (w->clock.interval_id) XtRemoveTimeOut (w->clock.interval_id);
+ XtReleaseGC (gw, w->clock.myGC);
+ XtReleaseGC (gw, w->clock.HighGC);
+ XtReleaseGC (gw, w->clock.HandGC);
+ XtReleaseGC (gw, w->clock.EraseGC);
+}
+
+static void Resize (gw)
+ Widget gw;
+{
+ ClockWidget w = (ClockWidget) gw;
+ /* don't do this computation if window hasn't been realized yet. */
+ if (XtIsRealized(gw) && w->clock.analog) {
+ /* need signed value since Dimension is unsigned */
+ int radius = ((int) min(w->core.width, w->core.height) - (int) (2 * w->clock.padding)) / 2;
+ w->clock.radius = (Dimension) max (radius, 1);
+
+ w->clock.second_hand_length = (int)(SECOND_HAND_FRACT * w->clock.radius) / 100;
+ w->clock.minute_hand_length = (int)(MINUTE_HAND_FRACT * w->clock.radius) / 100;
+ w->clock.hour_hand_length = (int)(HOUR_HAND_FRACT * w->clock.radius) / 100;
+ w->clock.hand_width = (int)(HAND_WIDTH_FRACT * w->clock.radius) / 100;
+ w->clock.second_hand_width = (int)(SECOND_WIDTH_FRACT * w->clock.radius) / 100;
+
+ w->clock.centerX = w->core.width / 2;
+ w->clock.centerY = w->core.height / 2;
+ }
+}
+
+/* ARGSUSED */
+static void Redisplay (gw, event, region)
+ Widget gw;
+ XEvent *event; /* unused */
+ Region region; /* unused */
+{
+ ClockWidget w = (ClockWidget) gw;
+ if (w->clock.analog) {
+ if (w->clock.numseg != 0)
+ erase_hands (w, (struct tm *) 0);
+ DrawClockFace(w);
+ } else {
+ w->clock.prev_time_string[0] = '\0';
+ }
+ clock_tic((XtPointer)w, (XtIntervalId)0);
+}
+
+/* ARGSUSED */
+static void clock_tic(client_data, id)
+ XtPointer client_data;
+ XtIntervalId *id;
+{
+ ClockWidget w = (ClockWidget)client_data;
+ struct tm tm;
+ Time_t time_value;
+ char *time_ptr;
+ register Display *dpy = XtDisplay(w);
+ register Window win = XtWindow(w);
+
+ if (id || !w->clock.interval_id)
+ w->clock.interval_id =
+ XtAppAddTimeOut( XtWidgetToApplicationContext( (Widget) w),
+ w->clock.update*1000, clock_tic, (XtPointer)w );
+ (void) time(&time_value);
+ tm = *localtime(&time_value);
+ /*
+ * Beep on the half hour; double-beep on the hour.
+ */
+ if (w->clock.chime == TRUE) {
+ if (w->clock.beeped && (tm.tm_min != 30) &&
+ (tm.tm_min != 0))
+ w->clock.beeped = FALSE;
+ if (((tm.tm_min == 30) || (tm.tm_min == 0))
+ && (!w->clock.beeped)) {
+ w->clock.beeped = TRUE;
+#ifdef XKB
+ if (tm.tm_min==0) {
+ XkbStdBell(dpy,win,50,XkbBI_ClockChimeHour);
+ XkbStdBell(dpy,win,50,XkbBI_RepeatingLastBell);
+ }
+ else {
+ XkbStdBell(dpy,win,50,XkbBI_ClockChimeHalf);
+ }
+#else
+ XBell(dpy, 50);
+ if (tm.tm_min == 0)
+ XBell(dpy, 50);
+#endif
+ }
+ }
+ if( w->clock.analog == FALSE ) {
+ int clear_from;
+ int i, len, prev_len;
+
+ time_ptr = asctime(&tm);
+ len = strlen (time_ptr);
+ if (time_ptr[len - 1] == '\n') time_ptr[--len] = '\0';
+ prev_len = strlen (w->clock.prev_time_string);
+ for (i = 0; ((i < len) && (i < prev_len) &&
+ (w->clock.prev_time_string[i] == time_ptr[i])); i++);
+ strcpy (w->clock.prev_time_string+i, time_ptr+i);
+
+ XDrawImageString (dpy, win, w->clock.myGC,
+ (2+w->clock.padding +
+ XTextWidth (w->clock.font, time_ptr, i)),
+ 2+w->clock.font->ascent+w->clock.padding,
+ time_ptr + i, len - i);
+ /*
+ * Clear any left over bits
+ */
+ clear_from = XTextWidth (w->clock.font, time_ptr, len)
+ + 2 + w->clock.padding;
+ if (clear_from < (int)w->core.width)
+ XFillRectangle (dpy, win, w->clock.EraseGC,
+ clear_from, 0, w->core.width - clear_from, w->core.height);
+ } else {
+ /*
+ * The second (or minute) hand is sec (or min)
+ * sixtieths around the clock face. The hour hand is
+ * (hour + min/60) twelfths of the way around the
+ * clock-face. The derivation is left as an excercise
+ * for the reader.
+ */
+
+ /*
+ * 12 hour clock.
+ */
+ if(tm.tm_hour >= 12)
+ tm.tm_hour -= 12;
+
+ erase_hands (w, &tm);
+
+ if (w->clock.numseg == 0 ||
+ tm.tm_min != w->clock.otm.tm_min ||
+ tm.tm_hour != w->clock.otm.tm_hour) {
+ w->clock.segbuffptr = w->clock.segbuff;
+ w->clock.numseg = 0;
+ /*
+ * Calculate the hour hand, fill it in with its
+ * color and then outline it. Next, do the same
+ * with the minute hand. This is a cheap hidden
+ * line algorithm.
+ */
+ DrawHand(w,
+ w->clock.minute_hand_length, w->clock.hand_width,
+ tm.tm_min * 12
+ );
+ if(w->clock.Hdpixel != w->core.background_pixel)
+ XFillPolygon( dpy,
+ win, w->clock.HandGC,
+ w->clock.segbuff, VERTICES_IN_HANDS,
+ Convex, CoordModeOrigin
+ );
+ XDrawLines( dpy,
+ win, w->clock.HighGC,
+ w->clock.segbuff, VERTICES_IN_HANDS,
+ CoordModeOrigin);
+ w->clock.hour = w->clock.segbuffptr;
+ DrawHand(w,
+ w->clock.hour_hand_length, w->clock.hand_width,
+ tm.tm_hour * 60 + tm.tm_min
+ );
+ if(w->clock.Hdpixel != w->core.background_pixel) {
+ XFillPolygon(dpy,
+ win, w->clock.HandGC,
+ w->clock.hour,
+ VERTICES_IN_HANDS,
+ Convex, CoordModeOrigin
+ );
+ }
+ XDrawLines( dpy,
+ win, w->clock.HighGC,
+ w->clock.hour, VERTICES_IN_HANDS,
+ CoordModeOrigin );
+
+ w->clock.sec = w->clock.segbuffptr;
+ }
+ if (w->clock.show_second_hand == TRUE) {
+ w->clock.segbuffptr = w->clock.sec;
+ DrawSecond(w,
+ w->clock.second_hand_length - 2,
+ w->clock.second_hand_width,
+ w->clock.minute_hand_length + 2,
+ tm.tm_sec * 12
+ );
+ if(w->clock.Hdpixel != w->core.background_pixel)
+ XFillPolygon( dpy,
+ win, w->clock.HandGC,
+ w->clock.sec,
+ VERTICES_IN_HANDS -2,
+ Convex, CoordModeOrigin
+ );
+ XDrawLines( dpy,
+ win, w->clock.HighGC,
+ w->clock.sec,
+ VERTICES_IN_HANDS-1,
+ CoordModeOrigin
+ );
+
+ }
+ w->clock.otm = tm;
+ }
+}
+
+static erase_hands (w, tm)
+ClockWidget w;
+struct tm *tm;
+{
+ /*
+ * Erase old hands.
+ */
+ if(w->clock.numseg > 0) {
+ Display *dpy;
+ Window win;
+
+ dpy = XtDisplay (w);
+ win = XtWindow (w);
+ if (w->clock.show_second_hand == TRUE) {
+ XDrawLines(dpy, win,
+ w->clock.EraseGC,
+ w->clock.sec,
+ VERTICES_IN_HANDS-1,
+ CoordModeOrigin);
+ if(w->clock.Hdpixel != w->core.background_pixel) {
+ XFillPolygon(dpy,
+ win, w->clock.EraseGC,
+ w->clock.sec,
+ VERTICES_IN_HANDS-2,
+ Convex, CoordModeOrigin
+ );
+ }
+ }
+ if(!tm || tm->tm_min != w->clock.otm.tm_min ||
+ tm->tm_hour != w->clock.otm.tm_hour)
+ {
+ XDrawLines( dpy, win,
+ w->clock.EraseGC,
+ w->clock.segbuff,
+ VERTICES_IN_HANDS,
+ CoordModeOrigin);
+ XDrawLines( dpy, win,
+ w->clock.EraseGC,
+ w->clock.hour,
+ VERTICES_IN_HANDS,
+ CoordModeOrigin);
+ if(w->clock.Hdpixel != w->core.background_pixel) {
+ XFillPolygon( dpy, win,
+ w->clock.EraseGC,
+ w->clock.segbuff, VERTICES_IN_HANDS,
+ Convex, CoordModeOrigin);
+ XFillPolygon( dpy, win,
+ w->clock.EraseGC,
+ w->clock.hour,
+ VERTICES_IN_HANDS,
+ Convex, CoordModeOrigin);
+ }
+ }
+ }
+}
+
+static float Const Sines[] = {
+.000000, .008727, .017452, .026177, .034899, .043619, .052336, .061049,
+.069756, .078459, .087156, .095846, .104528, .113203, .121869, .130526,
+.139173, .147809, .156434, .165048, .173648, .182236, .190809, .199368,
+.207912, .216440, .224951, .233445, .241922, .250380, .258819, .267238,
+.275637, .284015, .292372, .300706, .309017, .317305, .325568, .333807,
+.342020, .350207, .358368, .366501, .374607, .382683, .390731, .398749,
+.406737, .414693, .422618, .430511, .438371, .446198, .453990, .461749,
+.469472, .477159, .484810, .492424, .500000, .507538, .515038, .522499,
+.529919, .537300, .544639, .551937, .559193, .566406, .573576, .580703,
+.587785, .594823, .601815, .608761, .615661, .622515, .629320, .636078,
+.642788, .649448, .656059, .662620, .669131, .675590, .681998, .688355,
+.694658, .700909, .707107
+};
+
+static float Const Cosines[] = {
+1.00000, .999962, .999848, .999657, .999391, .999048, .998630, .998135,
+.997564, .996917, .996195, .995396, .994522, .993572, .992546, .991445,
+.990268, .989016, .987688, .986286, .984808, .983255, .981627, .979925,
+.978148, .976296, .974370, .972370, .970296, .968148, .965926, .963630,
+.961262, .958820, .956305, .953717, .951057, .948324, .945519, .942641,
+.939693, .936672, .933580, .930418, .927184, .923880, .920505, .917060,
+.913545, .909961, .906308, .902585, .898794, .894934, .891007, .887011,
+.882948, .878817, .874620, .870356, .866025, .861629, .857167, .852640,
+.848048, .843391, .838671, .833886, .829038, .824126, .819152, .814116,
+.809017, .803857, .798636, .793353, .788011, .782608, .777146, .771625,
+.766044, .760406, .754710, .748956, .743145, .737277, .731354, .725374,
+.719340, .713250, .707107
+};
+
+static void ClockAngle(tick_units, sinp, cosp)
+ int tick_units;
+ double *sinp, *cosp;
+{
+ int reduced, upper;
+
+ reduced = tick_units % 90;
+ upper = tick_units / 90;
+ if (upper & 1)
+ reduced = 90 - reduced;
+ if ((upper + 1) & 2) {
+ *sinp = Cosines[reduced];
+ *cosp = Sines[reduced];
+ } else {
+ *sinp = Sines[reduced];
+ *cosp = Cosines[reduced];
+ }
+ if (upper >= 2 && upper < 6)
+ *cosp = -*cosp;
+ if (upper >= 4)
+ *sinp = -*sinp;
+}
+
+/*
+ * DrawLine - Draws a line.
+ *
+ * blank_length is the distance from the center which the line begins.
+ * length is the maximum length of the hand.
+ * Tick_units is a number between zero and 12*60 indicating
+ * how far around the circle (clockwise) from high noon.
+ *
+ * The blank_length feature is because I wanted to draw tick-marks around the
+ * circle (for seconds). The obvious means of drawing lines from the center
+ * to the perimeter, then erasing all but the outside most pixels doesn't
+ * work because of round-off error (sigh).
+ */
+static void DrawLine(w, blank_length, length, tick_units)
+ClockWidget w;
+Dimension blank_length;
+Dimension length;
+int tick_units;
+{
+ double dblank_length = (double)blank_length, dlength = (double)length;
+ double cosangle, sinangle;
+ int cx = w->clock.centerX, cy = w->clock.centerY, x1, y1, x2, y2;
+
+ /*
+ * Angles are measured from 12 o'clock, clockwise increasing.
+ * Since in X, +x is to the right and +y is downward:
+ *
+ * x = x0 + r * sin(theta)
+ * y = y0 - r * cos(theta)
+ *
+ */
+ ClockAngle(tick_units, &sinangle, &cosangle);
+
+ /* break this out so that stupid compilers can cope */
+ x1 = cx + (int)(dblank_length * sinangle);
+ y1 = cy - (int)(dblank_length * cosangle);
+ x2 = cx + (int)(dlength * sinangle);
+ y2 = cy - (int)(dlength * cosangle);
+ SetSeg(w, x1, y1, x2, y2);
+}
+
+/*
+ * DrawHand - Draws a hand.
+ *
+ * length is the maximum length of the hand.
+ * width is the half-width of the hand.
+ * Tick_units is a number between zero and 12*60 indicating
+ * how far around the circle (clockwise) from high noon.
+ *
+ */
+static void DrawHand(w, length, width, tick_units)
+ClockWidget w;
+Dimension length, width;
+int tick_units;
+{
+
+ double cosangle, sinangle;
+ register double ws, wc;
+ Position x, y, x1, y1, x2, y2;
+
+ /*
+ * Angles are measured from 12 o'clock, clockwise increasing.
+ * Since in X, +x is to the right and +y is downward:
+ *
+ * x = x0 + r * sin(theta)
+ * y = y0 - r * cos(theta)
+ *
+ */
+ ClockAngle(tick_units, &sinangle, &cosangle);
+ /*
+ * Order of points when drawing the hand.
+ *
+ * 1,4
+ * / \
+ * / \
+ * / \
+ * 2 ------- 3
+ */
+ wc = width * cosangle;
+ ws = width * sinangle;
+ SetSeg(w,
+ x = w->clock.centerX + round(length * sinangle),
+ y = w->clock.centerY - round(length * cosangle),
+ x1 = w->clock.centerX - round(ws + wc),
+ y1 = w->clock.centerY + round(wc - ws)); /* 1 ---- 2 */
+ /* 2 */
+ SetSeg(w, x1, y1,
+ x2 = w->clock.centerX - round(ws - wc),
+ y2 = w->clock.centerY + round(wc + ws)); /* 2 ----- 3 */
+
+ SetSeg(w, x2, y2, x, y); /* 3 ----- 1(4) */
+}
+
+/*
+ * DrawSecond - Draws the second hand (diamond).
+ *
+ * length is the maximum length of the hand.
+ * width is the half-width of the hand.
+ * offset is direct distance from center to tail end.
+ * Tick_units is a number between zero and 12*60 indicating
+ * how far around the circle (clockwise) from high noon.
+ *
+ */
+static void DrawSecond(w, length, width, offset, tick_units)
+ClockWidget w;
+Dimension length, width, offset;
+int tick_units;
+{
+
+ double cosangle, sinangle;
+ register double ms, mc, ws, wc;
+ register int mid;
+ Position x, y;
+
+ /*
+ * Angles are measured from 12 o'clock, clockwise increasing.
+ * Since in X, +x is to the right and +y is downward:
+ *
+ * x = x0 + r * sin(theta)
+ * y = y0 - r * cos(theta)
+ *
+ */
+ ClockAngle(tick_units, &sinangle, &cosangle);
+ /*
+ * Order of points when drawing the hand.
+ *
+ * 1,5
+ * / \
+ * / \
+ * / \
+ * 2< >4
+ * \ /
+ * \ /
+ * \ /
+ * - 3
+ * |
+ * |
+ * offset
+ * |
+ * |
+ * - + center
+ */
+
+ mid = (int) (length + offset) / 2;
+ mc = mid * cosangle;
+ ms = mid * sinangle;
+ wc = width * cosangle;
+ ws = width * sinangle;
+ /*1 ---- 2 */
+ SetSeg(w,
+ x = w->clock.centerX + round(length * sinangle),
+ y = w->clock.centerY - round(length * cosangle),
+ w->clock.centerX + round(ms - wc),
+ w->clock.centerY - round(mc + ws) );
+ SetSeg(w, w->clock.centerX + round(offset *sinangle),
+ w->clock.centerY - round(offset * cosangle), /* 2-----3 */
+ w->clock.centerX + round(ms + wc),
+ w->clock.centerY - round(mc - ws));
+ w->clock.segbuffptr->x = x;
+ w->clock.segbuffptr++->y = y;
+ w->clock.numseg ++;
+}
+
+static void SetSeg(w, x1, y1, x2, y2)
+ClockWidget w;
+int x1, y1, x2, y2;
+{
+ w->clock.segbuffptr->x = x1;
+ w->clock.segbuffptr++->y = y1;
+ w->clock.segbuffptr->x = x2;
+ w->clock.segbuffptr++->y = y2;
+ w->clock.numseg += 2;
+}
+
+/*
+ * Draw the clock face (every fifth tick-mark is longer
+ * than the others).
+ */
+static void DrawClockFace(w)
+ClockWidget w;
+{
+ register int i;
+ register int delta = (int)(w->clock.radius - w->clock.second_hand_length) / 3;
+
+ w->clock.segbuffptr = w->clock.segbuff;
+ w->clock.numseg = 0;
+ for (i = 0; i < 60; i++)
+ DrawLine(w, ( (i % 5) == 0 ?
+ w->clock.second_hand_length :
+ (w->clock.radius - delta) ),
+ w->clock.radius, i * 12);
+ /*
+ * Go ahead and draw it.
+ */
+ XDrawSegments(XtDisplay(w), XtWindow(w),
+ w->clock.myGC, (XSegment *) &(w->clock.segbuff[0]),
+ w->clock.numseg/2);
+
+ w->clock.segbuffptr = w->clock.segbuff;
+ w->clock.numseg = 0;
+}
+
+static int round(x)
+double x;
+{
+ return(x >= 0.0 ? (int)(x + .5) : (int)(x - .5));
+}
+
+/* ARGSUSED */
+static Boolean SetValues (gcurrent, grequest, gnew, args, num_args)
+ Widget gcurrent, grequest, gnew;
+ ArgList args;
+ Cardinal *num_args;
+{
+ ClockWidget current = (ClockWidget) gcurrent;
+ ClockWidget new = (ClockWidget) gnew;
+ Boolean redisplay = FALSE;
+ XtGCMask valuemask;
+ XGCValues myXGCV;
+
+ /* first check for changes to clock-specific resources. We'll accept all
+ the changes, but may need to do some computations first. */
+
+ if (new->clock.update != current->clock.update) {
+ if (current->clock.interval_id)
+ XtRemoveTimeOut (current->clock.interval_id);
+ if (XtIsRealized( (Widget) new))
+ new->clock.interval_id = XtAppAddTimeOut(
+ XtWidgetToApplicationContext(gnew),
+ new->clock.update*1000,
+ clock_tic, (XtPointer)gnew);
+
+ new->clock.show_second_hand =(new->clock.update <= SECOND_HAND_TIME);
+ }
+
+ if (new->clock.padding != current->clock.padding)
+ redisplay = TRUE;
+
+ if (new->clock.analog != current->clock.analog)
+ redisplay = TRUE;
+
+ if (new->clock.font != current->clock.font)
+ redisplay = TRUE;
+
+ if ((new->clock.fgpixel != current->clock.fgpixel)
+ || (new->core.background_pixel != current->core.background_pixel)) {
+ valuemask = GCForeground | GCBackground | GCFont | GCLineWidth;
+ myXGCV.foreground = new->clock.fgpixel;
+ myXGCV.background = new->core.background_pixel;
+ myXGCV.font = new->clock.font->fid;
+ myXGCV.line_width = 0;
+ XtReleaseGC (gcurrent, current->clock.myGC);
+ new->clock.myGC = XtGetGC(gcurrent, valuemask, &myXGCV);
+ redisplay = TRUE;
+ }
+
+ if (new->clock.Hipixel != current->clock.Hipixel) {
+ valuemask = GCForeground | GCLineWidth;
+ myXGCV.foreground = new->clock.Hipixel;
+ myXGCV.font = new->clock.font->fid;
+ myXGCV.line_width = 0;
+ XtReleaseGC (gcurrent, current->clock.HighGC);
+ new->clock.HighGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV);
+ redisplay = TRUE;
+ }
+
+ if (new->clock.Hdpixel != current->clock.Hdpixel) {
+ valuemask = GCForeground;
+ myXGCV.foreground = new->clock.Hdpixel;
+ XtReleaseGC (gcurrent, current->clock.HandGC);
+ new->clock.HandGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV);
+ redisplay = TRUE;
+ }
+
+ if (new->core.background_pixel != current->core.background_pixel) {
+ valuemask = GCForeground | GCLineWidth;
+ myXGCV.foreground = new->core.background_pixel;
+ myXGCV.line_width = 0;
+ XtReleaseGC (gcurrent, current->clock.EraseGC);
+ new->clock.EraseGC = XtGetGC((Widget)gcurrent, valuemask, &myXGCV);
+ redisplay = TRUE;
+ }
+
+ return (redisplay);
+
+}