aboutsummaryrefslogtreecommitdiff
path: root/src/timezone-geoclue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/timezone-geoclue.cpp')
-rw-r--r--src/timezone-geoclue.cpp391
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()
+{
}
/****