[gnome-shell] NotificationDaemon: support sound in notifications



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]