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
This commit is contained in:
parent
2d9cf195d7
commit
c30661c44c
@ -331,6 +331,10 @@ Signals.addSignalMethods(NotificationPolicy.prototype);
|
|||||||
// the content and the action area of the notification will be cleared.
|
// the content and the action area of the notification will be cleared.
|
||||||
// The content area is also always cleared if 'customContent' is false
|
// 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.
|
// 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({
|
const Notification = new Lang.Class({
|
||||||
Name: 'Notification',
|
Name: 'Notification',
|
||||||
|
|
||||||
@ -360,6 +364,9 @@ const Notification = new Lang.Class({
|
|||||||
this._spacing = 0;
|
this._spacing = 0;
|
||||||
this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
|
this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
|
||||||
this._imageBin = null;
|
this._imageBin = null;
|
||||||
|
this._soundName = null;
|
||||||
|
this._soundFile = null;
|
||||||
|
this._soundPlayed = false;
|
||||||
|
|
||||||
source.connect('destroy', Lang.bind(this,
|
source.connect('destroy', Lang.bind(this,
|
||||||
function (source, reason) {
|
function (source, reason) {
|
||||||
@ -426,7 +433,9 @@ const Notification = new Lang.Class({
|
|||||||
titleMarkup: false,
|
titleMarkup: false,
|
||||||
bannerMarkup: false,
|
bannerMarkup: false,
|
||||||
bodyMarkup: false,
|
bodyMarkup: false,
|
||||||
clear: false });
|
clear: false,
|
||||||
|
soundName: null,
|
||||||
|
soundFile: null });
|
||||||
|
|
||||||
this._customContent = params.customContent;
|
this._customContent = params.customContent;
|
||||||
|
|
||||||
@ -524,6 +533,14 @@ const Notification = new Lang.Class({
|
|||||||
|
|
||||||
if (params.body)
|
if (params.body)
|
||||||
this.addBody(params.body, params.bodyMarkup);
|
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();
|
this.updated();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -884,6 +901,38 @@ const Notification = new Lang.Class({
|
|||||||
(!this._titleFitsInBannerMode && !this._table.has_style_class_name('multi-line-notification'));
|
(!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() {
|
updated: function() {
|
||||||
if (this.expanded)
|
if (this.expanded)
|
||||||
this.expand(false);
|
this.expand(false);
|
||||||
@ -1233,8 +1282,16 @@ const Source = new Lang.Class({
|
|||||||
notification.acknowledged = false;
|
notification.acknowledged = false;
|
||||||
this.pushNotification(notification);
|
this.pushNotification(notification);
|
||||||
|
|
||||||
if (!this.isMuted && this.policy.showBanners)
|
if (!this.isMuted) {
|
||||||
this.emit('notify', notification);
|
// 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) {
|
destroy: function(reason) {
|
||||||
@ -1998,9 +2055,10 @@ const MessageTray = new Lang.Class({
|
|||||||
} else {
|
} else {
|
||||||
// The summary box pointer is showing or shown (otherwise,
|
// The summary box pointer is showing or shown (otherwise,
|
||||||
// this._summaryBoxPointerItem would be null)
|
// this._summaryBoxPointerItem would be null)
|
||||||
// Immediately mark the notification as acknowledged, as it's
|
// Immediately mark the notification as acknowledged and play its
|
||||||
// not going into the queue
|
// sound, as it's not going into the queue
|
||||||
notification.acknowledged = true;
|
notification.acknowledged = true;
|
||||||
|
notification.playSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -2434,6 +2492,7 @@ const MessageTray = new Lang.Class({
|
|||||||
|
|
||||||
_updateShowingNotification: function() {
|
_updateShowingNotification: function() {
|
||||||
this._notification.acknowledged = true;
|
this._notification.acknowledged = true;
|
||||||
|
this._notification.playSound();
|
||||||
|
|
||||||
// We auto-expand notifications with CRITICAL urgency, or for which the relevant setting
|
// We auto-expand notifications with CRITICAL urgency, or for which the relevant setting
|
||||||
// is on in the control center.
|
// is on in the control center.
|
||||||
|
@ -527,7 +527,9 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
|
|
||||||
notification.update(summary, body, { gicon: gicon,
|
notification.update(summary, body, { gicon: gicon,
|
||||||
bannerMarkup: true,
|
bannerMarkup: true,
|
||||||
clear: true });
|
clear: true,
|
||||||
|
soundFile: hints['sound-file'],
|
||||||
|
soundName: hints['sound-name'] });
|
||||||
notification.setImage(image);
|
notification.setImage(image);
|
||||||
|
|
||||||
if (actions.length) {
|
if (actions.length) {
|
||||||
@ -582,7 +584,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
// 'icon-multi',
|
// 'icon-multi',
|
||||||
'icon-static',
|
'icon-static',
|
||||||
'persistence',
|
'persistence',
|
||||||
// 'sound',
|
'sound',
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1537,11 +1537,12 @@ shell_global_run_at_leisure (ShellGlobal *global,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
build_ca_proplist_for_event (ca_proplist *props,
|
build_ca_proplist_for_event (ca_proplist *props,
|
||||||
|
const char *event_property,
|
||||||
const char *event_id,
|
const char *event_id,
|
||||||
const char *event_description,
|
const char *event_description,
|
||||||
ClutterEvent *for_event)
|
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_EVENT_DESCRIPTION, event_description);
|
||||||
ca_proplist_sets (props, CA_PROP_CANBERRA_CACHE_CONTROL, "volatile");
|
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 *props;
|
||||||
|
|
||||||
ca_proplist_create (&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);
|
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 *props;
|
||||||
|
|
||||||
ca_proplist_create (&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_ID, application_id);
|
||||||
ca_proplist_sets (props, CA_PROP_APPLICATION_NAME, application_name);
|
ca_proplist_sets (props, CA_PROP_APPLICATION_NAME, application_name);
|
||||||
|
|
||||||
@ -1630,6 +1631,68 @@ shell_global_play_theme_sound_full (ShellGlobal *global,
|
|||||||
ca_proplist_destroy (props);
|
ca_proplist_destroy (props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
* shell_global_cancel_theme_sound:
|
||||||
* @global: the #ShellGlobal
|
* @global: the #ShellGlobal
|
||||||
|
@ -124,6 +124,19 @@ void shell_global_play_theme_sound_full (ShellGlobal *global,
|
|||||||
ClutterEvent *for_event,
|
ClutterEvent *for_event,
|
||||||
const char *application_id,
|
const char *application_id,
|
||||||
const char *application_name);
|
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,
|
void shell_global_cancel_theme_sound (ShellGlobal *global,
|
||||||
guint id);
|
guint id);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user