From 13d371f6c4974baad92574f5e287a72313080432 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sat, 13 Sep 2014 15:45:23 -0500 Subject: hide the implementation detials of FileTimezone and GeoclueTimezone behind Impl classes --- include/datetime/clock.h | 2 - include/datetime/timezone-file.h | 17 +- include/datetime/timezone-geoclue.h | 22 +- src/timezone-file.cpp | 175 +++++++++------- src/timezone-geoclue.cpp | 391 ++++++++++++++++++++---------------- src/wakeup-timer-powerd.cpp | 2 + 6 files changed, 329 insertions(+), 280 deletions(-) diff --git a/include/datetime/clock.h b/include/datetime/clock.h index 0b2a543..0445aab 100644 --- a/include/datetime/clock.h +++ b/include/datetime/clock.h @@ -25,8 +25,6 @@ #include #include -#include // GDBusConnection - #include // std::shared_ptr, std::unique_ptr namespace unity { diff --git a/include/datetime/timezone-file.h b/include/datetime/timezone-file.h index a67c01a..eca9c29 100644 --- a/include/datetime/timezone-file.h +++ b/include/datetime/timezone-file.h @@ -24,9 +24,6 @@ #include // std::string -#include -#include - namespace unity { namespace indicator { namespace datetime { @@ -37,21 +34,15 @@ namespace datetime { class FileTimezone: public Timezone { public: - FileTimezone(); FileTimezone(const std::string& filename); ~FileTimezone(); private: - void set_filename(const std::string& filename); - static void on_file_changed(gpointer gself); - void clear(); - void reload(); - - std::string m_filename; - GFileMonitor * m_monitor = nullptr; - unsigned long m_monitor_handler_id = 0; + class Impl; + friend Impl; + std::unique_ptr impl; - // we have raw pointers and glib tags in here, so disable copying + // we have pointers in here, so disable copying FileTimezone(const FileTimezone&) =delete; FileTimezone& operator=(const FileTimezone&) =delete; }; diff --git a/include/datetime/timezone-geoclue.h b/include/datetime/timezone-geoclue.h index 4a5b726..ab6b815 100644 --- a/include/datetime/timezone-geoclue.h +++ b/include/datetime/timezone-geoclue.h @@ -22,11 +22,6 @@ #include // base class -#include - -#include -#include - namespace unity { namespace indicator { namespace datetime { @@ -41,21 +36,10 @@ public: ~GeoclueTimezone(); private: - static void on_bus_got (GObject*, GAsyncResult*, gpointer); - static void on_client_created (GObject*, GAsyncResult*, gpointer); - static void on_address_changed (GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant*, gpointer); - static void on_requirements_set (GObject*, GAsyncResult*, gpointer); - static void on_address_started (GObject*, GAsyncResult*, gpointer); - static void on_address_got (GObject*, GAsyncResult*, gpointer); - void setTimezoneFromAddressVariant (GVariant*); - static GVariant * call_finish (GObject*, GAsyncResult*); - - GCancellable * m_cancellable = nullptr; - GDBusConnection * m_connection = nullptr; - std::string m_client_object_path; - guint m_signal_subscription = 0; + struct Impl; + std::unique_ptr impl; - // we've got pointers and gsignal tags in here, so don't allow copying + // we've got pointers in here, so don't allow copying GeoclueTimezone(const GeoclueTimezone&) =delete; GeoclueTimezone& operator=(const GeoclueTimezone&) =delete; }; diff --git a/src/timezone-file.cpp b/src/timezone-file.cpp index bbe48f7..3c73913 100644 --- a/src/timezone-file.cpp +++ b/src/timezone-file.cpp @@ -19,11 +19,97 @@ #include +#include + #include #include -namespace +namespace unity { +namespace indicator { +namespace datetime { + +/*** +**** +***/ + +class FileTimezone::Impl { +public: + + Impl(FileTimezone& owner, const std::string& filename): + m_owner(owner) + { + set_filename(filename); + } + + ~Impl() + { + clear(); + } + +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) + { + 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? + } + + 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 + { + 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()); + } + + reload(); + } + + static void on_file_changed(gpointer gself) + { + static_cast(gself)->reload(); + } + + void reload() + { + const auto new_timezone = get_timezone_from_file(m_filename); + + if (!new_timezone.empty()) + m_owner.timezone.set(new_timezone); + } + + /*** + **** + ***/ + std::string get_timezone_from_file(const std::string& filename) { GError * error; @@ -73,86 +159,33 @@ namespace return ret; } -} -namespace unity { -namespace indicator { -namespace datetime { + /*** + **** + ***/ -FileTimezone::FileTimezone() -{ -} + FileTimezone & m_owner; + std::string m_filename; + GFileMonitor * m_monitor = nullptr; + unsigned long m_monitor_handler_id = 0; +}; -FileTimezone::FileTimezone(const std::string& filename) -{ - set_filename(filename); -} - -FileTimezone::~FileTimezone() -{ - clear(); -} +/*** +**** +***/ -void -FileTimezone::clear() +FileTimezone::FileTimezone(const std::string& filename): + impl(new Impl{*this, filename}) { - if (m_monitor_handler_id) - g_signal_handler_disconnect(m_monitor, m_monitor_handler_id); - - g_clear_object (&m_monitor); - - m_filename.clear(); } -void -FileTimezone::set_filename(const std::string& filename) -{ - clear(); - - auto tmp = realpath(filename.c_str(), nullptr); - if(tmp != nullptr) - { - 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? - } - - 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 - { - 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()); - } - - reload(); -} - -void -FileTimezone::on_file_changed(gpointer gself) +FileTimezone::~FileTimezone() { - static_cast(gself)->reload(); } -void -FileTimezone::reload() -{ - const auto new_timezone = get_timezone_from_file(m_filename); - - if (!new_timezone.empty()) - timezone.set(new_timezone); -} +/*** +**** +***/ } // namespace datetime } // namespace indicator diff --git a/src/timezone-geoclue.cpp b/src/timezone-geoclue.cpp index b8847a4..ca9132f 100644 --- a/src/timezone-geoclue.cpp +++ b/src/timezone-geoclue.cpp @@ -19,225 +19,266 @@ #include +#include + +#include +#include +#include + #define GEOCLUE_BUS_NAME "org.freedesktop.Geoclue.Master" namespace unity { namespace indicator { namespace datetime { - -GeoclueTimezone::GeoclueTimezone(): - m_cancellable(g_cancellable_new()) -{ - g_bus_get(G_BUS_TYPE_SESSION, m_cancellable, on_bus_got, this); -} - -GeoclueTimezone::~GeoclueTimezone() +class GeoclueTimezone::Impl { - g_cancellable_cancel(m_cancellable); - g_object_unref(m_cancellable); - if (m_signal_subscription) - g_dbus_connection_signal_unsubscribe(m_connection, m_signal_subscription); +public: - g_object_unref(m_connection); -} - -/*** -**** -***/ - -void -GeoclueTimezone::on_bus_got(GObject* /*source*/, - GAsyncResult* res, - gpointer gself) -{ - GError * error; - GDBusConnection * connection; - - error = nullptr; - connection = g_bus_get_finish(res, &error); - if (error) + Impl(GeoclueTimezone& owner): + m_owner(owner), + m_cancellable(g_cancellable_new()) { - if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning("Couldn't get bus: %s", error->message); - - g_error_free(error); + g_bus_get(G_BUS_TYPE_SESSION, m_cancellable, on_bus_got, this); } - else + + ~Impl() { - auto self = static_cast(gself); - - self->m_connection = connection; - - g_dbus_connection_call(self->m_connection, - GEOCLUE_BUS_NAME, - "/org/freedesktop/Geoclue/Master", - "org.freedesktop.Geoclue.Master", - "Create", - nullptr, // parameters - G_VARIANT_TYPE("(o)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - self->m_cancellable, - on_client_created, - self); + g_cancellable_cancel(m_cancellable); + g_object_unref(m_cancellable); + g_object_unref(m_bus); } -} -void -GeoclueTimezone::on_client_created(GObject * source, GAsyncResult * res, gpointer gself) -{ - GVariant * result; +private: - if ((result = call_finish(source, res))) + void remember_subscription(GDBusConnection * bus, + guint tag) { - auto self = static_cast(gself); - - GVariant * child = g_variant_get_child_value(result, 0); - self->m_client_object_path = g_variant_get_string(child, nullptr); - g_variant_unref(child); - g_variant_unref(result); - - self->m_signal_subscription = g_dbus_connection_signal_subscribe( - self->m_connection, - GEOCLUE_BUS_NAME, - "org.freedesktop.Geoclue.Address", // inteface - "AddressChanged", // signal name - self->m_client_object_path.c_str(), // object path - nullptr, // arg0 - G_DBUS_SIGNAL_FLAGS_NONE, - on_address_changed, - self, - nullptr); - - g_dbus_connection_call(self->m_connection, - GEOCLUE_BUS_NAME, - self->m_client_object_path.c_str(), - "org.freedesktop.Geoclue.MasterClient", - "SetRequirements", - g_variant_new("(iibi)", 2, 0, FALSE, 1023), - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - self->m_cancellable, - on_requirements_set, - self); - } -} + g_object_ref(bus); -void -GeoclueTimezone::on_address_changed(GDBusConnection* /*connection*/, - const gchar* /*sender_name*/, - const gchar* /*object_path*/, - const gchar* /*interface_name*/, - const gchar* /*signal_name*/, - GVariant* parameters, - gpointer gself) -{ - static_cast(gself)->setTimezoneFromAddressVariant(parameters); -} + auto deleter = [tag](GDBusConnection* bus){ + g_dbus_connection_signal_unsubscribe(bus, tag); + g_object_unref(G_OBJECT(bus)); + }; -void -GeoclueTimezone::on_requirements_set(GObject* source, GAsyncResult* res, gpointer gself) -{ - GVariant * result; + m_subscriptions.push_back(std::shared_ptr(bus, deleter)); + } - if ((result = call_finish(source, res))) + static void on_bus_got(GObject * /*source*/, + GAsyncResult * res, + gpointer gself) { - auto self = static_cast(gself); - - g_dbus_connection_call(self->m_connection, - GEOCLUE_BUS_NAME, - self->m_client_object_path.c_str(), - "org.freedesktop.Geoclue.MasterClient", - "AddressStart", - nullptr, - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, - self->m_cancellable, - on_address_started, - self); - - g_variant_unref(result); - } -} + GError * error; + GDBusConnection * connection; -void -GeoclueTimezone::on_address_started(GObject * source, GAsyncResult * res, gpointer gself) -{ - GVariant * result; + error = nullptr; + connection = g_bus_get_finish(res, &error); + if (error) + { + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning("Couldn't get bus: %s", error->message); - if ((result = call_finish(source, res))) + g_error_free(error); + } + else + { + auto self = static_cast(gself); + + self->m_bus = connection; + + g_dbus_connection_call(self->m_bus, + GEOCLUE_BUS_NAME, + "/org/freedesktop/Geoclue/Master", + "org.freedesktop.Geoclue.Master", + "Create", + nullptr, // parameters + G_VARIANT_TYPE("(o)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + self->m_cancellable, + on_client_created, + self); + } + } + + static void on_client_created(GObject* source, GAsyncResult* res, gpointer gself) { - auto self = static_cast(gself); - - g_dbus_connection_call(self->m_connection, - GEOCLUE_BUS_NAME, - self->m_client_object_path.c_str(), - "org.freedesktop.Geoclue.Address", - "GetAddress", - nullptr, - G_VARIANT_TYPE("(ia{ss}(idd))"), - G_DBUS_CALL_FLAGS_NONE, - -1, - self->m_cancellable, - on_address_got, - self); - - g_variant_unref(result); + GVariant * result; + + if ((result = call_finish(G_STRFUNC, source, res))) + { + auto self = static_cast(gself); + + GVariant * child = g_variant_get_child_value(result, 0); + self->m_client_object_path = g_variant_get_string(child, nullptr); + g_variant_unref(child); + g_variant_unref(result); + + auto tag = g_dbus_connection_signal_subscribe(self->m_bus, + GEOCLUE_BUS_NAME, + "org.freedesktop.Geoclue.Address", // interface + "AddressChanged", // signal name + self->m_client_object_path.c_str(), // object path + nullptr, // arg0 + G_DBUS_SIGNAL_FLAGS_NONE, + on_address_changed, + self, + nullptr); + self->remember_subscription(self->m_bus, tag); + + g_dbus_connection_call(self->m_bus, + GEOCLUE_BUS_NAME, + self->m_client_object_path.c_str(), + "org.freedesktop.Geoclue.MasterClient", + "SetRequirements", + g_variant_new("(iibi)", 2, 0, FALSE, 1023), + nullptr, + G_DBUS_CALL_FLAGS_NONE, + -1, + self->m_cancellable, + on_requirements_set, + self); + } } -} -void -GeoclueTimezone::on_address_got(GObject * source, GAsyncResult * res, gpointer gself) -{ - GVariant * result; + static void on_address_changed(GDBusConnection* /*connection*/, + const gchar* /*sender_name*/, + const gchar* /*object_path*/, + const gchar* /*interface_name*/, + const gchar* /*signal_name*/, + GVariant* parameters, + gpointer gself) + { + static_cast(gself)->set_timezone_from_address_variant(parameters); + } - if ((result = call_finish(source, res))) + static void on_requirements_set(GObject* source, GAsyncResult* res, gpointer gself) { - static_cast(gself)->setTimezoneFromAddressVariant(result); - g_variant_unref(result); + GVariant * result; + + if ((result = call_finish(G_STRFUNC, source, res))) + { + auto self = static_cast(gself); + + g_dbus_connection_call(self->m_bus, + GEOCLUE_BUS_NAME, + self->m_client_object_path.c_str(), + "org.freedesktop.Geoclue.MasterClient", + "AddressStart", + nullptr, + nullptr, + G_DBUS_CALL_FLAGS_NONE, + -1, + self->m_cancellable, + on_address_started, + self); + + g_variant_unref(result); + } } -} -void -GeoclueTimezone::setTimezoneFromAddressVariant(GVariant * variant) -{ - g_return_if_fail(g_variant_is_of_type(variant, G_VARIANT_TYPE("(ia{ss}(idd))"))); + static void on_address_started(GObject* source, GAsyncResult* res, gpointer gself) + { + GVariant * result; + + if ((result = call_finish(G_STRFUNC, source, res))) + { + auto self = static_cast(gself); + + g_dbus_connection_call(self->m_bus, + GEOCLUE_BUS_NAME, + self->m_client_object_path.c_str(), + "org.freedesktop.Geoclue.Address", + "GetAddress", + nullptr, + G_VARIANT_TYPE("(ia{ss}(idd))"), + G_DBUS_CALL_FLAGS_NONE, + -1, + self->m_cancellable, + on_address_got, + self); + + g_variant_unref(result); + } + } - const gchar * timezone_string = nullptr; - GVariant * dict = g_variant_get_child_value(variant, 1); - if (dict) + static void on_address_got(GObject* source, GAsyncResult* res, gpointer gself) { - if (g_variant_lookup(dict, "timezone", "&s", &timezone_string)) - timezone.set(timezone_string); + GVariant * result; - g_variant_unref(dict); + if ((result = call_finish(G_STRFUNC, source, res))) + { + static_cast(gself)->set_timezone_from_address_variant(result); + g_variant_unref(result); + } } -} -GVariant* -GeoclueTimezone::call_finish(GObject * source, GAsyncResult * res) -{ - GError * error; - GVariant * result; + /*** + **** + ***/ - error = nullptr; - result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error); + void set_timezone_from_address_variant(GVariant * variant) + { + g_return_if_fail(g_variant_is_of_type(variant, G_VARIANT_TYPE("(ia{ss}(idd))"))); + + const gchar * timezone_string = nullptr; + GVariant * dict = g_variant_get_child_value(variant, 1); + if (dict) + { + if (g_variant_lookup(dict, "timezone", "&s", &timezone_string)) + { + g_debug("from geoclue, setting timezone to '%s'", timezone_string); + m_owner.timezone.set(timezone_string); + } + + g_variant_unref(dict); + } + } - if (error) + static GVariant* call_finish(const char * funcname, GObject * source, GAsyncResult * res) { + GError * error; + GVariant * result; + + error = nullptr; + result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error); + + if (error) + { if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning("AddressStart() failed: %s", error->message); + g_warning("%s failed: %s", funcname, error->message); g_error_free(error); g_clear_pointer(&result, g_variant_unref); + } + + return result; } - return result; + /*** + **** + ***/ + + GeoclueTimezone & m_owner; + GDBusConnection * m_bus = nullptr; + GCancellable * m_cancellable = nullptr; + std::string m_client_object_path; + std::vector> m_subscriptions; +}; + +/**** +***** +****/ + +GeoclueTimezone::GeoclueTimezone(): + impl(new Impl{*this}) +{ +} + +GeoclueTimezone::~GeoclueTimezone() +{ } /**** diff --git a/src/wakeup-timer-powerd.cpp b/src/wakeup-timer-powerd.cpp index 42d93e7..bbcc9dd 100644 --- a/src/wakeup-timer-powerd.cpp +++ b/src/wakeup-timer-powerd.cpp @@ -22,6 +22,8 @@ #include // BUS_POWERD_NAME +#include + #include // std::shared_ptr namespace unity { -- cgit v1.2.3