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) {
|
_init: function(manager) {
|
||||||
this.parent(_("Removable Devices"), 'media-removable');
|
this.parent(_("Removable Devices"), 'media-removable');
|
||||||
this.showInLockScreen = false;
|
|
||||||
|
|
||||||
this._mounts = [];
|
this._mounts = [];
|
||||||
|
|
||||||
@ -301,6 +300,10 @@ const AutorunResidentSource = new Lang.Class({
|
|||||||
this._notification = new AutorunResidentNotification(this._manager, this);
|
this._notification = new AutorunResidentNotification(this._manager, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_createPolicy: function() {
|
||||||
|
return new MessageTray.NotificationPolicy({ showInLockScreen: false });
|
||||||
|
},
|
||||||
|
|
||||||
buildRightClickMenu: function() {
|
buildRightClickMenu: function() {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -248,6 +248,32 @@ function strHasSuffix(string, suffix) {
|
|||||||
return string.substr(-suffix.length) == 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:
|
// Notification:
|
||||||
// @source: the notification's Source
|
// @source: the notification's Source
|
||||||
// @title: the title
|
// @title: the title
|
||||||
@ -1089,10 +1115,11 @@ const Source = new Lang.Class({
|
|||||||
this.isTransient = false;
|
this.isTransient = false;
|
||||||
this.isChat = false;
|
this.isChat = false;
|
||||||
this.isMuted = false;
|
this.isMuted = false;
|
||||||
this.showInLockScreen = true;
|
|
||||||
this.keepTrayOnSummaryClick = false;
|
this.keepTrayOnSummaryClick = false;
|
||||||
|
|
||||||
this.notifications = [];
|
this.notifications = [];
|
||||||
|
|
||||||
|
this.policy = this._createPolicy();
|
||||||
},
|
},
|
||||||
|
|
||||||
get count() {
|
get count() {
|
||||||
@ -1111,6 +1138,10 @@ const Source = new Lang.Class({
|
|||||||
this.emit('count-updated');
|
this.emit('count-updated');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_createPolicy: function() {
|
||||||
|
return new NotificationPolicy();
|
||||||
|
},
|
||||||
|
|
||||||
buildRightClickMenu: function() {
|
buildRightClickMenu: function() {
|
||||||
let item;
|
let item;
|
||||||
let rightClickMenu = new St.BoxLayout({ name: 'summary-right-click-menu',
|
let rightClickMenu = new St.BoxLayout({ name: 'summary-right-click-menu',
|
||||||
@ -1200,11 +1231,13 @@ const Source = new Lang.Class({
|
|||||||
notify: function(notification) {
|
notify: function(notification) {
|
||||||
notification.acknowledged = false;
|
notification.acknowledged = false;
|
||||||
this.pushNotification(notification);
|
this.pushNotification(notification);
|
||||||
if (!this.isMuted)
|
|
||||||
this.emit('notify', notification);
|
if (!this.isMuted && this.policy.showBanners)
|
||||||
|
this.emit('notify', notification);
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function(reason) {
|
destroy: function(reason) {
|
||||||
|
this.policy.destroy();
|
||||||
this.emit('destroy', reason);
|
this.emit('destroy', reason);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1300,6 +1333,14 @@ const SummaryItem = new Lang.Class({
|
|||||||
global.focus_manager.add_group(this.rightClickMenu);
|
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) {
|
_onKeyPress: function(actor, event) {
|
||||||
if (event.get_key_symbol() == Clutter.KEY_Up) {
|
if (event.get_key_symbol() == Clutter.KEY_Up) {
|
||||||
actor.emit('clicked', 1);
|
actor.emit('clicked', 1);
|
||||||
@ -1682,7 +1723,12 @@ const MessageTray = new Lang.Class({
|
|||||||
return;
|
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) {
|
_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) {
|
_onSourceDestroy: function(source) {
|
||||||
this._removeSource(source);
|
this._removeSource(source);
|
||||||
},
|
},
|
||||||
@ -2303,8 +2361,10 @@ const MessageTray = new Lang.Class({
|
|||||||
_updateShowingNotification: function() {
|
_updateShowingNotification: function() {
|
||||||
this._notification.acknowledged = true;
|
this._notification.acknowledged = true;
|
||||||
|
|
||||||
// We auto-expand notifications with CRITICAL urgency.
|
// We auto-expand notifications with CRITICAL urgency, or for which the relevant setting
|
||||||
if (this._notification.urgency == Urgency.CRITICAL)
|
// is on in the control center.
|
||||||
|
if (this._notification.urgency == Urgency.CRITICAL ||
|
||||||
|
this._notification.source.policy.forceExpanded)
|
||||||
this._expandNotification(true);
|
this._expandNotification(true);
|
||||||
|
|
||||||
// We tween all notifications to full opacity. This ensures that both new notifications and
|
// 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'
|
'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({
|
const NotificationDaemon = new Lang.Class({
|
||||||
Name: 'NotificationDaemon',
|
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() {
|
_onNameVanished: function() {
|
||||||
// Destroy the notification source when its sender is removed from DBus.
|
// 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
|
// 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);
|
this._lockScreenContents.add_actor(this._lockScreenContentsBox);
|
||||||
|
|
||||||
if (this._settings.get_boolean('show-notifications')) {
|
this._notificationsBox = new NotificationsBox();
|
||||||
this._notificationsBox = new NotificationsBox();
|
this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
|
||||||
this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
|
y_fill: true,
|
||||||
y_fill: true,
|
expand: true });
|
||||||
expand: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
this._hasLockScreen = true;
|
this._hasLockScreen = true;
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user