From 3855f25de17c1a4b11e63a639ab387efb576271c Mon Sep 17 00:00:00 2001
From: Marty Jack <martyj@linux.local>
Date: Thu, 4 Mar 2010 09:05:42 -0500
Subject: [PATCH 10/23] Improve clock poll interval for format strings that do not change every second (Bug2923562).
---
src/plugins/dclock.c | 137 ++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 110 insertions(+), 27 deletions(-)
diff --git a/src/plugins/dclock.c b/src/plugins/dclock.c
index fffefcd..6b0e4fa 100644
--- a/src/plugins/dclock.c
+++ b/src/plugins/dclock.c
@@ -45,12 +45,21 @@ typedef struct {
gboolean bold; /* True if bold font */
gboolean icon_only; /* True if icon only (no clock value) */
guint timer; /* Timer for periodic update */
- char * prev_output; /* Previous value of clock */
+ enum {
+ AWAITING_FIRST_CHANGE, /* Experimenting to determine interval, waiting for first change */
+ AWAITING_SECOND_CHANGE, /* Experimenting to determine interval, waiting for second change */
+ ONE_SECOND_INTERVAL, /* Determined that one second interval is necessary */
+ ONE_MINUTE_INTERVAL /* Determined that one minute interval is sufficient */
+ } expiration_interval;
+ int experiment_count; /* Count of experiments that have been done to determine interval */
+ char * prev_clock_value; /* Previous value of clock */
+ char * prev_tooltip_value; /* Previous value of tooltip */
} DClockPlugin;
static void dclock_popup_map(GtkWidget * widget, DClockPlugin * dc);
static GtkWidget * dclock_create_calendar(DClockPlugin * dc);
static gboolean dclock_button_press_event(GtkWidget * widget, GdkEventButton * evt, Plugin * plugin);
+static void dclock_timer_set(DClockPlugin * dc);
static gboolean dclock_update_display(DClockPlugin * dc);
static int dclock_constructor(Plugin * p, char ** fp);
static void dclock_destructor(Plugin * p);
@@ -126,6 +135,28 @@ static gboolean dclock_button_press_event(GtkWidget * widget, GdkEventButton * e
return TRUE;
}
+/* Set the timer. */
+static void dclock_timer_set(DClockPlugin * dc)
+{
+ /* Get current time to millisecond resolution. */
+ int milliseconds = 1000;
+ struct timeval current_time;
+ if (gettimeofday(¤t_time, NULL) >= 0)
+ {
+ /* Compute number of milliseconds until next second boundary. */
+ milliseconds = 1000 - (current_time.tv_usec / 1000);
+
+ /* If the expiration interval is the minute boundary,
+ * add number of milliseconds after that until next minute boundary. */
+ if (dc->expiration_interval == ONE_MINUTE_INTERVAL)
+ {
+ time_t seconds = 60 - (current_time.tv_sec - (current_time.tv_sec / 60) * 60) - 1;
+ milliseconds += seconds * 1000;
+ }
+ }
+ dc->timer = g_timeout_add(milliseconds, (GSourceFunc) dclock_update_display, (gpointer) dc);
+}
+
/* Periodic timer callback.
* Also used during initialization and configuration change to do a redraw. */
static gboolean dclock_update_display(DClockPlugin * dc)
@@ -133,29 +164,28 @@ static gboolean dclock_update_display(DClockPlugin * dc)
/* Determine the current time. */
time_t now;
time(&now);
- struct tm * detail = localtime(&now);
+ struct tm * current_time = localtime(&now);
- /* Determine the content of the clock label. */
- char output[64];
- strftime(output, sizeof(output),
- ((dc->clock_format != NULL) ? dc->clock_format : DEFAULT_CLOCK_FORMAT), detail);
+ /* Determine the content of the clock label and tooltip. */
+ char clock_value[64];
+ char tooltip_value[64];
+ strftime(clock_value, sizeof(clock_value), dc->clock_format, current_time);
+ strftime(tooltip_value, sizeof(tooltip_value), dc->tooltip_format, current_time);
/* When we write the clock value, it causes the panel to do a full relayout.
- * Since this function is called once per second, we take the trouble to check if the string actually changed first. */
+ * Since this function may be called too often while the timing experiment is underway,
+ * we take the trouble to check if the string actually changed first. */
if (( ! dc->icon_only)
- && ((dc->prev_output == NULL) || (strcmp(dc->prev_output, output) != 0)))
+ && ((dc->prev_clock_value == NULL) || (strcmp(dc->prev_clock_value, clock_value) != 0)))
{
- g_free(dc->prev_output);
- dc->prev_output = g_strdup(output);
-
/* Convert "\n" escapes in the user's format string to newline characters. */
char * newlines_converted = NULL;
- if (strstr(output, "\\n") != NULL)
+ if (strstr(clock_value, "\\n") != NULL)
{
- newlines_converted = g_strdup(output); /* Just to get enough space for the converted result */
+ newlines_converted = g_strdup(clock_value); /* Just to get enough space for the converted result */
char * p;
char * q;
- for (p = output, q = newlines_converted; *p != '\0'; p += 1)
+ for (p = clock_value, q = newlines_converted; *p != '\0'; p += 1)
{
if ((p[0] == '\\') && (p[1] == 'n'))
{
@@ -168,7 +198,7 @@ static gboolean dclock_update_display(DClockPlugin * dc)
*q = '\0';
}
- gchar * utf8 = g_locale_to_utf8(((newlines_converted != NULL) ? newlines_converted : output), -1, NULL, NULL, NULL);
+ gchar * utf8 = g_locale_to_utf8(((newlines_converted != NULL) ? newlines_converted : clock_value), -1, NULL, NULL, NULL);
if (utf8 != NULL)
{
panel_draw_label_text(dc->plugin->panel, dc->clock_label, utf8, dc->bold, TRUE);
@@ -178,15 +208,66 @@ static gboolean dclock_update_display(DClockPlugin * dc)
}
/* Determine the content of the tooltip. */
- strftime(output, sizeof(output),
- ((dc->tooltip_format != NULL) ? dc->tooltip_format : DEFAULT_TIP_FORMAT), detail);
- gchar * utf8 = g_locale_to_utf8(output, -1, NULL, NULL, NULL);
+ gchar * utf8 = g_locale_to_utf8(tooltip_value, -1, NULL, NULL, NULL);
if (utf8 != NULL)
{
gtk_widget_set_tooltip_text(dc->plugin->pwid, utf8);
g_free(utf8);
}
- return TRUE;
+
+ /* Conduct an experiment to see how often the value changes.
+ * Use this to decide whether we update the value every second or every minute.
+ * We need to account for the possibility that the experiment is being run when we cross a minute boundary. */
+ if (dc->expiration_interval < ONE_SECOND_INTERVAL)
+ {
+ if (dc->prev_clock_value == NULL)
+ {
+ /* Initiate the experiment. */
+ dc->prev_clock_value = g_strdup(clock_value);
+ dc->prev_tooltip_value = g_strdup(tooltip_value);
+ }
+ else
+ {
+ if ((strcmp(dc->prev_clock_value, clock_value) == 0)
+ && (strcmp(dc->prev_tooltip_value, tooltip_value) == 0))
+ {
+ dc->experiment_count += 1;
+ if (dc->experiment_count > 3)
+ {
+ /* No change within 3 seconds. Assume change no more often than once per minute. */
+ dc->expiration_interval = 60;
+ g_free(dc->prev_clock_value);
+ g_free(dc->prev_tooltip_value);
+ dc->prev_clock_value = NULL;
+ dc->prev_tooltip_value = NULL;
+ }
+ }
+ else if (dc->expiration_interval == AWAITING_FIRST_CHANGE)
+ {
+ /* We have a change at the beginning of the experiment, but we do not know when the next change might occur.
+ * Continue the experiment for 3 more seconds. */
+ dc->expiration_interval = AWAITING_SECOND_CHANGE;
+ dc->experiment_count = 0;
+ g_free(dc->prev_clock_value);
+ g_free(dc->prev_tooltip_value);
+ dc->prev_clock_value = g_strdup(clock_value);
+ dc->prev_tooltip_value = g_strdup(tooltip_value);
+ }
+ else
+ {
+ /* We have a second change. End the experiment. */
+ dc->expiration_interval = ((dc->experiment_count > 3) ? 60 : 1);
+ g_free(dc->prev_clock_value);
+ g_free(dc->prev_tooltip_value);
+ dc->prev_clock_value = NULL;
+ dc->prev_tooltip_value = NULL;
+ }
+ }
+ }
+
+ /* Reset the timer and return. */
+ dclock_timer_set(dc);
+ return FALSE;
}
/* Plugin constructor. */
@@ -252,12 +333,13 @@ static int dclock_constructor(Plugin * p, char ** fp)
/* Connect signals. */
g_signal_connect(G_OBJECT (p->pwid), "button_press_event", G_CALLBACK(dclock_button_press_event), (gpointer) p);
- /* Initialize the clock display */
+ /* Initialize the clock display. */
+ if (dc->clock_format == NULL)
+ dc->clock_format = g_strdup(DEFAULT_CLOCK_FORMAT);
+ if (dc->tooltip_format == NULL)
+ dc->tooltip_format = g_strdup(DEFAULT_TIP_FORMAT);
dclock_apply_configuration(p);
- /* Start a timer to refresh the clock display. */
- dc->timer = g_timeout_add(1000, (GSourceFunc) dclock_update_display, (gpointer) dc);
-
/* Show the widget and return. */
gtk_widget_show(p->pwid);
return 1;
@@ -280,7 +362,8 @@ static void dclock_destructor(Plugin * p)
g_free(dc->clock_format);
g_free(dc->tooltip_format);
g_free(dc->action);
- g_free(dc->prev_output);
+ g_free(dc->prev_clock_value);
+ g_free(dc->prev_tooltip_value);
g_free(dc);
}
@@ -302,9 +385,9 @@ static void dclock_apply_configuration(Plugin * p)
gtk_widget_hide(dc->clock_icon);
}
- /* Update the display. */
- g_free(dc->prev_output); /* Force the update of the clock display */
- dc->prev_output = NULL;
+ /* Rerun the experiment to determine update interval and update the display. */
+ dc->expiration_interval = AWAITING_FIRST_CHANGE;
+ dc->experiment_count = 0;
dclock_update_display(dc);
/* Hide the calendar. */
--
1.6.6.1