[gnome-shell] MessageTray: introduce configurable per-source notification policy
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] MessageTray: introduce configurable per-source notification policy
- Date: Thu, 31 Jan 2013 12:22:45 +0000 (UTC)
commit 098bd4509ba0de91ada3cfdce29439c9754a2d44
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Tue Oct 16 17:08:54 2012 +0200
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
js/ui/components/autorunManager.js | 5 +-
js/ui/messageTray.js | 72 ++++++++++++++++++--
js/ui/notificationDaemon.js | 129 ++++++++++++++++++++++++++++++++++++
js/ui/screenShield.js | 10 +--
4 files changed, 203 insertions(+), 13 deletions(-)
---
diff --git a/js/ui/components/autorunManager.js b/js/ui/components/autorunManager.js
index 7709a3d..6119c3a 100644
--- a/js/ui/components/autorunManager.js
+++ b/js/ui/components/autorunManager.js
@@ -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;
},
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index eec5a3b..103248c 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -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)
- this.emit('notify', notification);
+
+ 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
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index e353d8d..cbe2831 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -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
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
index 699fb96..38da9df 100644
--- a/js/ui/screenShield.js
+++ b/js/ui/screenShield.js
@@ -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._notificationsBox = new NotificationsBox();
+ this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
+ y_fill: true,
+ expand: true });
this._hasLockScreen = true;
},
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]