diff options
Diffstat (limited to 'src/timezone-geoclue.cpp')
-rw-r--r-- | src/timezone-geoclue.cpp | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/src/timezone-geoclue.cpp b/src/timezone-geoclue.cpp new file mode 100644 index 0000000..b8847a4 --- /dev/null +++ b/src/timezone-geoclue.cpp @@ -0,0 +1,250 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr <charles.kerr@canonical.com> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <datetime/timezone-geoclue.h> + +#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() +{ + g_cancellable_cancel(m_cancellable); + g_object_unref(m_cancellable); + + if (m_signal_subscription) + g_dbus_connection_signal_unsubscribe(m_connection, m_signal_subscription); + + 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) + { + 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); + } + else + { + 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); + } +} + +void +GeoclueTimezone::on_client_created(GObject * source, GAsyncResult * res, gpointer gself) +{ + GVariant * result; + + if ((result = call_finish(source, res))) + { + 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); + } +} + +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); +} + +void +GeoclueTimezone::on_requirements_set(GObject* source, GAsyncResult* res, gpointer gself) +{ + GVariant * result; + + if ((result = call_finish(source, res))) + { + 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); + } +} + +void +GeoclueTimezone::on_address_started(GObject * source, GAsyncResult * res, gpointer gself) +{ + GVariant * result; + + if ((result = call_finish(source, res))) + { + 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); + } +} + +void +GeoclueTimezone::on_address_got(GObject * source, GAsyncResult * res, gpointer gself) +{ + GVariant * result; + + if ((result = call_finish(source, res))) + { + static_cast<GeoclueTimezone*>(gself)->setTimezoneFromAddressVariant(result); + 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))"))); + + 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)) + timezone.set(timezone_string); + + g_variant_unref(dict); + } +} + +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); + + if (error) + { + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning("AddressStart() failed: %s", error->message); + + g_error_free(error); + + g_clear_pointer(&result, g_variant_unref); + } + + return result; +} + +/**** +***** +****/ + +} // namespace datetime +} // namespace indicator +} // namespace unity + |