diff options
-rw-r--r-- | Clock.c | 154 | ||||
-rw-r--r-- | ClockP.h | 3 |
2 files changed, 109 insertions, 48 deletions
@@ -145,8 +145,8 @@ static XtResource resources[] = { 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 }, + {XtNupdate, XtCInterval, XtRFloat, sizeof(float), + offset(update), XtRString, "60.0" }, #ifndef XRENDER {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), offset(fgpixel), XtRString, XtDefaultForeground}, @@ -584,7 +584,7 @@ Initialize (Widget request, Widget new, ArgList args, Cardinal *num_args) if(!w->clock.analog) { char *str; struct tm tm; - Time_t time_value; + struct timeval tv; int len; #ifndef NO_I18N @@ -612,8 +612,8 @@ Initialize (Widget request, Widget new, ArgList args, Cardinal *num_args) } #endif /* NO_I18N */ - (void) time(&time_value); - tm = *localtime(&time_value); + (void) gettimeofday(&tv, NULL); + tm = *localtime(&tv.tv_sec); str = TimeString (w, &tm); len = strlen(str); if (len && str[len - 1] == '\n') str[--len] = '\0'; @@ -724,7 +724,7 @@ Initialize (Widget request, Widget new, ArgList args, Cardinal *num_args) /* make invalid update's use a default */ /*if (w->clock.update <= 0) w->clock.update = 60;*/ - w->clock.show_second_hand = (abs(w->clock.update) <= SECOND_HAND_TIME); + w->clock.show_second_hand = (abs((int) w->clock.update) <= SECOND_HAND_TIME); w->clock.numseg = 0; w->clock.interval_id = 0; memset (&w->clock.otm, '\0', sizeof (w->clock.otm)); @@ -1089,15 +1089,21 @@ RenderHands (ClockWidget w, struct tm *tm, Boolean draw) } static void -RenderSec (ClockWidget w, struct tm *tm, Boolean draw) +RenderSec (ClockWidget w, struct tm *tm, struct timeval *tv, Boolean draw) { double c, s; XPointDouble poly[10]; double inner_x, middle_x, outer_x, far_x; double middle_y; double line_y; + double sec; - ClockAngle (tm->tm_sec * 60, &c, &s); + sec = tm->tm_sec; + + if (w->clock.update < 1.0) + sec += tv->tv_usec / 1000000.0; + + ClockAngle ((int) (sec * 60.0), &c, &s); s = -s; @@ -1248,6 +1254,69 @@ Redisplay(Widget gw, XEvent *event, Region region) clock_tic((XtPointer)w, (XtIntervalId *)NULL); } +#define USEC_MILLIS(us) ((unsigned long) (us) / 1000) +#define SEC_MILLIS(s) ((unsigned long) (s) * 1000) +#define MIN_MILLIS(m) SEC_MILLIS((unsigned long) (m) * 60) +#define HOUR_MILLIS(h) MIN_MILLIS((unsigned long) (h) * 60) +#define DAY_MILLIS HOUR_MILLIS((unsigned long) 24) + +#define MIN_SECS(m) ((unsigned long) (m) * 60) +#define HOUR_SECS(h) MIN_SECS((unsigned long) (h) * 60) + +/* Seconds since midnight */ +static unsigned long +time_seconds(struct tm *tm) +{ + return HOUR_SECS(tm->tm_hour) + MIN_SECS(tm->tm_min) + tm->tm_sec; +} + +/* Milliseconds since midnight */ +static unsigned long +time_millis(struct tm *tm, struct timeval *tv) +{ + return time_seconds(tm) * 1000 + USEC_MILLIS(tv->tv_usec); +} + +/* Round milliseconds to number of intervals (measured in milliseconds) */ +static unsigned long +time_intervals(unsigned long millis, unsigned long interval) +{ + return (millis + interval / 2) / interval; +} + +/* + * Round the current time to the nearest update interval using + * milliseconds since midnight + */ +static void +round_time(float _update, struct tm *tm, struct timeval *tv) +{ + /* interval in milliseconds */ + unsigned long update = (int) (_update * 1000.0 + 0.5); + + /* compute milliseconds since midnight */ + unsigned long old_secs = time_seconds(tm); + unsigned long old_millis = time_millis(tm, tv); + + /* Nearest number of intervals since midnight */ + unsigned long intervals = time_intervals(old_millis, update); + + /* The number of milliseconds for that number of intervals */ + unsigned long new_millis = intervals * update; + time_t t; + + if (new_millis > DAY_MILLIS) + new_millis = DAY_MILLIS; + + /* Compute the time_t of that interval by subtracting off the real + * seconds and adding back in the desired second + */ + + t = tv->tv_sec - old_secs + new_millis / 1000; + *tm = *localtime(&t); + tv->tv_usec = (new_millis % 1000) * 1000; +} + /* Choose the update times for well-defined clock states. * * For example, in HH:MM:SS notation the last number rolls over @@ -1328,36 +1397,22 @@ Redisplay(Widget gw, XEvent *event, Region region) * The code below implements (2) with n this year's duration in seconds * and using local time year's start as epoch. */ + static unsigned long -waittime(int update, struct timeval *tv, struct tm *tm) +waittime(float _update, struct timeval *tv, struct tm *tm) { - int twait; - long twaitms; - unsigned long retval; - - if(update>0) { - long tcur; - int trem; - - tcur=tm->tm_sec+60*(tm->tm_min+60*(tm->tm_hour+24*tm->tm_yday)); - /* ti=floor(tcur/u)*u, w=u-(tcur-ti), and tcur-ti==tcur % u */ - trem=tcur % update; - twait=update-trem; - } else { - twait=-update; - } - - if(tv->tv_usec>0) { - long usec; - twait--; - usec=1000000-tv->tv_usec; - twaitms=(usec+999)/1000; /* must round up to avoid zero retval */ - } else { - twaitms=0; - } - - retval=(unsigned long)labs(twaitms+1000*twait); - return retval; + unsigned long update_millis = (unsigned long) (_update * 1000 + 0.5); + unsigned long millis = time_millis(tm, tv); + unsigned long intervals = time_intervals(millis, update_millis); + unsigned long next = intervals + 1; + unsigned long next_millis = next * update_millis; + unsigned long result; + + if (next_millis > DAY_MILLIS) + next_millis = DAY_MILLIS; + + result = next_millis - millis; + return result; } /* ARGSUSED */ @@ -1366,20 +1421,20 @@ clock_tic(XtPointer client_data, XtIntervalId *id) { ClockWidget w = (ClockWidget)client_data; struct tm tm; - Time_t time_value; struct timeval tv; char *time_ptr; register Display *dpy = XtDisplay(w); register Window win = XtWindow(w); X_GETTIMEOFDAY (&tv); - time_value = tv.tv_sec; - tm = *localtime(&time_value); + tm = *localtime(&tv.tv_sec); if (w->clock.update && (id || !w->clock.interval_id)) w->clock.interval_id = XtAppAddTimeOut( XtWidgetToApplicationContext( (Widget) w), waittime(w->clock.update, &tv, &tm), clock_tic, (XtPointer)w ); + + round_time(w->clock.update, &tm, &tv); /* * Beep on the half hour; double-beep on the hour. */ @@ -1554,10 +1609,11 @@ clock_tic(XtPointer client_data, XtIntervalId *id) RenderHands (w, &tm, False); } if (w->clock.show_second_hand && - tm.tm_sec != w->clock.otm.tm_sec) + tm.tm_sec != w->clock.otm.tm_sec || + tv.tv_usec != w->clock.otv.tv_usec) { - RenderSec (w, &w->clock.otm, False); - RenderSec (w, &tm, False); + RenderSec (w, &w->clock.otm, &w->clock.otv, False); + RenderSec (w, &tm, &tv, False); } if (w->clock.damage.width && w->clock.damage.height) @@ -1566,9 +1622,10 @@ clock_tic(XtPointer client_data, XtIntervalId *id) DrawClockFace (w); RenderHands (w, &tm, True); if (w->clock.show_second_hand == TRUE) - RenderSec (w, &tm, True); + RenderSec (w, &tm, &tv, True); } w->clock.otm = tm; + w->clock.otv = tv; RenderUpdate (w); RenderResetBounds (&w->clock.damage); return; @@ -1579,7 +1636,8 @@ clock_tic(XtPointer client_data, XtIntervalId *id) if (w->clock.numseg == 0 || tm.tm_min != w->clock.otm.tm_min || - tm.tm_hour != w->clock.otm.tm_hour) { + tm.tm_hour != w->clock.otm.tm_hour || + tm.tm_sec != w->clock.otm.tm_sec) { w->clock.segbuffptr = w->clock.segbuff; w->clock.numseg = 0; /* @@ -1590,7 +1648,7 @@ clock_tic(XtPointer client_data, XtIntervalId *id) */ DrawHand(w, w->clock.minute_hand_length, w->clock.hand_width, - tm.tm_min * 60 + tm.tm_min * 60 + tm.tm_sec ); if(w->clock.Hdpixel != w->core.background_pixel) XFillPolygon( dpy, @@ -1628,7 +1686,7 @@ clock_tic(XtPointer client_data, XtIntervalId *id) w->clock.second_hand_length - 2, w->clock.second_hand_width, w->clock.minute_hand_length + 2, - tm.tm_sec * 60 + tm.tm_sec * 60 + tv.tv_usec * 60 / 1000000 ); if(w->clock.Hdpixel != w->core.background_pixel) XFillPolygon( dpy, @@ -1646,6 +1704,7 @@ clock_tic(XtPointer client_data, XtIntervalId *id) } w->clock.otm = tm; + w->clock.otv = tv; } } @@ -1677,7 +1736,8 @@ erase_hands(ClockWidget w, struct tm *tm) } } if(!tm || tm->tm_min != w->clock.otm.tm_min || - tm->tm_hour != w->clock.otm.tm_hour) + tm->tm_hour != w->clock.otm.tm_hour || + tm->tm_sec != w->clock.otm.tm_sec) { XDrawLines( dpy, win, w->clock.EraseGC, @@ -85,7 +85,7 @@ typedef struct { GC HandGC; /* Hand GC */ GC HighGC; /* Highlighting GC */ /* start of graph stuff */ - int update; /* update period in second */ + float update; /* update period in second */ Dimension radius; /* radius factor */ int backing_store; /* backing store type */ Boolean chime; @@ -109,6 +109,7 @@ typedef struct { XPoint *segbuffptr; XPoint *hour, *sec; struct tm otm ; + struct timeval otv ; XtIntervalId interval_id; char prev_time_string[STRFTIME_BUFF_SIZE]; #ifndef NO_I18N |