aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCharles Kerr <charles.kerr@canonical.com>2014-02-04 13:00:22 -0600
committerCharles Kerr <charles.kerr@canonical.com>2014-02-04 13:00:22 -0600
commit61581201f13509fbce9eb05fc90a5da17307c6a3 (patch)
tree75adcfe01936ed16d2958dfdbd657352be23aef5 /src
parent61accb9ce497e1f1cbe8038ac495d66d6a4505ff (diff)
downloadayatana-indicator-datetime-61581201f13509fbce9eb05fc90a5da17307c6a3.tar.gz
ayatana-indicator-datetime-61581201f13509fbce9eb05fc90a5da17307c6a3.tar.bz2
ayatana-indicator-datetime-61581201f13509fbce9eb05fc90a5da17307c6a3.zip
Add audio notitication when the alarm is triggered. Add a manual test to tests/ to trigger a snap decision.
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp15
-rw-r--r--src/snap.cpp146
2 files changed, 119 insertions, 42 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 71a1ce5..7e09fda 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -17,8 +17,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-
#include <datetime/actions-live.h>
#include <datetime/clock.h>
#include <datetime/clock-watcher.h>
@@ -33,10 +31,11 @@
#include <glib/gi18n.h> // bindtextdomain()
#include <gio/gio.h>
-#include <libnotify/notify.h>
+
+#include <url-dispatcher.h>
#include <locale.h>
-#include <stdlib.h> // exit()
+#include <cstdlib> // exit()
using namespace unity::indicator::datetime;
@@ -52,10 +51,6 @@ main(int /*argc*/, char** /*argv*/)
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> state(new State);
std::shared_ptr<Settings> live_settings(new LiveSettings);
@@ -73,7 +68,9 @@ main(int /*argc*/, char** /*argv*/)
ClockWatcherImpl clock_watcher(state);
Snap snap;
clock_watcher.alarm_reached().connect([&snap](const Appointment& appt){
- snap(appt);
+ snap(appt,
+ [](const Appointment& a){url_dispatch_send(a.url.c_str(), nullptr, nullptr);},
+ [](const Appointment&){});
});
// create the menus
diff --git a/src/snap.cpp b/src/snap.cpp
index a290f99..5f46dc7 100644
--- a/src/snap.cpp
+++ b/src/snap.cpp
@@ -22,13 +22,14 @@
#include <datetime/snap.h>
#include <datetime/utils.h> // generate_full_format_string_at_time()
-#include <url-dispatcher.h>
-
+#include <canberra.h>
#include <libnotify/notify.h>
#include <glib/gi18n.h>
#include <glib.h>
+#define ALARM_SOUND_FILENAME "/usr/share/sounds/ubuntu/stereo/phone-incoming-call.ogg"
+
namespace unity {
namespace indicator {
namespace datetime {
@@ -40,77 +41,156 @@ namespace datetime {
namespace
{
-void dispatch_alarm_url(const Appointment& appointment)
+/**
+*** libcanberra -- play sounds
+**/
+
+ca_context *c_context = nullptr;
+
+ca_context* get_ca_context()
{
- g_return_if_fail(!appointment.has_alarms);
+ if (G_UNLIKELY(c_context == nullptr))
+ {
+ int rv;
+ if ((rv = ca_context_create(&c_context)) != CA_SUCCESS)
+ {
+ g_warning("Failed to create canberra context: %s\n", ca_strerror(rv));
+ c_context = nullptr;
+ }
+ }
- const auto fmt = appointment.begin.format("%F %T");
- g_debug("dispatching url \"%s\" for appointment \"%s\", which begins at %s",
- appointment.url.c_str(),
- appointment.summary.c_str(),
- fmt.c_str());
+ return c_context;
+}
+
+void play_soundfile(const char* filename)
+{
+ auto context = get_ca_context();
+ g_return_if_fail(context != nullptr);
- url_dispatch_send(appointment.url.c_str(), nullptr, nullptr);
+ const auto rv = ca_context_play(context, 0, CA_PROP_MEDIA_FILENAME, filename, NULL);
+ if (rv != CA_SUCCESS)
+ g_warning("Failed to play file '%s': %s\n", filename, ca_strerror(rv));
}
-void on_snap_decided(NotifyNotification * /*notification*/,
- char * action,
- gpointer gurl)
+void play_alarm_sound()
{
- g_debug("%s: %s", G_STRFUNC, action);
+ play_soundfile(ALARM_SOUND_FILENAME);
+}
+
+/**
+*** libnotify -- snap decisions
+**/
- if (!g_strcmp0(action, "show"))
+void first_time_init()
+{
+ static bool inited = false;
+
+ if (G_UNLIKELY(!inited))
{
- const auto url = static_cast<const gchar*>(gurl);
- g_debug("dispatching url '%s'", url);
- url_dispatch_send(url, nullptr, nullptr);
+ inited = true;
+
+ if(!notify_init("indicator-datetime-service"))
+ g_critical("libnotify initialization failed");
}
}
-} // unnamed namespace
+struct SnapData
+{
+ Snap::appointment_func show;
+ Snap::appointment_func dismiss;
+ Appointment appointment;
+};
-/***
-****
-***/
+void on_snap_show(NotifyNotification*, gchar* /*action*/, gpointer gdata)
+{
+ auto data = static_cast<SnapData*>(gdata);
+ data->show(data->appointment);
+}
-Snap::Snap()
+void on_snap_dismiss(NotifyNotification*, gchar* /*action*/, gpointer gdata)
{
+ auto data = static_cast<SnapData*>(gdata);
+ data->dismiss(data->appointment);
}
-Snap::~Snap()
+void snap_data_destroy_notify(gpointer gdata)
{
+ delete static_cast<SnapData*>(gdata);
}
-void Snap::operator()(const Appointment& appointment)
+void show_snap_decision(SnapData* data)
{
- if (!appointment.has_alarms)
- return;
+ const Appointment& appointment = data->appointment;
- auto timestr = generate_full_format_string_at_time (appointment.begin.get(), nullptr, nullptr);
+ auto timestr = generate_full_format_string_at_time(appointment.begin.get(), nullptr, nullptr);
auto title = g_strdup_printf(_("Alarm %s"), timestr);
const auto body = appointment.summary;
const gchar* icon_name = "alarm-clock";
- g_debug("creating a snap decision with title '%s', body '%s', icon '%s'", title, body.c_str(), icon_name);
auto nn = notify_notification_new(title, body.c_str(), icon_name);
notify_notification_set_hint_string(nn, "x-canonical-snap-decisions", "true");
notify_notification_set_hint_string(nn, "x-canonical-private-button-tint", "true");
- notify_notification_add_action(nn, "show", _("Show"), on_snap_decided, g_strdup(appointment.url.c_str()), g_free);
- notify_notification_add_action(nn, "dismiss", _("Dismiss"), on_snap_decided, nullptr, nullptr);
+ notify_notification_add_action(nn, "show", _("Show"), on_snap_show, data, nullptr);
+ notify_notification_add_action(nn, "dismiss", _("Dismiss"), on_snap_dismiss, data, nullptr);
+ g_object_set_data_full(G_OBJECT(nn), "snap-data", data, snap_data_destroy_notify);
GError * error = nullptr;
notify_notification_show(nn, &error);
if (error != NULL)
{
- g_warning("Unable to show alarm '%s' popup: %s", body.c_str(), error->message);
+ g_warning("Unable to show snap decision for '%s': %s", body.c_str(), error->message);
g_error_free(error);
- dispatch_alarm_url(appointment);
+ data->show(data->appointment);
}
g_free(title);
g_free(timestr);
}
+/**
+***
+**/
+
+void notify(const Appointment& appointment,
+ Snap::appointment_func show,
+ Snap::appointment_func dismiss)
+{
+ auto data = new SnapData;
+ data->appointment = appointment;
+ data->show = show;
+ data->dismiss = dismiss;
+
+ play_alarm_sound();
+ show_snap_decision(data);
+}
+
+} // unnamed namespace
+
+
+/***
+****
+***/
+
+Snap::Snap()
+{
+ first_time_init();
+}
+
+Snap::~Snap()
+{
+ g_clear_pointer(&c_context, ca_context_destroy);
+}
+
+void Snap::operator()(const Appointment& appointment,
+ appointment_func show,
+ appointment_func dismiss)
+{
+ if (appointment.has_alarms)
+ notify(appointment, show, dismiss);
+ else
+ dismiss(appointment);
+}
+
/***
****
***/