MessageTray: introduce configurable per-source notification policy
Allow message tray sources to provide a NotificationPolicy object, that will configure how and if the source is displayed. For notification daemon sources, this object is hooked to GSettings. https://bugzilla.gnome.org/show_bug.cgi?id=685926
This commit is contained in:
parent
4dc5bac72f
commit
098bd4509b
@ -293,7 +293,6 @@ const AutorunResidentSource = new Lang.Class({
|
||||
|
||||
_init: function(manager) {
|
||||
this.parent(_("Removable Devices"), 'media-removable');
|
||||
this.showInLockScreen = false;
|
||||
|
||||
this._mounts = [];
|
||||
|
||||
@ -301,6 +300,10 @@ const AutorunResidentSource = new Lang.Class({
|
||||
this._notification = new AutorunResidentNotification(this._manager, this);
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
return new MessageTray.NotificationPolicy({ showInLockScreen: false });
|
||||
},
|
||||
|
||||
buildRightClickMenu: function() {
|
||||
return null;
|
||||
},
|
||||
|
@ -248,6 +248,32 @@ function strHasSuffix(string, suffix) {
|
||||
return string.substr(-suffix.length) == suffix;
|
||||
}
|
||||
|
||||
// NotificationPolicy:
|
||||
// An object that holds all bits of configurable policy related to a notification
|
||||
// source, such as whether to play sound or honour the critical bit.
|
||||
//
|
||||
// A notification without a policy object will inherit the default one.
|
||||
const NotificationPolicy = new Lang.Class({
|
||||
Name: 'NotificationPolicy',
|
||||
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { enable: true,
|
||||
enableSound: true,
|
||||
showBanners: true,
|
||||
forceExpanded: false,
|
||||
showInLockScreen: true,
|
||||
detailsInLockScreen: false
|
||||
});
|
||||
Lang.copyProperties(params, this);
|
||||
},
|
||||
|
||||
// Do nothing for the default policy. These methods are only useful for the
|
||||
// GSettings policy.
|
||||
store: function() { },
|
||||
destroy: function() { }
|
||||
});
|
||||
Signals.addSignalMethods(NotificationPolicy.prototype);
|
||||
|
||||
// Notification:
|
||||
// @source: the notification's Source
|
||||
// @title: the title
|
||||
@ -1089,10 +1115,11 @@ const Source = new Lang.Class({
|
||||
this.isTransient = false;
|
||||
this.isChat = false;
|
||||
this.isMuted = false;
|
||||
this.showInLockScreen = true;
|
||||
this.keepTrayOnSummaryClick = false;
|
||||
|
||||
this.notifications = [];
|
||||
|
||||
this.policy = this._createPolicy();
|
||||
},
|
||||
|
||||
get count() {
|
||||
@ -1111,6 +1138,10 @@ const Source = new Lang.Class({
|
||||
this.emit('count-updated');
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
return new NotificationPolicy();
|
||||
},
|
||||
|
||||
buildRightClickMenu: function() {
|
||||
let item;
|
||||
let rightClickMenu = new St.BoxLayout({ name: 'summary-right-click-menu',
|
||||
@ -1200,11 +1231,13 @@ const Source = new Lang.Class({
|
||||
notify: function(notification) {
|
||||
notification.acknowledged = false;
|
||||
this.pushNotification(notification);
|
||||
if (!this.isMuted)
|
||||
|
||||
if (!this.isMuted && this.policy.showBanners)
|
||||
this.emit('notify', notification);
|
||||
},
|
||||
|
||||
destroy: function(reason) {
|
||||
this.policy.destroy();
|
||||
this.emit('destroy', reason);
|
||||
},
|
||||
|
||||
@ -1300,6 +1333,14 @@ const SummaryItem = new Lang.Class({
|
||||
global.focus_manager.add_group(this.rightClickMenu);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
// remove the actor from the summary item so it doesn't get destroyed
|
||||
// with us
|
||||
this._sourceBox.remove_actor(this._sourceIcon);
|
||||
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
_onKeyPress: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.KEY_Up) {
|
||||
actor.emit('clicked', 1);
|
||||
@ -1682,7 +1723,12 @@ const MessageTray = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
this._addSource(source);
|
||||
// Register that we got a notification for this source
|
||||
source.policy.store();
|
||||
|
||||
source.policy.connect('enable-changed', Lang.bind(this, this._onSourceEnableChanged, source));
|
||||
source.policy.connect('policy-changed', Lang.bind(this, this._updateState));
|
||||
this._onSourceEnableChanged(source.policy, source);
|
||||
},
|
||||
|
||||
_addSource: function(source) {
|
||||
@ -1773,6 +1819,18 @@ const MessageTray = new Lang.Class({
|
||||
});
|
||||
},
|
||||
|
||||
_onSourceEnableChanged: function(policy, source) {
|
||||
let wasEnabled = this.contains(source);
|
||||
let shouldBeEnabled = policy.enable;
|
||||
|
||||
if (wasEnabled != shouldBeEnabled) {
|
||||
if (shouldBeEnabled)
|
||||
this._addSource(source);
|
||||
else
|
||||
this._removeSource(source);
|
||||
}
|
||||
},
|
||||
|
||||
_onSourceDestroy: function(source) {
|
||||
this._removeSource(source);
|
||||
},
|
||||
@ -2303,8 +2361,10 @@ const MessageTray = new Lang.Class({
|
||||
_updateShowingNotification: function() {
|
||||
this._notification.acknowledged = true;
|
||||
|
||||
// We auto-expand notifications with CRITICAL urgency.
|
||||
if (this._notification.urgency == Urgency.CRITICAL)
|
||||
// We auto-expand notifications with CRITICAL urgency, or for which the relevant setting
|
||||
// is on in the control center.
|
||||
if (this._notification.urgency == Urgency.CRITICAL ||
|
||||
this._notification.source.policy.forceExpanded)
|
||||
this._expandNotification(true);
|
||||
|
||||
// We tween all notifications to full opacity. This ensures that both new notifications and
|
||||
|
@ -103,6 +103,126 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
|
||||
'ibus-ui-gtk': 'keyboard'
|
||||
};
|
||||
|
||||
const NotificationGenericPolicy = new Lang.Class({
|
||||
Name: 'NotificationGenericPolicy',
|
||||
Extends: MessageTray.NotificationPolicy,
|
||||
|
||||
_init: function() {
|
||||
// Don't chain to parent, it would try setting
|
||||
// our properties to the defaults
|
||||
|
||||
this.id = 'generic';
|
||||
|
||||
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
|
||||
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
|
||||
},
|
||||
|
||||
store: function() { },
|
||||
|
||||
destroy: function() {
|
||||
this._masterSettings.run_dispose();
|
||||
},
|
||||
|
||||
_changed: function(settings, key) {
|
||||
this.emit('policy-changed', key);
|
||||
},
|
||||
|
||||
get enable() {
|
||||
return true;
|
||||
},
|
||||
|
||||
get enableSound() {
|
||||
return true;
|
||||
},
|
||||
|
||||
get showBanners() {
|
||||
return this._masterSettings.get_boolean('show-banners');
|
||||
},
|
||||
|
||||
get forceExpanded() {
|
||||
return false;
|
||||
},
|
||||
|
||||
get showInLockScreen() {
|
||||
return this._masterSettings.get_boolean('show-in-lock-screen');
|
||||
},
|
||||
|
||||
get detailsInLockScreen() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
const NotificationApplicationPolicy = new Lang.Class({
|
||||
Name: 'NotificationApplicationPolicy',
|
||||
Extends: MessageTray.NotificationPolicy,
|
||||
|
||||
_init: function(id) {
|
||||
// Don't chain to parent, it would try setting
|
||||
// our properties to the defaults
|
||||
|
||||
this.id = id;
|
||||
this._canonicalId = this._canonicalizeId(id)
|
||||
|
||||
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
|
||||
this._settings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications.application',
|
||||
path: '/org/gnome/desktop/notifications/application/' + this._canonicalId + '/' });
|
||||
|
||||
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
|
||||
this._settings.connect('changed', Lang.bind(this, this._changed));
|
||||
},
|
||||
|
||||
store: function() {
|
||||
this._settings.set_string('application-id', this.id + '.desktop');
|
||||
|
||||
let apps = this._masterSettings.get_strv('application-children');
|
||||
if (apps.indexOf(this._canonicalId) < 0) {
|
||||
apps.push(this._canonicalId);
|
||||
this._masterSettings.set_strv('application-children', apps);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this._masterSettings.run_dispose();
|
||||
this._settings.run_dispose();
|
||||
},
|
||||
|
||||
_changed: function(settings, key) {
|
||||
this.emit('policy-changed', key);
|
||||
},
|
||||
|
||||
_canonicalizeId: function(id) {
|
||||
// Keys are restricted to lowercase alphanumeric characters and dash,
|
||||
// and two dashes cannot be in succession
|
||||
return id.toLowerCase().replace(/[^a-z0-9\-]/g, '-').replace(/--+/g, '-');
|
||||
},
|
||||
|
||||
get enable() {
|
||||
return this._settings.get_boolean('enable');
|
||||
},
|
||||
|
||||
get enableSound() {
|
||||
return this._settings.get_boolean('enable-sound-alerts');
|
||||
},
|
||||
|
||||
get showBanners() {
|
||||
return this._masterSettings.get_boolean('show-banners') &&
|
||||
this._settings.get_boolean('show-banners');
|
||||
},
|
||||
|
||||
get forceExpanded() {
|
||||
return this._settings.get_boolean('force-expanded');
|
||||
},
|
||||
|
||||
get showInLockScreen() {
|
||||
return this._masterSettings.get_boolean('show-in-lock-screen') &&
|
||||
this._settings.get_boolean('show-in-lock-screen');
|
||||
},
|
||||
|
||||
get detailsInLockScreen() {
|
||||
return this._settings.get_boolean('details-in-lock-screen');
|
||||
}
|
||||
});
|
||||
|
||||
const NotificationDaemon = new Lang.Class({
|
||||
Name: 'NotificationDaemon',
|
||||
|
||||
@ -546,6 +666,15 @@ const Source = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
if (this.app) {
|
||||
let id = this.app.get_id().replace(/\.desktop$/,'');
|
||||
return new NotificationApplicationPolicy(id);
|
||||
} else {
|
||||
return new NotificationGenericPolicy();
|
||||
}
|
||||
},
|
||||
|
||||
_onNameVanished: function() {
|
||||
// Destroy the notification source when its sender is removed from DBus.
|
||||
// Only do so if this.app is set to avoid removing "notify-send" sources, senders
|
||||
|
@ -851,12 +851,10 @@ const ScreenShield = new Lang.Class({
|
||||
|
||||
this._lockScreenContents.add_actor(this._lockScreenContentsBox);
|
||||
|
||||
if (this._settings.get_boolean('show-notifications')) {
|
||||
this._notificationsBox = new NotificationsBox();
|
||||
this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true });
|
||||
}
|
||||
|
||||
this._hasLockScreen = true;
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user