+
+#define TIMER_INTERVAL_MS 100
+
+static void
+grr_board_view_refresh_timer (grr_board_view_t *view)
+{
+ int x, y;
+
+ grr_board_view_transform_cell_to_pixel (view,
+ view->board_width / 2 - 1,
+ view->board_height / 2 -1,
+ &x, &y);
+ gtk_widget_queue_draw_area (GTK_WIDGET (view),
+ x, y,
+ 2 * view->cell_width,
+ 2 * view->cell_height);
+}
+
+static gboolean
+grr_board_view_decrement_timer (void *widget)
+{
+ grr_board_view_t *view = widget;
+
+ view->time -= TIMER_INTERVAL_MS / 1000.0;
+ view->time += view->drift_correct;
+
+ grr_board_view_refresh_timer (view);
+
+ return TRUE;
+}
+
+void
+grr_board_view_start_timer (grr_board_view_t *view, double time)
+{
+ /* XXX: It would be good to adjust the clock for latency somewhere... */
+ /* Correct any drift within the next 10 seconds, or half the
+ remaining time --- whichever is less. */
+ if (view->timer) {
+ double correction_time;
+ if (time >= 20.0)
+ correction_time = 10.0;
+ else
+ correction_time = time / 2.0;
+ view->drift_correct = (time - view->time) / (correction_time * TIMER_INTERVAL_MS);
+ } else {
+ view->time = time;
+
+ view->timer = gtk_timeout_add (TIMER_INTERVAL_MS, grr_board_view_decrement_timer, view);
+ }
+}
+
+void
+grr_board_view_stop_timer (grr_board_view_t *view)
+{
+ if (view->timer == 0)
+ return;
+
+ gtk_timeout_remove (view->timer);
+ view->timer = 0;
+ view->time = 0.0;
+
+ grr_board_view_refresh_timer (view);
+}
+
+void
+grr_board_view_reset_timer (grr_board_view_t *view)
+{
+ grr_board_view_stop_timer (view);
+
+ view->time = 60.0;
+ view->drift_correct = 0.0;
+}