aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/timezone-timedated.cpp249
1 files changed, 135 insertions, 114 deletions
diff --git a/src/timezone-timedated.cpp b/src/timezone-timedated.cpp
index d38557b..9254612 100644
--- a/src/timezone-timedated.cpp
+++ b/src/timezone-timedated.cpp
@@ -17,6 +17,7 @@
* Charles Kerr <charles.kerr@canonical.com>
*/
+#include <datetime/dbus-shared.h>
#include <datetime/timezone-timedated.h>
#include <gio/gio.h>
@@ -36,166 +37,186 @@ class TimedatedTimezone::Impl
{
public:
- Impl(TimedatedTimezone& owner, std::string filename):
- m_owner(owner),
- m_filename(filename)
+ Impl(TimedatedTimezone& owner):
+ m_owner{owner},
+ m_cancellable{g_cancellable_new()}
{
- g_debug("Filename is '%s'", filename.c_str());
- monitor_timezone_property();
+ // set the fallback value
+ m_owner.timezone.set("Etc/Utc");
+
+ // watch for timedate1 on the bus
+ m_watcher_id = g_bus_watch_name(
+ G_BUS_TYPE_SYSTEM,
+ Bus::Timedate1::BUSNAME,
+ G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
+ on_timedate1_appeared,
+ on_timedate1_vanished,
+ this,
+ nullptr);
}
~Impl()
{
- clear();
- }
+ g_cancellable_cancel(m_cancellable);
+ g_clear_object(&m_cancellable);
-private:
+ g_bus_unwatch_name(m_watcher_id);
- void clear()
- {
- if (m_connection && m_signal_subscription_id)
+ if (m_connection != nullptr)
{
- g_dbus_connection_signal_unsubscribe (m_connection, m_signal_subscription_id);
- m_signal_subscription_id = 0;
- }
+ if (m_signal_subscription_id)
+ g_dbus_connection_signal_unsubscribe(m_connection, m_signal_subscription_id);
- g_clear_object(&m_connection);
+ g_clear_object(&m_connection);
+ }
}
- static void on_properties_changed (GDBusConnection *connection G_GNUC_UNUSED,
- const gchar *sender_name G_GNUC_UNUSED,
- const gchar *object_path G_GNUC_UNUSED,
- const gchar *interface_name G_GNUC_UNUSED,
- const gchar *signal_name G_GNUC_UNUSED,
- GVariant *parameters,
- gpointer gself)
- {
- auto self = static_cast<Impl*>(gself);
- const char *tz;
- GVariant *changed_properties;
- gchar **invalidated_properties;
-
- g_variant_get (parameters, "(s@a{sv}^as)", NULL, &changed_properties, &invalidated_properties);
+private:
- if (g_variant_lookup(changed_properties, "Timezone", "&s", &tz, NULL))
- self->notify_timezone(tz);
- else if (g_strv_contains (invalidated_properties, "Timezone"))
- self->notify_timezone(self->get_timezone_from_file(self->m_filename));
+ static void on_timedate1_appeared(GDBusConnection * connection,
+ const gchar * /*name*/,
+ const gchar * /*name_owner*/,
+ gpointer gself)
+ {
+ static_cast<Impl*>(gself)->timedate1_appeared(connection);
+ }
+ void timedate1_appeared(GDBusConnection* connection)
+ {
+ // cache m_connection for later...
+ g_clear_object(&m_connection);
+ m_connection = G_DBUS_CONNECTION(g_object_ref(G_OBJECT(connection)));
- g_variant_unref (changed_properties);
- g_strfreev (invalidated_properties);
+ ensure_propchange_subscription();
+ ask_for_timezone();
}
- void monitor_timezone_property()
+ void ensure_propchange_subscription()
{
- GError *err = nullptr;
-
- /*
- * There is an unlikely race which happens if there is an activation
- * and timezone change before our match rule is added.
- */
- notify_timezone(get_timezone_from_file(m_filename));
-
- /*
- * Make sure the bus is around at least until we add the match rules,
- * otherwise things (tests) are sad.
- */
- m_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM,
- nullptr,
- &err);
-
- if (err)
+ if (m_signal_subscription_id == 0)
{
- g_warning("Couldn't get bus connection: '%s'", err->message);
- g_error_free(err);
- return;
- }
-
- m_signal_subscription_id = g_dbus_connection_signal_subscribe(m_connection,
- "org.freedesktop.timedate1",
- "org.freedesktop.DBus.Properties",
- "PropertiesChanged",
- "/org/freedesktop/timedate1",
- NULL, G_DBUS_SIGNAL_FLAGS_NONE,
+ m_signal_subscription_id = g_dbus_connection_signal_subscribe(
+ m_connection,
+ Bus::Timedate1::IFACE,
+ Bus::Properties::IFACE,
+ Bus::Properties::Signals::PROPERTIES_CHANGED,
+ Bus::Timedate1::ADDR,
+ nullptr,
+ G_DBUS_SIGNAL_FLAGS_NONE,
on_properties_changed,
- this, nullptr);
+ this,
+ nullptr);
+ }
}
- void notify_timezone(std::string new_timezone)
+ static void on_timedate1_vanished(GDBusConnection * /*connection*/,
+ const gchar * name,
+ gpointer /*gself*/)
{
- g_debug("notify_timezone '%s'", new_timezone.c_str());
- if (!new_timezone.empty())
- m_owner.timezone.set(new_timezone);
+ g_debug("%s not present on system bus", name);
}
- std::string get_timezone_from_file(const std::string& filename)
+ static void on_properties_changed(GDBusConnection * /*connection*/,
+ const gchar * /*sender_name*/,
+ const gchar * /*object_path*/,
+ const gchar * /*interface_name*/,
+ const gchar * /*signal_name*/,
+ GVariant * parameters,
+ gpointer gself)
{
- 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)
- {
- 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_strstrip(line->str);
+ auto self = static_cast<Impl*>(gself);
- if (!line->len) // skip empty lines
- continue;
+ GVariant* changed_properties {};
+ gchar** invalidated_properties {};
+ g_variant_get(parameters, "(s@a{sv}^as)", NULL, &changed_properties, &invalidated_properties);
- if (*line->str=='#') // skip comments
- continue;
+ const char* tz {};
+ if (g_variant_lookup(changed_properties, Bus::Timedate1::Properties::TIMEZONE, "&s", &tz, NULL))
+ {
+ if (tz != nullptr)
+ self->set_timezone(tz);
+ else
+ g_warning("%s no timezone found", G_STRLOC);
+ }
+ else if (g_strv_contains(invalidated_properties, Bus::Timedate1::Properties::TIMEZONE))
+ {
+ self->ask_for_timezone();
+ }
- ret = line->str;
- }
+ g_variant_unref(changed_properties);
+ g_strfreev(invalidated_properties);
+ }
- g_string_free(line, true);
- } else
- /* Default to UTC */
- ret = "Etc/Utc";
+ void ask_for_timezone()
+ {
+ g_return_if_fail(m_connection != nullptr);
+
+ g_dbus_connection_call(
+ m_connection,
+ Bus::Timedate1::BUSNAME,
+ Bus::Timedate1::ADDR,
+ Bus::Properties::IFACE,
+ Bus::Properties::Methods::GET,
+ g_variant_new("(ss)", Bus::Timedate1::IFACE, Bus::Timedate1::Properties::TIMEZONE),
+ G_VARIANT_TYPE("(v)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ m_cancellable,
+ on_get_timezone_ready,
+ this);
+ }
- if (io_channel != nullptr)
+ static void on_get_timezone_ready(GObject * connection,
+ GAsyncResult * res,
+ gpointer gself)
+ {
+ GError* error {};
+ GVariant* v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(connection), res, &error);
+ if (v == nullptr)
{
- g_io_channel_shutdown(io_channel, false, nullptr);
- g_io_channel_unref(io_channel);
+ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning("%s Couldn't get timezone: %s", G_STRLOC, error->message);
}
-
- if (error != nullptr)
+ else
{
- g_warning("%s Unable to read timezone file '%s': %s", G_STRLOC, filename.c_str(), error->message);
- g_error_free(error);
+ GVariant* tzv {};
+ g_variant_get(v, "(v)", &tzv);
+ const char* tz = g_variant_get_string(tzv, nullptr);
+
+ if (tz != nullptr)
+ static_cast<Impl*>(gself)->set_timezone(tz);
+ else
+ g_warning("%s no timezone found", G_STRLOC);
+
+ g_clear_pointer(&tzv, g_variant_unref);
+ g_clear_pointer(&v, g_variant_unref);
}
+ }
+
+ void set_timezone(const std::string& tz)
+ {
+ g_return_if_fail(!tz.empty());
- return ret;
+ g_debug("set timezone: '%s'", tz.c_str());
+ m_owner.timezone.set(tz);
}
/***
****
***/
- TimedatedTimezone & m_owner;
- GDBusConnection *m_connection = nullptr;
- unsigned long m_signal_subscription_id = 0;
- std::string m_filename;
+ TimedatedTimezone& m_owner;
+ GCancellable* m_cancellable {};
+ GDBusConnection* m_connection {};
+ unsigned long m_signal_subscription_id {};
+ unsigned int m_watcher_id {};
};
/***
****
***/
-TimedatedTimezone::TimedatedTimezone(std::string filename):
- impl(new Impl{*this, filename})
+TimedatedTimezone::TimedatedTimezone():
+ impl{new Impl{*this}}
{
}