[gnome-shell] NotificationDaemon: support sound in notifications
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] NotificationDaemon: support sound in notifications
- Date: Thu, 14 Feb 2013 17:54:45 +0000 (UTC)
commit c30661c44c47286a0fa30bb8c10e5fa41053c358
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Mon Nov 5 18:10:24 2012 +0100
NotificationDaemon: support sound in notifications
The notifications spec has two hints for playing a sound, sound-file
and sound-name. We can support them using the existing code that
wraps libcanberra.
https://bugzilla.gnome.org/show_bug.cgi?id=642831
js/ui/messageTray.js | 69 +++++++++++++++++++++++++++++++++++++++---
js/ui/notificationDaemon.js | 6 ++-
src/shell-global.c | 69 +++++++++++++++++++++++++++++++++++++++++--
src/shell-global.h | 13 ++++++++
4 files changed, 147 insertions(+), 10 deletions(-)
---
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index d4bd7b5..7376456 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -331,6 +331,10 @@ Signals.addSignalMethods(NotificationPolicy.prototype);
// the content and the action area of the notification will be cleared.
// The content area is also always cleared if 'customContent' is false
// because it might contain the @banner that didn't fit in the banner mode.
+//
+// If @params contains 'soundName' or 'soundFile', the corresponding
+// event sound is played when the notification is shown (if the policy for
+// @source allows playing sounds).
const Notification = new Lang.Class({
Name: 'Notification',
@@ -360,6 +364,9 @@ const Notification = new Lang.Class({
this._spacing = 0;
this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
this._imageBin = null;
+ this._soundName = null;
+ this._soundFile = null;
+ this._soundPlayed = false;
source.connect('destroy', Lang.bind(this,
function (source, reason) {
@@ -426,7 +433,9 @@ const Notification = new Lang.Class({
titleMarkup: false,
bannerMarkup: false,
bodyMarkup: false,
- clear: false });
+ clear: false,
+ soundName: null,
+ soundFile: null });
this._customContent = params.customContent;
@@ -524,6 +533,14 @@ const Notification = new Lang.Class({
if (params.body)
this.addBody(params.body, params.bodyMarkup);
+
+ if (this._soundName != params.soundName ||
+ this._soundFile != params.soundFile) {
+ this._soundName = params.soundName;
+ this._soundFile = params.soundFile;
+ this._soundPlayed = false;
+ }
+
this.updated();
},
@@ -884,6 +901,38 @@ const Notification = new Lang.Class({
(!this._titleFitsInBannerMode &&
!this._table.has_style_class_name('multi-line-notification'));
},
+ playSound: function() {
+ if (this._soundPlayed)
+ return;
+
+ if (!this.source.policy.enableSound) {
+ this._soundPlayed = true;
+ return;
+ }
+
+ if (this._soundName) {
+ if (this.source.app) {
+ let app = this.source.app;
+
+ global.play_theme_sound_full(0, this._soundName,
+ this.title, null,
+ app.get_id(), app.get_name());
+ } else {
+ global.play_theme_sound(0, this._soundName, this.title, null);
+ }
+ } else if (this._soundFile) {
+ if (this.source.app) {
+ let app = this.source.app;
+
+ global.play_sound_file_full(0, this._soundFile,
+ this.title, null,
+ app.get_id(), app.get_name());
+ } else {
+ global.play_sound_file(0, this._soundFile, this.title, null);
+ }
+ }
+ },
+
updated: function() {
if (this.expanded)
this.expand(false);
@@ -1233,8 +1282,16 @@ const Source = new Lang.Class({
notification.acknowledged = false;
this.pushNotification(notification);
- if (!this.isMuted && this.policy.showBanners)
- this.emit('notify', notification);
+ if (!this.isMuted) {
+ // Play the sound now, if banners are disabled.
+ // Otherwise, it will be played when the notification
+ // is next shown.
+ if (this.policy.showBanners) {
+ this.emit('notify', notification);
+ } else {
+ notification.playSound();
+ }
+ }
},
destroy: function(reason) {
@@ -1998,9 +2055,10 @@ const MessageTray = new Lang.Class({
} else {
// The summary box pointer is showing or shown (otherwise,
// this._summaryBoxPointerItem would be null)
- // Immediately mark the notification as acknowledged, as it's
- // not going into the queue
+ // Immediately mark the notification as acknowledged and play its
+ // sound, as it's not going into the queue
notification.acknowledged = true;
+ notification.playSound();
}
return;
@@ -2434,6 +2492,7 @@ const MessageTray = new Lang.Class({
_updateShowingNotification: function() {
this._notification.acknowledged = true;
+ this._notification.playSound();
// We auto-expand notifications with CRITICAL urgency, or for which the relevant setting
// is on in the control center.
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index e02bf22..28d2cfb 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -527,7 +527,9 @@ const NotificationDaemon = new Lang.Class({
notification.update(summary, body, { gicon: gicon,
bannerMarkup: true,
- clear: true });
+ clear: true,
+ soundFile: hints['sound-file'],
+ soundName: hints['sound-name'] });
notification.setImage(image);
if (actions.length) {
@@ -582,7 +584,7 @@ const NotificationDaemon = new Lang.Class({
// 'icon-multi',
'icon-static',
'persistence',
- // 'sound',
+ 'sound',
];
},
diff --git a/src/shell-global.c b/src/shell-global.c
index 7344334..e8559eb 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -1537,11 +1537,12 @@ shell_global_run_at_leisure (ShellGlobal *global,
static void
build_ca_proplist_for_event (ca_proplist *props,
+ const char *event_property,
const char *event_id,
const char *event_description,
ClutterEvent *for_event)
{
- ca_proplist_sets (props, CA_PROP_EVENT_ID, event_id);
+ ca_proplist_sets (props, event_property, event_id);
ca_proplist_sets (props, CA_PROP_EVENT_DESCRIPTION, event_description);
ca_proplist_sets (props, CA_PROP_CANBERRA_CACHE_CONTROL, "volatile");
@@ -1589,7 +1590,7 @@ shell_global_play_theme_sound (ShellGlobal *global,
ca_proplist *props;
ca_proplist_create (&props);
- build_ca_proplist_for_event (props, name, description, for_event);
+ build_ca_proplist_for_event (props, CA_PROP_EVENT_ID, name, description, for_event);
ca_context_play_full (global->sound_context, id, props, NULL, NULL);
@@ -1621,7 +1622,7 @@ shell_global_play_theme_sound_full (ShellGlobal *global,
ca_proplist *props;
ca_proplist_create (&props);
- build_ca_proplist_for_event (props, name, description, for_event);
+ build_ca_proplist_for_event (props, CA_PROP_EVENT_ID, name, description, for_event);
ca_proplist_sets (props, CA_PROP_APPLICATION_ID, application_id);
ca_proplist_sets (props, CA_PROP_APPLICATION_NAME, application_name);
@@ -1631,6 +1632,68 @@ shell_global_play_theme_sound_full (ShellGlobal *global,
}
/**
+ * shell_global_play_sound_file_full:
+ * @global: the #ShellGlobal
+ * @id: an id, used to cancel later (0 if not needed)
+ * @file_name: the file name to play
+ * @description: the localized description of the event that triggered this alert
+ * @for_event: (allow-none): a #ClutterEvent in response to which the sound is played
+ * @application_id: application on behalf of which the sound is played
+ * @application_name:
+ *
+ * Like shell_global_play_theme_sound_full(), but with an explicit path
+ * instead of a themed sound.
+ */
+void
+shell_global_play_sound_file_full (ShellGlobal *global,
+ guint id,
+ const char *file_name,
+ const char *description,
+ ClutterEvent *for_event,
+ const char *application_id,
+ const char *application_name)
+{
+ ca_proplist *props;
+
+ ca_proplist_create (&props);
+ build_ca_proplist_for_event (props, CA_PROP_MEDIA_FILENAME, file_name, description, for_event);
+ ca_proplist_sets (props, CA_PROP_APPLICATION_ID, application_id);
+ ca_proplist_sets (props, CA_PROP_APPLICATION_NAME, application_name);
+
+ ca_context_play_full (global->sound_context, id, props, NULL, NULL);
+
+ ca_proplist_destroy (props);
+}
+
+/**
+ * shell_global_play_sound_file:
+ * @global: the #ShellGlobal
+ * @id: an id, used to cancel later (0 if not needed)
+ * @file_name: the file name to play
+ * @description: the localized description of the event that triggered this alert
+ * @for_event: (allow-none): a #ClutterEvent in response to which the sound is played
+ *
+ * Like shell_global_play_theme_sound(), but with an explicit path
+ * instead of a themed sound.
+ */
+void
+shell_global_play_sound_file (ShellGlobal *global,
+ guint id,
+ const char *file_name,
+ const char *description,
+ ClutterEvent *for_event)
+{
+ ca_proplist *props;
+
+ ca_proplist_create (&props);
+ build_ca_proplist_for_event (props, CA_PROP_MEDIA_FILENAME, file_name, description, for_event);
+
+ ca_context_play_full (global->sound_context, id, props, NULL, NULL);
+
+ ca_proplist_destroy (props);
+}
+
+/**
* shell_global_cancel_theme_sound:
* @global: the #ShellGlobal
* @id: the id previously passed to shell_global_play_theme_sound()
diff --git a/src/shell-global.h b/src/shell-global.h
index 88b40be..a8df0f5 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -124,6 +124,19 @@ void shell_global_play_theme_sound_full (ShellGlobal *global,
ClutterEvent *for_event,
const char *application_id,
const char *application_name);
+void shell_global_play_sound_file (ShellGlobal *global,
+ guint id,
+ const char *file_name,
+ const char *description,
+ ClutterEvent *for_event);
+void shell_global_play_sound_file_full (ShellGlobal *global,
+ guint id,
+ const char *file_name,
+ const char *description,
+ ClutterEvent *for_event,
+ const char *application_id,
+ const char *application_name);
+
void shell_global_cancel_theme_sound (ShellGlobal *global,
guint id);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]