From 132ac93bbd4141824cfa22f6516366f953fce9a0 Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Mon, 31 Aug 2015 22:08:36 +0100 Subject: Use timedated's Timezone property instead of watching /etc/timezone Still need to rename everything to not use "timezone-file" --- src/CMakeLists.txt | 3 +- src/main.cpp | 4 +- src/timezone-file.cpp | 199 +++++++++++++++++++++++++++---------------------- src/timezones-live.cpp | 5 +- 4 files changed, 113 insertions(+), 98 deletions(-) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5fc822c..6f27e99 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,7 @@ set (SERVICE_LIB "indicatordatetimeservice") set (SERVICE_EXEC "indicator-datetime-service") -add_definitions (-DTIMEZONE_FILE="/etc/timezone" - -DG_LOG_DOMAIN="Indicator-Datetime") +add_definitions (-DG_LOG_DOMAIN="Indicator-Datetime") # handwritten sources set (SERVICE_C_SOURCES diff --git a/src/main.cpp b/src/main.cpp index 907d49f..460f98c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,7 +68,7 @@ namespace { // create the live objects auto live_settings = std::make_shared(); - auto live_timezones = std::make_shared(live_settings, TIMEZONE_FILE); + auto live_timezones = std::make_shared(live_settings); auto live_clock = std::make_shared(timezone_); // create a full-month planner currently pointing to the current month @@ -128,7 +128,7 @@ main(int /*argc*/, char** /*argv*/) textdomain(GETTEXT_PACKAGE); auto engine = create_engine(); - auto timezone_ = std::make_shared(TIMEZONE_FILE); + auto timezone_ = std::make_shared(); auto state = create_state(engine, timezone_); auto actions = std::make_shared(state); MenuFactory factory(actions, state); diff --git a/src/timezone-file.cpp b/src/timezone-file.cpp index 3c73913..15e4f61 100644 --- a/src/timezone-file.cpp +++ b/src/timezone-file.cpp @@ -36,10 +36,11 @@ class FileTimezone::Impl { public: - Impl(FileTimezone& owner, const std::string& filename): - m_owner(owner) + Impl(FileTimezone& owner): + m_owner(owner), + m_loop(g_main_loop_new(nullptr, FALSE)) { - set_filename(filename); + monitor_timezone_property(); } ~Impl() @@ -51,113 +52,128 @@ private: void clear() { - if (m_monitor_handler_id) - g_signal_handler_disconnect(m_monitor, m_monitor_handler_id); - - g_clear_object (&m_monitor); - - m_filename.clear(); - } - - void set_filename(const std::string& filename) - { - clear(); - - auto tmp = realpath(filename.c_str(), nullptr); - if(tmp != nullptr) + if (m_bus_watch_id) { - m_filename = tmp; - free(tmp); - } - else - { - g_warning("Unable to resolve path '%s': %s", filename.c_str(), g_strerror(errno)); - m_filename = filename; // better than nothing? + g_bus_unwatch_name (m_bus_watch_id); + m_bus_watch_id = 0; } - auto file = g_file_new_for_path(m_filename.c_str()); - GError * err = nullptr; - m_monitor = g_file_monitor_file(file, G_FILE_MONITOR_NONE, nullptr, &err); - g_object_unref(file); - if (err) - { - g_warning("%s Unable to monitor timezone file '%s': %s", G_STRLOC, TIMEZONE_FILE, err->message); - g_error_free(err); - } - else + if (m_properties_changed_id) { - m_monitor_handler_id = g_signal_connect_swapped(m_monitor, "changed", G_CALLBACK(on_file_changed), this); - g_debug("%s Monitoring timezone file '%s'", G_STRLOC, m_filename.c_str()); + g_signal_handler_disconnect(m_proxy, m_properties_changed_id); + m_properties_changed_id = 0; } - reload(); + g_clear_object(&m_proxy); + g_clear_pointer(&m_loop, g_main_loop_unref); } - static void on_file_changed(gpointer gself) + static void on_properties_changed(GDBusProxy *proxy G_GNUC_UNUSED, + GVariant *changed_properties /* a{sv} */, + GStrv invalidated_properties G_GNUC_UNUSED, + gpointer gself) { - static_cast(gself)->reload(); + auto self = static_cast(gself); + char *tz; + + if (g_variant_lookup(changed_properties, "Timezone", "s", &tz, NULL)) + { + g_debug("on_properties_changed: got timezone '%s'", tz); + self->notify_timezone(tz); + g_free (tz); + } } - void reload() + static void on_proxy_ready(GObject *object G_GNUC_UNUSED, + GAsyncResult *res, + gpointer gself) { - const auto new_timezone = get_timezone_from_file(m_filename); + auto self = static_cast(gself); + GError *error = nullptr; + self->m_proxy = g_dbus_proxy_new_finish(res, &error); - if (!new_timezone.empty()) - m_owner.timezone.set(new_timezone); - } + if (error) + { + g_warning ("Couldn't create proxy to read timezone: %s", error->message); + goto out; + } - /*** - **** - ***/ + /* Read the property */ + GVariant *prop; + prop = g_dbus_proxy_get_cached_property(self->m_proxy, "Timezone"); - std::string get_timezone_from_file(const std::string& filename) - { - GError * error; - GIOChannel * io_channel; - std::string ret; - - // read through filename line-by-line until we fine a nonempty non-comment line - error = nullptr; - io_channel = g_io_channel_new_file(filename.c_str(), "r", &error); - if (error == nullptr) + if (!prop || !g_variant_is_of_type(prop, G_VARIANT_TYPE_STRING)) { - auto line = g_string_new(nullptr); - - while(ret.empty()) - { - const auto io_status = g_io_channel_read_line_string(io_channel, line, nullptr, &error); - if ((io_status == G_IO_STATUS_EOF) || (io_status == G_IO_STATUS_ERROR)) - break; - if (error != nullptr) - break; + g_warning("Couldn't read the Timezone property, defaulting to Etc/Utc"); + self->notify_timezone("Etc/Utc"); + goto out; + } - g_strstrip(line->str); + const gchar *tz; + tz = g_variant_get_string(prop, nullptr); - if (!line->len) // skip empty lines - continue; + self->notify_timezone(tz); - if (*line->str=='#') // skip comments - continue; + self->m_properties_changed_id = g_signal_connect(self->m_proxy, + "g-properties-changed", + (GCallback) on_properties_changed, + gself); - ret = line->str; - } +out: + g_clear_pointer(&error, g_error_free); + g_clear_pointer(&prop, g_variant_unref); + if (self->m_loop && g_main_loop_is_running(self->m_loop)) + g_main_loop_quit(self->m_loop); + } - g_string_free(line, true); - } + static void on_name_appeared(GDBusConnection *connection, + const gchar *name, + const gchar *name_owner G_GNUC_UNUSED, + gpointer gself G_GNUC_UNUSED) + { + g_debug ("timedate1 appeared"); + g_dbus_proxy_new(connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + name, + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + nullptr, + on_proxy_ready, + gself); + } - if (io_channel != nullptr) - { - g_io_channel_shutdown(io_channel, false, nullptr); - g_io_channel_unref(io_channel); - } + static void on_name_vanished(GDBusConnection *connection G_GNUC_UNUSED, + const gchar *name G_GNUC_UNUSED, + gpointer gself) + { + auto self = static_cast(gself); + g_debug ("timedate1 vanished"); + + g_signal_handler_disconnect(self->m_proxy, + self->m_properties_changed_id); + self->m_properties_changed_id = 0; + g_clear_object(&self->m_proxy); + g_clear_pointer(&self->m_proxy, g_main_loop_unref); + } - if (error != nullptr) - { - g_warning("%s Unable to read timezone file '%s': %s", G_STRLOC, filename.c_str(), error->message); - g_error_free(error); - } + void monitor_timezone_property() + { + m_bus_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, + "org.freedesktop.timedate1", + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + on_name_appeared, + on_name_vanished, + this, + nullptr); + + g_main_loop_run(m_loop); + } - return ret; + void notify_timezone(std::string new_timezone) + { + if (!new_timezone.empty()) + m_owner.timezone.set(new_timezone); } /*** @@ -165,17 +181,18 @@ private: ***/ FileTimezone & m_owner; - std::string m_filename; - GFileMonitor * m_monitor = nullptr; - unsigned long m_monitor_handler_id = 0; + unsigned long m_properties_changed_id = 0; + unsigned long m_bus_watch_id = 0; + GDBusProxy *m_proxy = nullptr; + GMainLoop *m_loop = nullptr; }; /*** **** ***/ -FileTimezone::FileTimezone(const std::string& filename): - impl(new Impl{*this, filename}) +FileTimezone::FileTimezone(): + impl(new Impl{*this}) { } diff --git a/src/timezones-live.cpp b/src/timezones-live.cpp index 4902b76..c5dd43c 100644 --- a/src/timezones-live.cpp +++ b/src/timezones-live.cpp @@ -25,9 +25,8 @@ namespace unity { namespace indicator { namespace datetime { -LiveTimezones::LiveTimezones(const std::shared_ptr& settings, - const std::string& filename): - m_file(filename), +LiveTimezones::LiveTimezones(const std::shared_ptr& settings): + m_file(), m_settings(settings) { m_file.timezone.changed().connect([this](const std::string&){update_timezones();}); -- cgit v1.2.3