diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:53 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:53 +0000 |
commit | 7fa20e0899cf53cbb6d386d0688127df8b6fb0c7 (patch) | |
tree | 2a47ff68a964eb21a7cb24420e7d3183bfa9720f /Clock.c |
R6.6 is the Xorg base-lineXORG-MAIN
Diffstat (limited to 'Clock.c')
-rw-r--r-- | Clock.c | 882 |
1 files changed, 882 insertions, 0 deletions
@@ -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); + +} |