diff options
-rw-r--r-- | include/datetime/appointment.h | 1 | ||||
-rw-r--r-- | src/engine-eds.cpp | 18 | ||||
-rw-r--r-- | src/snap.cpp | 89 |
3 files changed, 82 insertions, 26 deletions
diff --git a/include/datetime/appointment.h b/include/datetime/appointment.h index 4778293..2e406a2 100644 --- a/include/datetime/appointment.h +++ b/include/datetime/appointment.h @@ -39,6 +39,7 @@ public: std::string summary; std::string url; std::string uid; + std::string audio_url; bool has_alarms = false; DateTime begin; DateTime end; diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp index 1949193..80a47da 100644 --- a/src/engine-eds.cpp +++ b/src/engine-eds.cpp @@ -443,8 +443,9 @@ private: appointment.color = subtask->color; appointment.uid = uid; - // if the component has display alarms that have a url, - // use the first one as our Appointment.url + // Look through all of this component's alarms + // for DISPLAY or AUDIO url attachments. + // If we find any, use them for appointment.url and audio_sound auto alarm_uids = e_cal_component_get_alarm_uids(component); appointment.has_alarms = alarm_uids != nullptr; for(auto walk=alarm_uids; appointment.url.empty() && walk!=nullptr; walk=walk->next) @@ -453,7 +454,7 @@ private: ECalComponentAlarmAction action; e_cal_component_alarm_get_action(alarm, &action); - if (action == E_CAL_COMPONENT_ALARM_DISPLAY) + if ((action == E_CAL_COMPONENT_ALARM_DISPLAY) || (action == E_CAL_COMPONENT_ALARM_AUDIO)) { icalattach* attach = nullptr; e_cal_component_alarm_get_attach(alarm, &attach); @@ -463,7 +464,16 @@ private: { const char* url = icalattach_get_url(attach); if (url != nullptr) - appointment.url = url; + { + if ((action == E_CAL_COMPONENT_ALARM_DISPLAY) && appointment.url.empty()) + { + appointment.url = url; + } + else if ((action == E_CAL_COMPONENT_ALARM_AUDIO) && appointment.audio_url.empty()) + { + appointment.audio_url = url; + } + } } icalattach_unref(attach); diff --git a/src/snap.cpp b/src/snap.cpp index 8e9dfbe..78602d3 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -32,8 +32,6 @@ #include <set> #include <string> -#define FALLBACK_ALARM_SOUND "/usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg" - namespace unity { namespace indicator { namespace datetime { @@ -54,9 +52,9 @@ class LoopedSound public: - LoopedSound(const std::shared_ptr<const Settings>& settings): - m_filename(settings->alarm_sound.get()), - m_volume(settings->alarm_volume.get()), + LoopedSound(const std::string& filename, const AlarmVolume volume): + m_filename(filename), + m_volume(volume), m_canberra_id(get_next_canberra_id()) { const auto rv = ca_context_create(&m_context); @@ -118,21 +116,13 @@ private: auto context = m_context; g_return_if_fail(context != nullptr); - std::string filename = m_filename; - if (!g_file_test(filename.c_str(), G_FILE_TEST_EXISTS)) - { - g_warning("Unable to find '%s' -- using fallback '%s' instead", - filename.c_str(), FALLBACK_ALARM_SOUND); - filename = FALLBACK_ALARM_SOUND; - } - ca_proplist* props = nullptr; ca_proplist_create(&props); - ca_proplist_sets(props, CA_PROP_MEDIA_FILENAME, filename.c_str()); + ca_proplist_sets(props, CA_PROP_MEDIA_FILENAME, m_filename.c_str()); ca_proplist_setf(props, CA_PROP_CANBERRA_VOLUME, "%f", get_decibel_multiplier(m_volume)); const auto rv = ca_context_play_full(context, m_canberra_id, props, on_done_playing, this); if (rv != CA_SUCCESS) - g_warning("Failed to play file '%s': %s", filename.c_str(), ca_strerror(rv)); + g_warning("Failed to play file '%s': %s", m_filename.c_str(), ca_strerror(rv)); g_clear_pointer(&props, ca_proplist_destroy); } @@ -177,9 +167,11 @@ class Popup public: Popup(const Appointment& appointment, - const std::shared_ptr<const Settings>& settings): + const std::string& sound_filename, + const AlarmVolume sound_volume): m_appointment(appointment), - m_settings(settings), + m_sound_filename(sound_filename), + m_sound_volume(sound_volume), m_mode(get_mode()) { show(); @@ -238,10 +230,10 @@ private: shown = false; } - // if we were able to show a popup that requires - // user response, play the sound in a loop + // if we were able to show a popup that requires user response, + // play the sound in a loop if (shown && (m_mode == MODE_SNAP)) - m_sound.reset(new LoopedSound(m_settings)); + m_sound.reset(new LoopedSound(m_sound_filename, m_sound_volume)); // if showing the notification didn't work, // treat it as if the user clicked the 'show' button @@ -337,7 +329,8 @@ private: typedef Popup Self; const Appointment m_appointment; - const std::shared_ptr<const Settings> m_settings; + const std::string m_sound_filename; + const AlarmVolume m_sound_volume; const Mode m_mode; std::unique_ptr<LoopedSound> m_sound; core::Signal<Response> m_response; @@ -362,6 +355,56 @@ void first_time_init() } } +std::string get_local_filename (const std::string& str) +{ + std::string ret; + + // maybe try it as a file path + if (ret.empty() && !str.empty()) + { + auto file = g_file_new_for_path (str.c_str()); + if (g_file_is_native(file) && g_file_query_exists(file,nullptr)) + ret = g_file_get_path(file); + g_clear_object(&file); + } + + // maybe try it as a uri + if (ret.empty() && !str.empty()) + { + auto file = g_file_new_for_uri (str.c_str()); + if (g_file_is_native(file) && g_file_query_exists(file,nullptr)) + ret = g_file_get_path(file); + g_clear_object(&file); + } + + return ret; +} + +std::string get_alarm_sound(const Appointment& appointment, + const std::shared_ptr<const Settings>& settings) +{ + static const constexpr char* const FALLBACK_AUDIO_FILENAME {"/usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg"}; + + const std::string candidates[] = { appointment.audio_url, + settings->alarm_sound.get(), + FALLBACK_AUDIO_FILENAME }; + + std::string alarm_sound; + + for (const auto& candidate : candidates) + { + alarm_sound = get_local_filename (candidate); + + if (!alarm_sound.empty()) + break; + } + + g_debug("%s: Appointment \"%s\" using alarm sound \"%s\"", + G_STRFUNC, appointment.summary.c_str(), alarm_sound.c_str()); + + return alarm_sound; +} + } // unnamed namespace /*** @@ -389,7 +432,9 @@ void Snap::operator()(const Appointment& appointment, } // create a popup... - auto popup = new Popup(appointment, m_settings); + auto popup = new Popup(appointment, + get_alarm_sound(appointment, m_settings), + m_settings->alarm_volume.get()); // listen for it to finish... popup->response().connect([appointment, |