=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2014-02-10 22:59:02 +0000
+++ CMakeLists.txt 2014-02-19 15:36:23 +0000
@@ -38,10 +38,10 @@
libical>=0.48
libecal-1.2>=3.5
libedataserver-1.2>=3.5
+ libcanberra>=0.12
libnotify>=0.7.6
url-dispatcher-1>=1
- properties-cpp>=0.0.1
- json-glib-1.0>=0.16.2)
+ properties-cpp>=0.0.1)
include_directories (SYSTEM ${SERVICE_DEPS_INCLUDE_DIRS})
##
=== modified file 'debian/control'
--- debian/control 2014-02-11 20:06:28 +0000
+++ debian/control 2014-02-19 15:36:23 +0000
@@ -16,13 +16,13 @@
libgtest-dev,
libglib2.0-dev (>= 2.35.4),
libnotify-dev (>= 0.7.6),
+ libcanberra-dev,
libido3-0.1-dev (>= 0.2.90),
libgeoclue-dev (>= 0.12.0),
libecal1.2-dev (>= 3.5),
libical-dev (>= 1.0),
libgtk-3-dev (>= 3.1.4),
libcairo2-dev (>= 1.10),
- libjson-glib-dev,
libpolkit-gobject-1-dev,
libedataserver1.2-dev (>= 3.5),
libgconf2-dev (>= 2.31),
=== added file 'include/datetime/clock-watcher.h'
--- include/datetime/clock-watcher.h 1970-01-01 00:00:00 +0000
+++ include/datetime/clock-watcher.h 2014-02-19 15:36:23 +0000
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014 Canonical Ltd.
+ *
+ * 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 .
+ *
+ * Authors:
+ * Charles Kerr
+ */
+
+#ifndef INDICATOR_DATETIME_CLOCK_WATCHER_H
+#define INDICATOR_DATETIME_CLOCK_WATCHER_H
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+
+/**
+ * \brief Watches the clock and appointments to notify when an
+ * appointment's time is reached.
+ */
+class ClockWatcher
+{
+public:
+ ClockWatcher() =default;
+ virtual ~ClockWatcher() =default;
+ virtual core::Signal& alarm_reached() = 0;
+};
+
+
+/**
+ * \brief A #ClockWatcher implementation
+ */
+class ClockWatcherImpl: public ClockWatcher
+{
+public:
+ ClockWatcherImpl(const std::shared_ptr& state);
+ ~ClockWatcherImpl() =default;
+ core::Signal& alarm_reached();
+
+private:
+ void pulse();
+ std::set m_triggered;
+ std::shared_ptr m_state;
+ core::Signal m_alarm_reached;
+};
+
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_CLOCK_WATCHER_H
=== modified file 'include/datetime/date-time.h'
--- include/datetime/date-time.h 2014-01-30 19:00:22 +0000
+++ include/datetime/date-time.h 2014-02-19 15:36:23 +0000
@@ -41,6 +41,7 @@
DateTime& operator=(GDateTime* in);
DateTime& operator=(const DateTime& in);
DateTime to_timezone(const std::string& zone) const;
+ DateTime add_full(int years, int months, int days, int hours, int minutes, double seconds) const;
void reset(GDateTime* in=nullptr);
GDateTime* get() const;
@@ -48,9 +49,11 @@
std::string format(const std::string& fmt) const;
int day_of_month() const;
+ double seconds() const;
int64_t to_unix() const;
bool operator<(const DateTime& that) const;
+ bool operator<=(const DateTime& that) const;
bool operator!=(const DateTime& that) const;
bool operator==(const DateTime& that) const;
=== modified file 'include/datetime/planner-eds.h'
--- include/datetime/planner-eds.h 2014-01-15 05:07:10 +0000
+++ include/datetime/planner-eds.h 2014-02-19 15:36:23 +0000
@@ -20,9 +20,10 @@
#ifndef INDICATOR_DATETIME_PLANNER_EDS_H
#define INDICATOR_DATETIME_PLANNER_EDS_H
+#include
#include
-#include // unique_ptr
+#include // shared_ptr, unique_ptr
namespace unity {
namespace indicator {
@@ -34,7 +35,7 @@
class PlannerEds: public Planner
{
public:
- PlannerEds();
+ PlannerEds(const std::shared_ptr& clock);
virtual ~PlannerEds();
private:
=== added file 'include/datetime/snap.h'
--- include/datetime/snap.h 1970-01-01 00:00:00 +0000
+++ include/datetime/snap.h 2014-02-19 15:36:23 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014 Canonical Ltd.
+ *
+ * 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 .
+ *
+ * Authors:
+ * Charles Kerr
+ */
+
+#ifndef INDICATOR_DATETIME_SNAP_H
+#define INDICATOR_DATETIME_SNAP_H
+
+#include
+
+#include
+#include
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief Pops up Snap Decisions for appointments
+ */
+class Snap
+{
+public:
+ Snap();
+ virtual ~Snap();
+
+ typedef std::function appointment_func;
+ void operator()(const Appointment& appointment,
+ appointment_func show,
+ appointment_func dismiss);
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_SNAP_H
=== modified file 'include/datetime/timezone-file.h'
--- include/datetime/timezone-file.h 2014-01-30 19:00:22 +0000
+++ include/datetime/timezone-file.h 2014-02-19 15:36:23 +0000
@@ -42,8 +42,8 @@
~FileTimezone();
private:
- void setFilename(const std::string& filename);
- static void onFileChanged(gpointer gself);
+ void set_filename(const std::string& filename);
+ static void on_file_changed(gpointer gself);
void clear();
void reload();
=== modified file 'po/POTFILES.in'
--- po/POTFILES.in 2014-02-10 22:59:02 +0000
+++ po/POTFILES.in 2014-02-19 15:36:23 +0000
@@ -1,3 +1,5 @@
src/formatter.cpp
src/formatter-desktop.cpp
src/menu.cpp
+src/snap.cpp
+src/utils.c
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2014-02-10 22:59:02 +0000
+++ src/CMakeLists.txt 2014-02-19 15:36:23 +0000
@@ -13,6 +13,7 @@
appointment.cpp
clock.cpp
clock-live.cpp
+ clock-watcher.cpp
date-time.cpp
exporter.cpp
formatter.cpp
@@ -22,6 +23,7 @@
menu.cpp
planner-eds.cpp
settings-live.cpp
+ snap.cpp
timezone-file.cpp
timezone-geoclue.cpp
timezones-live.cpp
=== modified file 'src/actions-live.cpp'
--- src/actions-live.cpp 2014-02-10 22:59:02 +0000
+++ src/actions-live.cpp 2014-02-19 15:36:23 +0000
@@ -156,7 +156,7 @@
GError * err = nullptr;
auto proxy = g_dbus_proxy_new_for_bus_finish(res, &err);
- if (err != NULL)
+ if (err != nullptr)
{
if (!g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning("Could not grab DBus proxy for timedated: %s", err->message);
=== added file 'src/clock-watcher.cpp'
--- src/clock-watcher.cpp 1970-01-01 00:00:00 +0000
+++ src/clock-watcher.cpp 2014-02-19 15:36:23 +0000
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 Canonical Ltd.
+ *
+ * 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 .
+ *
+ * Authors:
+ * Charles Kerr
+ */
+
+#include
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/***
+****
+***/
+
+ClockWatcherImpl::ClockWatcherImpl(const std::shared_ptr& state):
+ m_state(state)
+{
+ m_state->planner->upcoming.changed().connect([this](const std::vector&){
+ g_debug("ClockWatcher pulse because upcoming appointments changed");
+ pulse();
+ });
+ m_state->clock->minute_changed.connect([this](){
+ g_debug("ClockWatcher pulse because clock minute_changed");
+ pulse();
+ });
+ pulse();
+}
+
+core::Signal& ClockWatcherImpl::alarm_reached()
+{
+ return m_alarm_reached;
+}
+
+void ClockWatcherImpl::pulse()
+{
+ const auto now = m_state->clock->localtime();
+
+ for(const auto& appointment : m_state->planner->upcoming.get())
+ {
+ if (m_triggered.count(appointment.uid))
+ continue;
+ if (!DateTime::is_same_minute(now, appointment.begin))
+ continue;
+
+ m_triggered.insert(appointment.uid);
+ m_alarm_reached(appointment);
+ }
+}
+
+/***
+****
+***/
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
=== modified file 'src/date-time.cpp'
--- src/date-time.cpp 2014-01-30 19:00:22 +0000
+++ src/date-time.cpp 2014-02-19 15:36:23 +0000
@@ -69,6 +69,14 @@
return dt;
}
+DateTime DateTime::add_full(int years, int months, int days, int hours, int minutes, double seconds) const
+{
+ auto gdt = g_date_time_add_full(get(), years, months, days, hours, minutes, seconds);
+ DateTime dt(gdt);
+ g_date_time_unref(gdt);
+ return dt;
+}
+
GDateTime* DateTime::get() const
{
g_assert(m_dt);
@@ -88,6 +96,11 @@
return g_date_time_get_day_of_month(get());
}
+double DateTime::seconds() const
+{
+ return g_date_time_get_seconds(get());
+}
+
int64_t DateTime::to_unix() const
{
return g_date_time_to_unix(get());
@@ -112,6 +125,11 @@
return g_date_time_compare(get(), that.get()) < 0;
}
+bool DateTime::operator<=(const DateTime& that) const
+{
+ return g_date_time_compare(get(), that.get()) <= 0;
+}
+
bool DateTime::operator!=(const DateTime& that) const
{
// return true if this isn't set, or if it's not equal
=== modified file 'src/main.cpp'
--- src/main.cpp 2014-01-30 19:06:33 +0000
+++ src/main.cpp 2014-02-19 15:36:23 +0000
@@ -17,24 +17,25 @@
* with this program. If not, see .
*/
-
-
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include // bindtextdomain()
#include
-#include
+
+#include
#include
-#include // exit()
+#include // exit()
using namespace unity::indicator::datetime;
@@ -50,10 +51,6 @@
bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR);
textdomain(GETTEXT_PACKAGE);
- // init libnotify
- if(!notify_init("indicator-datetime-service"))
- g_critical("libnotify initialization failed");
-
// build the state, actions, and menufactory
std::shared_ptr state(new State);
std::shared_ptr live_settings(new LiveSettings);
@@ -62,11 +59,27 @@
state->settings = live_settings;
state->clock = live_clock;
state->locations.reset(new SettingsLocations(live_settings, live_timezones));
- state->planner.reset(new PlannerEds);
+ state->planner.reset(new PlannerEds(live_clock));
state->planner->time = live_clock->localtime();
std::shared_ptr actions(new LiveActions(state));
MenuFactory factory(actions, state);
+ // snap decisions
+ ClockWatcherImpl clock_watcher(state);
+ Snap snap;
+ clock_watcher.alarm_reached().connect([&snap](const Appointment& appt){
+ auto snap_show = [](const Appointment& a){
+ const char* url;
+ if(!a.url.empty())
+ url = a.url.c_str();
+ else // alarm doesn't have a URl associated with it; use a fallback
+ url = "appid://com.ubuntu.clock/clock/current-user-version";
+ url_dispatch_send(url, nullptr, nullptr);
+ };
+ auto snap_dismiss = [](const Appointment&){};
+ snap(appt, snap_show, snap_dismiss);
+ });
+
// create the menus
std::vector> menus;
for(int i=0, n=Menu::NUM_PROFILES; i
#include
-#include
-
#include
#include
+#include
+
namespace unity {
namespace indicator {
namespace datetime {
@@ -62,7 +62,7 @@
****/
-#define FALLBACK_ALARM_CLOCK_ICON_NAME "clock"
+#define ALARM_ICON_NAME "alarm-clock"
#define CALENDAR_ICON_NAME "calendar"
class MenuImpl: public Menu
@@ -105,12 +105,15 @@
update_section(Appointments); // showing events got toggled
});
m_state->planner->upcoming.changed().connect([this](const std::vector&){
- update_section(Appointments); // "upcoming" is the list of Appointments we show
+ update_upcoming(); // our m_upcoming is planner->upcoming() filtered by time
});
m_state->clock->date_changed.connect([this](){
update_section(Calendar); // need to update the Date menuitem
update_section(Locations); // locations' relative time may have changed
});
+ m_state->clock->minute_changed.connect([this](){
+ update_upcoming(); // our m_upcoming is planner->upcoming() filtered by time
+ });
m_state->locations->locations.changed().connect([this](const std::vector&) {
update_section(Locations); // "locations" is the list of Locations we show
});
@@ -133,6 +136,24 @@
g_action_group_change_action_state(action_group, action_name.c_str(), state);
}
+ void update_upcoming()
+ {
+ const auto now = m_state->clock->localtime();
+ const auto next_minute = now.add_full(0,0,0,0,1,-now.seconds());
+
+ std::vector upcoming;
+ for(const auto& a : m_state->planner->upcoming.get())
+ if (next_minute <= a.begin)
+ upcoming.push_back(a);
+
+ if (m_upcoming != upcoming)
+ {
+ m_upcoming.swap(upcoming);
+ update_header(); // show an 'alarm' icon if there are upcoming alarms
+ update_section(Appointments); // "upcoming" is the list of Appointments we show
+ }
+ }
+
std::shared_ptr m_state;
std::shared_ptr m_actions;
std::shared_ptr m_formatter;
@@ -141,71 +162,19 @@
GVariant* get_serialized_alarm_icon()
{
if (G_UNLIKELY(m_serialized_alarm_icon == nullptr))
- m_serialized_alarm_icon = create_alarm_icon();
+ {
+ auto i = g_themed_icon_new_with_default_fallbacks(ALARM_ICON_NAME);
+ m_serialized_alarm_icon = g_icon_serialize(i);
+ g_object_unref(i);
+ }
return m_serialized_alarm_icon;
}
+ std::vector m_upcoming;
+
private:
- /* try to get the clock app's filename from click. (/$pkgdir/$icon) */
- static GVariant* create_alarm_icon()
- {
- GVariant* serialized = nullptr;
- gchar* icon_filename = nullptr;
- gchar* standard_error = nullptr;
- gchar* pkgdir = nullptr;
-
- g_spawn_command_line_sync("click pkgdir com.ubuntu.clock", &pkgdir, &standard_error, nullptr, nullptr);
- g_clear_pointer(&standard_error, g_free);
- if (pkgdir != nullptr)
- {
- gchar* manifest = nullptr;
- g_strstrip(pkgdir);
- g_spawn_command_line_sync("click info com.ubuntu.clock", &manifest, &standard_error, nullptr, nullptr);
- g_clear_pointer(&standard_error, g_free);
- if (manifest != nullptr)
- {
- JsonParser* parser = json_parser_new();
- if (json_parser_load_from_data(parser, manifest, -1, nullptr))
- {
- JsonNode* root = json_parser_get_root(parser); /* transfer-none */
- if ((root != nullptr) && (JSON_NODE_TYPE(root) == JSON_NODE_OBJECT))
- {
- JsonObject* o = json_node_get_object(root); /* transfer-none */
- const gchar* icon_name = json_object_get_string_member(o, "icon");
- if (icon_name != nullptr)
- icon_filename = g_build_filename(pkgdir, icon_name, nullptr);
- }
- }
- g_object_unref(parser);
- g_free(manifest);
- }
- g_free(pkgdir);
- }
-
- if (icon_filename != nullptr)
- {
- GFile* file = g_file_new_for_path(icon_filename);
- GIcon* icon = g_file_icon_new(file);
-
- serialized = g_icon_serialize(icon);
-
- g_object_unref(icon);
- g_object_unref(file);
- g_free(icon_filename);
- }
-
- if (serialized == nullptr)
- {
- auto i = g_themed_icon_new_with_default_fallbacks(FALLBACK_ALARM_CLOCK_ICON_NAME);
- serialized = g_icon_serialize(i);
- g_object_unref(i);
- }
-
- return serialized;
- }
-
GVariant* get_serialized_calendar_icon()
{
if (G_UNLIKELY(m_serialized_calendar_icon == nullptr))
@@ -273,7 +242,7 @@
// add calendar
if (show_calendar)
{
- item = g_menu_item_new ("[calendar]", NULL);
+ item = g_menu_item_new ("[calendar]", nullptr);
v = g_variant_new_int64(0);
g_menu_item_set_action_and_target_value (item, "indicator.calendar", v);
g_menu_item_set_attribute (item, "x-canonical-type",
@@ -296,11 +265,13 @@
const int MAX_APPTS = 5;
std::set added;
- for (const auto& appt : m_state->planner->upcoming.get())
+ for (const auto& appt : m_upcoming)
{
+ // don't show too many
if (n++ >= MAX_APPTS)
break;
+ // don't show duplicates
if (added.count(appt.uid))
continue;
@@ -508,7 +479,7 @@
{
// are there alarms?
bool has_alarms = false;
- for(const auto& appointment : m_state->planner->upcoming.get())
+ for(const auto& appointment : m_upcoming)
if((has_alarms = appointment.has_alarms))
break;
=== modified file 'src/planner-eds.cpp'
--- src/planner-eds.cpp 2014-01-31 00:33:14 +0000
+++ src/planner-eds.cpp 2014-02-19 15:36:23 +0000
@@ -26,6 +26,9 @@
#include
#include
+#include