aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/datetime/clock.h6
-rw-r--r--include/datetime/timezone-file.h17
-rw-r--r--include/datetime/timezone-geoclue.h22
-rw-r--r--src/clock-live.cpp31
-rw-r--r--src/main.cpp14
-rw-r--r--src/planner-range.cpp7
-rw-r--r--src/timezone-file.cpp175
-rw-r--r--src/timezone-geoclue.cpp391
-rw-r--r--src/wakeup-timer-powerd.cpp2
-rw-r--r--tests/manual9
-rw-r--r--tests/test-clock.cpp31
11 files changed, 385 insertions, 320 deletions
diff --git a/include/datetime/clock.h b/include/datetime/clock.h
index 0b2a543..8745d24 100644
--- a/include/datetime/clock.h
+++ b/include/datetime/clock.h
@@ -25,8 +25,6 @@
#include <core/property.h>
#include <core/signal.h>
-#include <gio/gio.h> // GDBusConnection
-
#include <memory> // std::shared_ptr, std::unique_ptr
namespace unity {
@@ -68,7 +66,7 @@ private:
****
***/
-class Timezones;
+class Timezone;
/**
* \brief A live #Clock that provides the actual system time.
@@ -76,7 +74,7 @@ class Timezones;
class LiveClock: public Clock
{
public:
- LiveClock (const std::shared_ptr<const Timezones>& zones);
+ LiveClock (const std::shared_ptr<const Timezone>& zones);
virtual ~LiveClock();
virtual DateTime localtime() const;
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 <string> // std::string
-#include <glib.h>
-#include <gio/gio.h>
-
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> 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 <datetime/timezone.h> // base class
-#include <string>
-
-#include <glib.h>
-#include <gio/gio.h>
-
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> 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/clock-live.cpp b/src/clock-live.cpp
index 21a18a3..68a8a8b 100644
--- a/src/clock-live.cpp
+++ b/src/clock-live.cpp
@@ -18,7 +18,7 @@
*/
#include <datetime/clock.h>
-#include <datetime/timezones.h>
+#include <datetime/timezone.h>
namespace unity {
namespace indicator {
@@ -59,14 +59,15 @@ class LiveClock::Impl
{
public:
- Impl(LiveClock& owner, const std::shared_ptr<const Timezones>& tzd):
+ Impl(LiveClock& owner, const std::shared_ptr<const Timezone>& timezone_):
m_owner(owner),
- m_timezones(tzd)
+ m_timezone(timezone_)
{
- if (m_timezones)
+ if (m_timezone)
{
- m_timezones->timezone.changed().connect([this](const std::string& z) {setTimezone(z);});
- setTimezone(m_timezones->timezone.get());
+ auto setter = [this](const std::string& z){setTimezone(z);};
+ m_timezone->timezone.changed().connect(setter);
+ setter(m_timezone->timezone.get());
}
restart_minute_timer();
@@ -76,14 +77,14 @@ public:
{
clearTimer(m_timer);
- g_clear_pointer(&m_timezone, g_time_zone_unref);
+ g_clear_pointer(&m_gtimezone, g_time_zone_unref);
}
DateTime localtime() const
{
- g_assert(m_timezone != nullptr);
+ g_assert(m_gtimezone != nullptr);
- auto gdt = g_date_time_new_now(m_timezone);
+ auto gdt = g_date_time_new_now(m_gtimezone);
DateTime ret(gdt);
g_date_time_unref(gdt);
return ret;
@@ -93,8 +94,8 @@ private:
void setTimezone(const std::string& str)
{
- g_clear_pointer(&m_timezone, g_time_zone_unref);
- m_timezone = g_time_zone_new(str.c_str());
+ g_clear_pointer(&m_gtimezone, g_time_zone_unref);
+ m_gtimezone = g_time_zone_new(str.c_str());
m_owner.minute_changed();
}
@@ -134,15 +135,15 @@ private:
protected:
LiveClock& m_owner;
- GTimeZone* m_timezone = nullptr;
- std::shared_ptr<const Timezones> m_timezones;
+ GTimeZone* m_gtimezone = nullptr;
+ std::shared_ptr<const Timezone> m_timezone;
DateTime m_prev_datetime;
unsigned int m_timer = 0;
};
-LiveClock::LiveClock(const std::shared_ptr<const Timezones>& tzd):
- p(new Impl(*this, tzd))
+LiveClock::LiveClock(const std::shared_ptr<const Timezone>& timezone_):
+ p(new Impl(*this, timezone_))
{
}
diff --git a/src/main.cpp b/src/main.cpp
index 54517c9..aa8f829 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -63,20 +63,20 @@ namespace
}
std::shared_ptr<State> create_state(const std::shared_ptr<Engine>& engine,
- const std::shared_ptr<Timezone>& tz)
+ const std::shared_ptr<Timezone>& timezone_)
{
// create the live objects
auto live_settings = std::make_shared<LiveSettings>();
auto live_timezones = std::make_shared<LiveTimezones>(live_settings, TIMEZONE_FILE);
- auto live_clock = std::make_shared<LiveClock>(live_timezones);
+ auto live_clock = std::make_shared<LiveClock>(timezone_);
// create a full-month planner currently pointing to the current month
const auto now = live_clock->localtime();
- auto range_planner = std::make_shared<SimpleRangePlanner>(engine, tz);
+ auto range_planner = std::make_shared<SimpleRangePlanner>(engine, timezone_);
auto calendar_month = std::make_shared<MonthPlanner>(range_planner, now);
// create an upcoming-events planner currently pointing to the current date
- range_planner = std::make_shared<SimpleRangePlanner>(engine, tz);
+ range_planner = std::make_shared<SimpleRangePlanner>(engine, timezone_);
auto calendar_upcoming = std::make_shared<UpcomingPlanner>(range_planner, now);
// create the state
@@ -127,8 +127,8 @@ main(int /*argc*/, char** /*argv*/)
textdomain(GETTEXT_PACKAGE);
auto engine = create_engine();
- auto timezone = std::make_shared<FileTimezone>(TIMEZONE_FILE);
- auto state = create_state(engine, timezone);
+ auto timezone_ = std::make_shared<FileTimezone>(TIMEZONE_FILE);
+ auto state = create_state(engine, timezone_);
auto actions = std::make_shared<LiveActions>(state);
MenuFactory factory(actions, state);
@@ -136,7 +136,7 @@ main(int /*argc*/, char** /*argv*/)
auto snooze_planner = std::make_shared<SnoozePlanner>(state->settings, state->clock);
auto notification_engine = std::make_shared<uin::Engine>("indicator-datetime-service");
std::unique_ptr<Snap> snap (new Snap(notification_engine, state->settings));
- auto alarm_queue = create_simple_alarm_queue(state->clock, snooze_planner, engine, timezone);
+ auto alarm_queue = create_simple_alarm_queue(state->clock, snooze_planner, engine, timezone_);
auto on_snooze = [snooze_planner](const Appointment& a) {snooze_planner->add(a);};
auto on_ok = [](const Appointment&){};
auto on_alarm_reached = [&snap, &on_snooze, &on_ok](const Appointment& a) {(*snap)(a, on_snooze, on_ok);};
diff --git a/src/planner-range.cpp b/src/planner-range.cpp
index 41b0f56..c223665 100644
--- a/src/planner-range.cpp
+++ b/src/planner-range.cpp
@@ -28,7 +28,7 @@ namespace datetime {
***/
SimpleRangePlanner::SimpleRangePlanner(const std::shared_ptr<Engine>& engine,
- const std::shared_ptr<Timezone>& timezone):
+ const std::shared_ptr<Timezone>& timezone):
m_engine(engine),
m_timezone(timezone),
m_range(std::pair<DateTime,DateTime>(DateTime::NowLocal(), DateTime::NowLocal()))
@@ -38,6 +38,11 @@ SimpleRangePlanner::SimpleRangePlanner(const std::shared_ptr<Engine>& engine,
rebuild_soon();
});
+ m_timezone->timezone.changed().connect([this](const std::string& s){
+ g_debug("RangePlanner %p rebuilding soon because the timezone changed to '%s'", this, s.c_str());
+ rebuild_soon();
+ });
+
range().changed().connect([this](const std::pair<DateTime,DateTime>&){
g_debug("rebuilding because the date range changed");
rebuild_soon();
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 <datetime/timezone-file.h>
+#include <gio/gio.h>
+
#include <cerrno>
#include <cstdlib>
-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<Impl*>(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<FileTimezone*>(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 <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()
+{
}
/****
diff --git a/src/wakeup-timer-powerd.cpp b/src/wakeup-timer-powerd.cpp
index 3c4b322..ab6859f 100644
--- a/src/wakeup-timer-powerd.cpp
+++ b/src/wakeup-timer-powerd.cpp
@@ -22,6 +22,8 @@
#include <notifications/dbus-shared.h> // BUS_POWERD_NAME
+#include <gio/gio.h>
+
#include <memory> // std::shared_ptr
namespace unity {
diff --git a/tests/manual b/tests/manual
index 2b16841..87ad674 100644
--- a/tests/manual
+++ b/tests/manual
@@ -40,6 +40,15 @@ Test-case indicator-datetime/new-alarm-wakeup
<dd>If the device supports haptic feedback, confirm the alarm vibrates.</dd>
</dl>
+Test-case indicator-datetime/alarm-timezone
+<dl>
+ <dt>In ubuntu-system-settings, change your timezone to a zone you're not in</dt>
+ <dt>In ubuntu-clock-app, create and save an upcoming alarm</dt>
+ <dd>The indicator's menu should show the alarm to click at the specified time</dd>
+ <dt>In ubuntu-system-settings, change back to your correct timezone</dt>
+ <dd>The indicator's menu should still show the alarm to click at the specified time</dd>
+</dl>
+
Test-case indicator-datetime/snooze
<dl>
<dt>Create and save an upcoming alarm in ubuntu-clock-app</dt>
diff --git a/tests/test-clock.cpp b/tests/test-clock.cpp
index 62281fb..5601d35 100644
--- a/tests/test-clock.cpp
+++ b/tests/test-clock.cpp
@@ -19,11 +19,12 @@
#include <datetime/clock.h>
#include <datetime/clock-mock.h>
-#include <datetime/timezones.h>
+#include <datetime/timezone.h>
#include <notifications/dbus-shared.h>
#include "test-dbus-fixture.h"
+#include "timezone-mock.h"
/***
****
@@ -40,9 +41,9 @@ class ClockFixture: public TestDBusFixture
TEST_F(ClockFixture, MinuteChangedSignalShouldTriggerOncePerMinute)
{
// start up a live clock
- std::shared_ptr<Timezones> zones(new Timezones);
- zones->timezone.set("America/New_York");
- LiveClock clock(zones);
+ auto timezone_ = std::make_shared<MockTimezone>();
+ timezone_->timezone.set("America/New_York");
+ LiveClock clock(timezone_);
wait_msec(500); // wait for the bus to set up
// count how many times clock.minute_changed() is emitted over the next minute
@@ -65,17 +66,17 @@ TEST_F(ClockFixture, MinuteChangedSignalShouldTriggerOncePerMinute)
TEST_F(ClockFixture, HelloFixture)
{
- std::shared_ptr<Timezones> zones(new Timezones);
- zones->timezone.set("America/New_York");
- LiveClock clock(zones);
+ auto timezone_ = std::make_shared<MockTimezone>();
+ timezone_->timezone.set("America/New_York");
+ LiveClock clock(timezone_);
}
TEST_F(ClockFixture, TimezoneChangeTriggersSkew)
{
- std::shared_ptr<Timezones> zones(new Timezones);
- zones->timezone.set("America/New_York");
- LiveClock clock(zones);
+ auto timezone_ = std::make_shared<MockTimezone>();
+ timezone_->timezone.set("America/New_York");
+ LiveClock clock(timezone_);
auto tz_nyc = g_time_zone_new("America/New_York");
auto now_nyc = g_date_time_new_now(tz_nyc);
@@ -90,9 +91,9 @@ TEST_F(ClockFixture, TimezoneChangeTriggersSkew)
g_main_loop_quit(loop);
});
g_idle_add([](gpointer gs){
- static_cast<Timezones*>(gs)->timezone.set("America/Los_Angeles");
+ static_cast<Timezone*>(gs)->timezone.set("America/Los_Angeles");
return G_SOURCE_REMOVE;
- }, zones.get());
+ }, timezone_.get());
g_main_loop_run(loop);
auto tz_la = g_time_zone_new("America/Los_Angeles");
@@ -130,9 +131,9 @@ namespace
*/
TEST_F(ClockFixture, SleepTriggersSkew)
{
- std::shared_ptr<Timezones> zones(new Timezones);
- zones->timezone.set("America/New_York");
- LiveClock clock(zones);
+ auto timezone_ = std::make_shared<MockTimezone>();
+ timezone_->timezone.set("America/New_York");
+ LiveClock clock(timezone_);
wait_msec(250); // wait for the bus to set up
bool skewed = false;