[california] Update current date when date changes: Closes bgo#726139
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california] Update current date when date changes: Closes bgo#726139
- Date: Thu, 20 Mar 2014 23:50:22 +0000 (UTC)
commit abf84e744e1d7252ddd13c225427c9fbc97bdf43
Author: Jim Nelson <jim yorba org>
Date: Thu Mar 20 16:47:30 2014 -0700
Update current date when date changes: Closes bgo#726139
Detecting if the current date has changed is done through two
mechanisms: (a) if the timezone changes and that change results in
a date change, and (b) polling the system clock occassionally for
a date change. The second feels wasteful but there's no system
event I can locate that will inform an app when the date has changed
and don't want to poll too infrequently in case the user/NTP updates
the clock manually.
src/calendar/calendar-date.vala | 14 +++++-
src/calendar/calendar-exact-time.vala | 9 ++++
src/calendar/calendar-system.vala | 82 +++++++++++++++++++++++++++++---
src/host/host-main-window.vala | 3 +-
src/host/host-show-event.vala | 2 +
src/view/month/month-cell.vala | 8 +++
src/view/month/month-controllable.vala | 16 ++++++-
src/view/view-controllable.vala | 3 +
8 files changed, 127 insertions(+), 10 deletions(-)
---
diff --git a/src/calendar/calendar-date.vala b/src/calendar/calendar-date.vala
index a401342..65b7b2c 100644
--- a/src/calendar/calendar-date.vala
+++ b/src/calendar/calendar-date.vala
@@ -34,7 +34,12 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
/**
* Indicates that the year should be included in the return date string.
*/
- INCLUDE_YEAR
+ INCLUDE_YEAR,
+ /**
+ * Indicates that the localized string for "Today" should not be used if the date matches
+ * { link System.today}.
+ */
+ NO_TODAY
}
public DayOfWeek day_of_week { get; private set; }
@@ -276,10 +281,17 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
/**
* Returns the { link Date} in a prettified, localized format according to supplied
* { link PrettyFlag}s.
+ *
+ * Returns "Today" (localized) if this matches { link System.today} unless the NO_TODAY flag
+ * or INCLUDE_YEAR flag is specified.
*/
public string to_pretty_string(PrettyFlag flags) {
bool abbrev = (flags & PrettyFlag.ABBREV) != 0;
bool with_year = (flags & PrettyFlag.INCLUDE_YEAR) != 0;
+ bool no_today = (flags & PrettyFlag.NO_TODAY) != 0;
+
+ if (!no_today && !with_year && equal_to(System.today))
+ return _("Today");
unowned string fmt;
if (abbrev)
diff --git a/src/calendar/calendar-exact-time.vala b/src/calendar/calendar-exact-time.vala
index 74078cd..518a2dc 100644
--- a/src/calendar/calendar-exact-time.vala
+++ b/src/calendar/calendar-exact-time.vala
@@ -153,6 +153,15 @@ public class ExactTime : BaseObject, Gee.Comparable<ExactTime>, Gee.Hashable<Exa
}
/**
+ * Returns the difference (in seconds) between this { link ExactTime} and another ExactTime.
+ *
+ * If the supplied ExactTime is earlier than this one, a negative value will be returned.
+ */
+ public int64 difference(ExactTime other) {
+ return date_time.difference(other.date_time) / TimeSpan.SECOND;
+ }
+
+ /**
* See DateTime.to_unix_time.
*/
public time_t to_time_t() {
diff --git a/src/calendar/calendar-system.vala b/src/calendar/calendar-system.vala
index be1558b..8bd745e 100644
--- a/src/calendar/calendar-system.vala
+++ b/src/calendar/calendar-system.vala
@@ -20,12 +20,16 @@ public class System : BaseObject {
private const string CLOCK_FORMAT_KEY = "clock-format";
private const string CLOCK_FORMAT_24H = "24h";
+ private const int CHECK_DATE_PRIORITY = Priority.LOW;
+ private const int MIN_CHECK_DATE_INTERVAL_SEC = 1;
+ private const int MAX_CHECK_DATE_INTERVAL_SEC = 30;
+
public static System instance { get; private set; }
/**
* The current date according to the local timezone.
*
- * TODO: This currently does not update as the program executes.
+ * @see today_changed
*/
public static Date today { get; private set; }
@@ -60,6 +64,14 @@ public class System : BaseObject {
private static DBus.Properties timedated_properties;
/**
+ * Fired when { link today} changes.
+ *
+ * This indicates that the system time has crossed midnight (potentially either direction since
+ * clock adjustments can happen for a variety of reasons).
+ */
+ public signal void today_changed(Calendar.Date old_today, Calendar.Date new_today);
+
+ /**
* Fired when { link is_24hr} changes.
*
* This means the user has changed the their clock format configuration.
@@ -72,14 +84,15 @@ public class System : BaseObject {
* This generally indicates that the user has changed system time zone manually or that the
* system detected the change through geolocation services.
*/
- public signal void zone_changed(OlsonZone new_zone);
+ public signal void zone_changed(OlsonZone old_zone, OlsonZone new_zone);
/**
* Fired when { link local_timezone} changes due to system configuration changes.
*/
- public signal void timezone_changed(Timezone new_timezone);
+ public signal void timezone_changed(Timezone old_timezone, Timezone new_timezone);
private Settings system_clock_format_schema = new Settings(CLOCK_FORMAT_SCHEMA);
+ private uint date_timer_id = 0;
private System() {
zone = new OlsonZone(timedated_service.timezone);
@@ -89,6 +102,7 @@ public class System : BaseObject {
// to be notified of changes as they occur
timedated_properties.properties_changed.connect(on_timedated_properties_changed);
+ // monitor 12/24-hr setting for changes and update
is_24hr = system_clock_format_schema.get_string(CLOCK_FORMAT_KEY) == CLOCK_FORMAT_24H;
system_clock_format_schema.changed[CLOCK_FORMAT_KEY].connect(() => {
bool new_is_24hr = system_clock_format_schema.get_string(CLOCK_FORMAT_KEY) == CLOCK_FORMAT_24H;
@@ -98,8 +112,19 @@ public class System : BaseObject {
}
});
- // TODO: Tie this into the event loop so it's properly updated
+ // timezone change can potentially update "today"; unless there's a system event we can
+ // trap to indicate when the date has changed, use the event loop to check once every so
+ // often, but also attempt to calculate time until midnight to change along with it ...
+ // this may seem wasteful, but since the date can change for a lot of reasons (user
+ // intervention, clock drift, NTP, etc.) this is a simple way to stay on top of things
today = new Date.now(Timezone.local);
+ date_timer_id = Timeout.add_seconds_full(CHECK_DATE_PRIORITY, next_check_today_interval_sec(),
+ check_today_changed);
+ }
+
+ ~System() {
+ if (date_timer_id != 0)
+ Source.remove(date_timer_id);
}
internal static void preinit() throws IOError {
@@ -123,17 +148,60 @@ public class System : BaseObject {
HashTable<string, Variant> changed_properties_values, string[] changed_properties) {
if (changed_properties_values.contains(DBus.timedated.PROP_TIMEZONE)
|| DBus.timedated.PROP_TIMEZONE in changed_properties) {
+ OlsonZone old_zone = zone;
zone = new OlsonZone(timedated_service.timezone);
- timezone = new Timezone(zone);
debug("New local zone: %s", zone.to_string());
+ Timezone old_timezone = timezone;
+ timezone = new Timezone(zone);
+
// fire signals last in case a subscriber monitoring zone thinks that local_timezone
// has also changed
- zone_changed(zone);
- timezone_changed(timezone);
+ zone_changed(old_zone, zone);
+ timezone_changed(old_timezone, timezone);
+
+ // update current date, if necessary
+ update_today();
}
}
+ private int next_check_today_interval_sec() {
+ // get the amount of time until midnight, adding one back to account for the second needed
+ // to cross into the next day, and another one because this isn't rocket science but a
+ // best-effort kind of thing
+ ExactTime last_sec_of_day = new ExactTime(Timezone.local, today, WallTime.latest);
+ int64 sec_to_midnight = last_sec_of_day.difference(new ExactTime.now(Timezone.local)) + 2;
+
+ // clamp values to (a) ensure zero is never passed to Timeout.add_seconds(), which could
+ // cause brief racing around midnight if close (but not close enough) to the appointed hour,
+ // and (b) not too far out in case the user changes the date and would like to see the
+ // change in California at some reasonable interval
+ return (int) sec_to_midnight.clamp(MIN_CHECK_DATE_INTERVAL_SEC, MAX_CHECK_DATE_INTERVAL_SEC);
+ }
+
+ // See note in constructor for logic behind this SourceFunc
+ private bool check_today_changed() {
+ update_today();
+
+ // reschedule w/ the next interval
+ date_timer_id = Timeout.add_seconds_full(CHECK_DATE_PRIORITY, next_check_today_interval_sec(),
+ check_today_changed);
+
+ return false;
+ }
+
+ private void update_today() {
+ Date new_today = new Date.now(Timezone.local);
+ if (new_today.equal_to(today))
+ return;
+
+ Date old_today = today;
+ today = new_today;
+ debug("Date changed: %s", new_today.to_string());
+
+ today_changed(old_today, new_today);
+ }
+
public override string to_string() {
return get_class().get_type().name();
}
diff --git a/src/host/host-main-window.vala b/src/host/host-main-window.vala
index c7465f6..50934e4 100644
--- a/src/host/host-main-window.vala
+++ b/src/host/host-main-window.vala
@@ -41,7 +41,8 @@ public class MainWindow : Gtk.ApplicationWindow {
bool rtl = get_direction () == Gtk.TextDirection.RTL;
- Gtk.Button today = new Gtk.Button.with_label(_("Today"));
+ Gtk.Button today = new Gtk.Button.with_label(_("_Today"));
+ today.use_underline = true;
today.clicked.connect(() => { current_view.today(); });
Gtk.Button prev = new Gtk.Button.from_icon_name(rtl ? "go-previous-rtl-symbolic" :
"go-previous-symbolic", Gtk.IconSize.MENU);
diff --git a/src/host/host-show-event.vala b/src/host/host-show-event.vala
index dd87d92..1c8af92 100644
--- a/src/host/host-show-event.vala
+++ b/src/host/host-show-event.vala
@@ -33,10 +33,12 @@ public class ShowEvent : Gtk.Grid, Interaction {
build_display();
Calendar.System.instance.is_24hr_changed.connect(build_display);
+ Calendar.System.instance.today_changed.connect(build_display);
}
~ShowEvent() {
Calendar.System.instance.is_24hr_changed.disconnect(build_display);
+ Calendar.System.instance.today_changed.disconnect(build_display);
}
private void build_display() {
diff --git a/src/view/month/month-cell.vala b/src/view/month/month-cell.vala
index 2aa450f..ba732a4 100644
--- a/src/view/month/month-cell.vala
+++ b/src/view/month/month-cell.vala
@@ -91,12 +91,14 @@ public class Cell : Gtk.EventBox {
notify["date"].connect(queue_draw);
notify["selected"].connect(queue_draw);
Calendar.System.instance.is_24hr_changed.connect(on_24hr_changed);
+ Calendar.System.instance.today_changed.connect(on_today_changed);
canvas.draw.connect(on_draw);
}
~Cell() {
Calendar.System.instance.is_24hr_changed.disconnect(on_24hr_changed);
+ Calendar.System.instance.today_changed.disconnect(on_today_changed);
}
internal static void init() {
@@ -159,6 +161,12 @@ public class Cell : Gtk.EventBox {
queue_draw();
}
+ private void on_today_changed(Calendar.Date old_today, Calendar.Date new_today) {
+ // need to know re: redrawing background color to indicate current day
+ if (date != null && (date.equal_to(old_today) || date.equal_to(new_today)))
+ queue_draw();
+ }
+
private void on_span_updated(Object object, ParamSpec param) {
if (date == null)
return;
diff --git a/src/view/month/month-controllable.vala b/src/view/month/month-controllable.vala
index bff8f18..de49d3d 100644
--- a/src/view/month/month-controllable.vala
+++ b/src/view/month/month-controllable.vala
@@ -111,11 +111,16 @@ public class Controllable : Gtk.Grid, View.Controllable {
notify[PROP_MONTH_OF_YEAR].connect(on_month_of_year_changed);
notify[PROP_FIRST_OF_WEEK].connect(update_first_of_week);
notify[PROP_SHOW_OUTSIDE_MONTH].connect(update_cells);
+ Calendar.System.instance.today_changed.connect(on_today_changed);
// update now that signal handlers are in place
month_of_year = Calendar.System.today.month_of_year();
}
+ ~Controllable() {
+ Calendar.System.instance.today_changed.disconnect(on_today_changed);
+ }
+
/**
* @inheritDoc
*/
@@ -237,9 +242,18 @@ public class Controllable : Gtk.Grid, View.Controllable {
update_subscription();
}
+ private void update_is_viewing_today() {
+ is_viewing_today = month_of_year.equal_to(Calendar.System.today.month_of_year());
+ }
+
+ private void on_today_changed() {
+ // don't update view but indicate if it's still in view
+ update_is_viewing_today();
+ }
+
private void on_month_of_year_changed() {
current_label = month_of_year.full_name;
- is_viewing_today = month_of_year.equal_to(Calendar.System.today.month_of_year());
+ update_is_viewing_today();
// default date is first of month unless displaying current month, in which case it's
// current date
diff --git a/src/view/view-controllable.vala b/src/view/view-controllable.vala
index 9f83936..0346bf9 100644
--- a/src/view/view-controllable.vala
+++ b/src/view/view-controllable.vala
@@ -28,6 +28,9 @@ public interface Controllable : Object {
/**
* Flag indicating if the current calendar unit matches the unit the { link today} method
* could jump to.
+ *
+ * This value should update dynamically as { link Calendar.System.today} changes. There's no
+ * requirement for the { link Controllable} to change its view as the day changes, however.
*/
public abstract bool is_viewing_today { get; protected set; }
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]