From 61581201f13509fbce9eb05fc90a5da17307c6a3 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 4 Feb 2014 13:00:22 -0600 Subject: Add audio notitication when the alarm is triggered. Add a manual test to tests/ to trigger a snap decision. --- src/main.cpp | 15 +++--- src/snap.cpp | 146 +++++++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 119 insertions(+), 42 deletions(-) (limited to 'src') 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 . */ - - #include #include #include @@ -33,10 +31,11 @@ #include // bindtextdomain() #include -#include + +#include #include -#include // exit() +#include // 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(new State); std::shared_ptr 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 #include // generate_full_format_string_at_time() -#include - +#include #include #include #include +#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(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(gdata); + data->show(data->appointment); +} -Snap::Snap() +void on_snap_dismiss(NotifyNotification*, gchar* /*action*/, gpointer gdata) { + auto data = static_cast(gdata); + data->dismiss(data->appointment); } -Snap::~Snap() +void snap_data_destroy_notify(gpointer gdata) { + delete static_cast(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); +} + /*** **** ***/ -- cgit v1.2.3