summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Clock.c154
-rw-r--r--ClockP.h3
2 files changed, 109 insertions, 48 deletions
diff --git a/Clock.c b/Clock.c
index 35416d4..fefe0a8 100644
--- a/Clock.c
+++ b/Clock.c
@@ -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,
diff --git a/ClockP.h b/ClockP.h
index f8c84ee..632b65e 100644
--- a/ClockP.h
+++ b/ClockP.h
@@ -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