diff options
Diffstat (limited to 'src/timezone-geoclue.cpp')
-rw-r--r-- | src/timezone-geoclue.cpp | 391 |
1 files changed, 216 insertions, 175 deletions
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 <datetime/timezone-geoclue.h> +#include <gio/gio.h> + +#include <memory> +#include <string> +#include <vector> + #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<GeoclueTimezone*>(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<GeoclueTimezone*>(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<GeoclueTimezone*>(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<GDBusConnection>(bus, deleter)); + } - if ((result = call_finish(source, res))) + static void on_bus_got(GObject * /*source*/, + GAsyncResult * res, + gpointer gself) { - auto self = static_cast<GeoclueTimezone*>(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<Impl*>(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<GeoclueTimezone*>(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<Impl*>(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<Impl*>(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<GeoclueTimezone*>(gself)->setTimezoneFromAddressVariant(result); - g_variant_unref(result); + GVariant * result; + + if ((result = call_finish(G_STRFUNC, source, res))) + { + auto self = static_cast<Impl*>(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<Impl*>(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<Impl*>(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<std::shared_ptr<GDBusConnection>> m_subscriptions; +}; + +/**** +***** +****/ + +GeoclueTimezone::GeoclueTimezone(): + impl(new Impl{*this}) +{ +} + +GeoclueTimezone::~GeoclueTimezone() +{ } /**** |