[gnome-shell] ScreenShield: decouple detailed notifications from resident notifications
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] ScreenShield: decouple detailed notifications from resident notifications
- Date: Thu, 31 Jan 2013 12:22:50 +0000 (UTC)
commit 8cb3884fae67a20a2b87f442479cfdb5feb8a9c8
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Wed Jan 30 19:47:55 2013 +0100
ScreenShield: decouple detailed notifications from resident notifications
The designs says that only music notifications should be shown in full
in the screenshield, the others should be either shown as a summary or
with very light details.
https://bugzilla.gnome.org/show_bug.cgi?id=685926
data/theme/gnome-shell.css | 1 +
js/ui/messageTray.js | 42 ++++---
js/ui/notificationDaemon.js | 3 +
js/ui/screenShield.js | 266 ++++++++++++++++++++++++++-----------------
4 files changed, 188 insertions(+), 124 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 41a9557..e1c5fb7 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -2417,6 +2417,7 @@ StScrollBar StButton#vhandle:active {
.screen-shield-notifications-box {
spacing: 18px;
+ max-width: 34em;
}
.screen-shield-notification-source {
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index 103248c..6cc5729 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -345,6 +345,7 @@ const Notification = new Lang.Class({
this.resident = false;
// 'transient' is a reserved keyword in JS, so we have to use an alternate variable name
this.isTransient = false;
+ this.isMusic = false;
this.forFeedback = false;
this.expanded = false;
this.focused = false;
@@ -352,8 +353,8 @@ const Notification = new Lang.Class({
this._destroyed = false;
this._useActionIcons = false;
this._customContent = false;
- this._bannerBodyText = null;
- this._bannerBodyMarkup = false;
+ this.bannerBodyText = null;
+ this.bannerBodyMarkup = false;
this._titleFitsInBannerMode = true;
this._titleDirection = Clutter.TextDirection.DEFAULT;
this._spacing = 0;
@@ -505,12 +506,12 @@ const Notification = new Lang.Class({
// is done correctly automatically.
this._table.set_text_direction(this._titleDirection);
- // Unless the notification has custom content, we save this._bannerBodyText
+ // Unless the notification has custom content, we save this.bannerBodyText
// to add it to the content of the notification if the notification is
// expandable due to other elements in its content area or due to the banner
// not fitting fully in the single-line mode.
- this._bannerBodyText = this._customContent ? null : banner;
- this._bannerBodyMarkup = params.bannerMarkup;
+ this.bannerBodyText = this._customContent ? null : banner;
+ this.bannerBodyMarkup = params.bannerMarkup;
banner = banner ? banner.replace(/\n/g, ' ') : '';
@@ -518,7 +519,7 @@ const Notification = new Lang.Class({
this._bannerLabel.queue_relayout();
// Add the bannerBody now if we know for sure we'll need it
- if (this._bannerBodyText && this._bannerBodyText.indexOf('\n') > -1)
+ if (this.bannerBodyText && this.bannerBodyText.indexOf('\n') > -1)
this._addBannerBody();
if (params.body)
@@ -584,10 +585,10 @@ const Notification = new Lang.Class({
},
_addBannerBody: function() {
- if (this._bannerBodyText) {
- let text = this._bannerBodyText;
- this._bannerBodyText = null;
- this.addBody(text, this._bannerBodyMarkup);
+ if (this.bannerBodyText) {
+ let text = this.bannerBodyText;
+ this.bannerBodyText = null;
+ this.addBody(text, this.bannerBodyMarkup);
}
},
@@ -879,7 +880,7 @@ const Notification = new Lang.Class({
},
_canExpandContent: function() {
- return this._bannerBodyText ||
+ return this.bannerBodyText ||
(!this._titleFitsInBannerMode && !this._table.has_style_class_name('multi-line-notification'));
},
@@ -1279,7 +1280,16 @@ const Source = new Lang.Class({
hasResidentNotification: function() {
return this.notifications.some(function(n) { return n.resident; });
- }
+ },
+
+ getMusicNotification: function() {
+ for (let i = 0; i < this.notifications.length; i++) {
+ if (this.notifications[i].isMusic)
+ return this.notifications[i];
+ }
+
+ return null;
+ },
});
Signals.addSignalMethods(Source.prototype);
@@ -1777,7 +1787,7 @@ const MessageTray = new Lang.Class({
// So postpone calling _updateState() a tiny bit.
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { this._updateState(); return false; }));
- this.emit('summary-item-added', summaryItem);
+ this.emit('source-added', source);
this._updateNoMessagesLabel();
},
@@ -1813,10 +1823,8 @@ const MessageTray = new Lang.Class({
this._updateState();
},
- getSummaryItems: function() {
- return this._sources.values().map(function(v) {
- return v.summaryItem;
- });
+ getSources: function() {
+ return this._sources.keys();
},
_onSourceEnableChanged: function(policy, source) {
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index cbe2831..e02bf22 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -501,6 +501,9 @@ const NotificationDaemon = new Lang.Class({
}));
}
+ // Mark music notifications so they can be shown in the screen shield
+ notification.isMusic = (ndata.hints['category'] == 'x-gnome.music');
+
let gicon = this._iconForNotificationData(icon, hints);
let gimage = this._imageForNotificationData(hints);
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
index 38da9df..0367f60 100644
--- a/js/ui/screenShield.js
+++ b/js/ui/screenShield.js
@@ -13,6 +13,7 @@ const St = imports.gi.St;
const TweenerEquations = imports.tweener.equations;
const GnomeSession = imports.misc.gnomeSession;
+const Hash = imports.misc.hash;
const Layout = imports.ui.layout;
const LoginManager = imports.misc.loginManager;
const Lightbox = imports.ui.lightbox;
@@ -127,49 +128,48 @@ const NotificationsBox = new Lang.Class({
name: 'screenShieldNotifications',
style_class: 'screen-shield-notifications-box' });
- this._residentNotificationBox = new St.BoxLayout({ vertical: true,
- style_class: 'screen-shield-notifications-box' });
+ this._musicBin = new St.Bin({ style_class: 'screen-shield-notifications-box',
+ visible: false });
+
let scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.START });
- this._persistentNotificationBox = new St.BoxLayout({ vertical: true,
- style_class: 'screen-shield-notifications-box' });
- scrollView.add_actor(this._persistentNotificationBox);
+ this._notificationBox = new St.BoxLayout({ vertical: true,
+ style_class: 'screen-shield-notifications-box' });
+ scrollView.add_actor(this._notificationBox);
- this.actor.add(this._residentNotificationBox, { x_fill: true });
+ this.actor.add(this._musicBin);
this.actor.add(scrollView, { x_fill: true, x_align: St.Align.START });
- this._items = [];
- Main.messageTray.getSummaryItems().forEach(Lang.bind(this, function(item) {
- this._summaryItemAdded(Main.messageTray, item, true);
+ this._sources = new Hash.Map();
+ Main.messageTray.getSources().forEach(Lang.bind(this, function(source) {
+ this._sourceAdded(Main.messageTray, source, true);
}));
this._updateVisibility();
- this._summaryAddedId = Main.messageTray.connect('summary-item-added', Lang.bind(this, this._summaryItemAdded));
+ this._sourceAddedId = Main.messageTray.connect('source-added', Lang.bind(this, this._sourceAdded));
},
destroy: function() {
- if (this._summaryAddedId) {
- Main.messageTray.disconnect(this._summaryAddedId);
- this._summaryAddedId = 0;
+ if (this._sourceAddedId) {
+ Main.messageTray.disconnect(this._sourceAddedId);
+ this._sourceAddedId = 0;
}
- for (let i = 0; i < this._items.length; i++)
- this._removeItem(this._items[i]);
- this._items = [];
+ let items = this._sources.items();
+ for (let i = 0; i < items.length; i++) {
+ let [source, obj] = items[i];
+ this._removeSource(source, obj);
+ }
this.actor.destroy();
},
_updateVisibility: function() {
- this._residentNotificationBox.visible = this._residentNotificationBox.get_n_children() > 0;
- this._persistentNotificationBox.visible = this._persistentNotificationBox.get_children().some(function(a) {
+ this._musicBin.visible = this._musicBin.child != null && this._musicBin.child.visible;
+ this._notificationBox.visible = this._notificationBox.get_children().some(function(a) {
return a.visible;
});
- this.actor.visible = this._residentNotificationBox.visible || this._persistentNotificationBox.visible;
- },
-
- _sourceIsResident: function(source) {
- return source.hasResidentNotification() && !source.isChat;
+ this.actor.visible = this._musicBin.visible || this._notificationBox.visible;
},
_makeNotificationCountText: function(count, isChat) {
@@ -179,18 +179,16 @@ const NotificationsBox = new Lang.Class({
return ngettext("%d new notification", "%d new notifications", count).format(count);
},
- _makeNotificationSource: function(source) {
- let box = new St.BoxLayout({ style_class: 'screen-shield-notification-source' });
-
+ _makeNotificationSource: function(source, box) {
let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
box.add(sourceActor.actor, { y_fill: true });
let textBox = new St.BoxLayout({ vertical: true });
box.add(textBox, { y_fill: false, y_align: St.Align.START });
- let label = new St.Label({ text: source.title,
+ let title = new St.Label({ text: source.title,
style_class: 'screen-shield-notification-label' });
- textBox.add(label);
+ textBox.add(title);
let count = source.unseenCount;
let countLabel = new St.Label({ text: this._makeNotificationCountText(count, source.isChat),
@@ -198,118 +196,172 @@ const NotificationsBox = new Lang.Class({
textBox.add(countLabel);
box.visible = count != 0;
- return [box, countLabel];
+ return [title, countLabel];
+ },
+
+ _makeNotificationDetailedSource: function(source, box) {
+ let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
+ box.add(sourceActor.actor, { y_fill: true });
+
+ let textBox = new St.BoxLayout({ vertical: true });
+ box.add(textBox, { y_fill: false, y_align: St.Align.START });
+
+ let title = new St.Label({ text: source.title,
+ style_class: 'screen-shield-notification-label' });
+ textBox.add(title);
+
+ let visible = false;
+ for (let i = 0; i < source.notifications.length; i++) {
+ let n = source.notifications[i];
+
+ if (n.acknowledged || n.isMusic)
+ continue;
+
+ let body = '';
+ if (n.bannerBodyText)
+ body = n.bannerBodyMarkup ? n.bannerBodyText :
+ GLib.markup_escape_text(n.bannerBodyMarkup, -1);
+ let label = new St.Label({ style_class: 'screen-shield-notification-count-text' });
+ label.clutter_text.set_markup('<b>' + n.title + '</b> ' + body);
+ textBox.add(label);
+
+ visible = true;
+ }
+
+ box.visible = visible;
+ return [title, null];
+ },
+
+ _showSource: function(source, obj, box) {
+ let musicNotification = source.getMusicNotification();
+
+ if (musicNotification != null &&
+ this._musicBin.child == null) {
+ if (musicNotification.actor.get_parent() != null)
+ musicNotification.actor.get_parent().remove_actor(musicNotification.actor);
+ this._musicBin.child = musicNotification.actor;
+ this._musicBin.child.visible = obj.visible;
+
+ musicNotification.expand(false /* animate */);
+
+ obj.musicNotification = musicNotification;
+ }
+
+ if (obj.detailed) {
+ [obj.titleLabel, obj.countLabel] = this._makeNotificationDetailedSource(source, box);
+ } else {
+ [obj.titleLabel, obj.countLabel] = this._makeNotificationSource(source, box);
+ }
+
+ box.visible = obj.visible &&
+ (source.unseenCount > (musicNotification ? 1 : 0));
},
- _summaryItemAdded: function(tray, item, dontUpdateVisibility) {
- // Ignore transient sources, or sources explicitly marked not to show
- // in the lock screen
- if (item.source.isTransient || !item.source.showInLockScreen)
+ _sourceAdded: function(tray, source, dontUpdateVisibility) {
+ // Ignore transient sources
+ if (source.isTransient)
return;
let obj = {
- item: item,
- source: item.source,
- resident: this._sourceIsResident(item.source),
- contentUpdatedId: 0,
+ visible: source.policy.showInLockScreen,
+ detailed: source.policy.detailsInLockScreen,
sourceDestroyId: 0,
+ sourceCountChangedId: 0,
+ sourceTitleChangedId: 0,
+ sourceUpdatedId: 0,
+ musicNotification: null,
sourceBox: null,
+ titleLabel: null,
countLabel: null,
};
- if (obj.resident) {
- this._residentNotificationBox.add(item.notificationStackWidget);
- item.closeButton.hide();
- item.prepareNotificationStackForShowing();
- } else {
- [obj.sourceBox, obj.countLabel] = this._makeNotificationSource(item.source);
- this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
- }
+ obj.sourceBox = new St.BoxLayout({ style_class: 'screen-shield-notification-source' });
+ this._showSource(source, obj, obj.sourceBox);
+ this._notificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
+
+ obj.sourceCountChangedId = source.connect('count-updated', Lang.bind(this, function(source) {
+ this._countChanged(source, obj);
+ }));
+ obj.sourceTitleChangedId = source.connect('title-changed', Lang.bind(this, function(source) {
+ this._titleChanged(source, obj);
+ }));
+ obj.policyChangedId = source.policy.connect('policy-changed', Lang.bind(this, function(policy, key) {
+ if (key == 'show-in-lock-screen')
+ this._visibleChanged(source, obj);
+ else
+ this._detailedChanged(source, obj);
+ }));
+ obj.sourceDestroyId = source.connect('destroy', Lang.bind(this, function(source) {
+ this._onSourceDestroy(source, obj);
+ }));
- obj.contentUpdatedId = item.connect('content-updated', Lang.bind(this, this._onItemContentUpdated));
- obj.sourceCountChangedId = item.source.connect('count-updated', Lang.bind(this, this._onSourceChanged));
- obj.sourceTitleChangedId = item.source.connect('title-changed', Lang.bind(this, this._onSourceChanged));
- obj.sourceDestroyId = item.source.connect('destroy', Lang.bind(this, this._onSourceDestroy));
- this._items.push(obj);
+ this._sources.set(source, obj);
if (!dontUpdateVisibility)
this._updateVisibility();
},
- _findSource: function(source) {
- for (let i = 0; i < this._items.length; i++) {
- if (this._items[i].source == source)
- return i;
- }
-
- return -1;
+ _titleChanged: function(source, obj) {
+ obj.titleLabel.text = source.title;
},
- _onItemContentUpdated: function(item) {
- let obj = this._items[this._findSource(item.source)];
- this._updateItem(obj);
- },
+ _countChanged: function(source, obj) {
+ if (obj.detailed) {
+ // A new notification was pushed, or a previous notification was destroyed.
+ // Give up, and build the list again.
- _onSourceChanged: function(source) {
- let obj = this._items[this._findSource(source)];
- this._updateItem(obj);
- },
+ obj.sourceBox.destroy_all_children();
+ obj.titleLabel = obj.countLabel = null;
+ this._showSource(source, obj, obj.sourceBox);
+ } else {
+ let count = source.unseenCount;
+ obj.countLabel.text = this._makeNotificationCountText(count, source.isChat);
+ }
- _updateItem: function(obj) {
- let itemShouldBeResident = this._sourceIsResident(obj.source);
+ obj.sourceBox.visible = obj.visible &&
+ (source.unseenCount > (obj.musicNotification ? 1 : 0));
+ this._updateVisibility();
+ },
- if (itemShouldBeResident && obj.resident) {
- // Nothing to do here, the actor is already updated
+ _visibleChanged: function(source, obj) {
+ if (obj.visible == source.policy.showInLockScreen)
return;
- }
- if (obj.resident && !itemShouldBeResident) {
- // make into a regular item
- obj.item.doneShowingNotificationStack();
- this._residentNotificationBox.remove_actor(obj.item.notificationStackWidget);
-
- [obj.sourceBox, obj.countLabel] = this._makeNotificationSource(obj.source);
- this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
- } else if (itemShouldBeResident && !obj.resident) {
- // make into a resident item
- obj.sourceBox.destroy();
- obj.sourceBox = obj.countLabel = null;
- obj.resident = true;
-
- this._residentNotificationBox.add(obj.item.notificationStackWidget);
- obj.item.closeButton.hide();
- obj.item.prepareNotificationStackForShowing();
- } else {
- // just update the counter
- let count = obj.source.unseenCount;
- obj.countLabel.text = this._makeNotificationCountText(count, obj.source.isChat);
- obj.sourceBox.visible = count != 0;
- }
+ obj.visible = source.policy.showInLockScreen;
+ if (obj.musicNotification)
+ obj.musicNotification.actor.visible = obj.visible;
+ obj.sourceBox.visible = obj.visible &&
+ source.unseenCount > (obj.musicNotification ? 1 : 0);
this._updateVisibility();
},
- _onSourceDestroy: function(source) {
- let idx = this._findSource(source);
+ _detailedChanged: function(source, obj) {
+ if (obj.detailed == source.policy.detailsInLockScreen)
+ return;
+
+ obj.detailed = source.policy.detailsInLockScreen;
- this._removeItem(this._items[idx]);
- this._items.splice(idx, 1);
+ obj.sourceBox.destroy_all_children();
+ obj.titleLabel = obj.countLabel = null;
+ this._showSource(source, obj, obj.sourceBox);
+ },
+ _onSourceDestroy: function(source, obj) {
+ this._removeSource(source, obj);
this._updateVisibility();
},
- _removeItem: function(obj) {
- if (obj.resident) {
- obj.item.doneShowingNotificationStack();
- this._residentNotificationBox.remove_actor(obj.item.notificationStackWidget);
- } else {
- obj.sourceBox.destroy();
- }
+ _removeSource: function(source, obj) {
+ obj.sourceBox.destroy();
+ obj.sourceBox = obj.titleLabel = obj.countLabel = null;
+
+ source.disconnect(obj.sourceDestroyId);
+ source.disconnect(obj.sourceCountChangedId);
+ source.disconnect(obj.sourceTitleChangedId);
+ source.policy.disconnect(obj.policyChangedId);
- obj.item.disconnect(obj.contentUpdatedId);
- obj.source.disconnect(obj.sourceDestroyId);
- obj.source.disconnect(obj.sourceCountChangedId);
- obj.source.disconnect(obj.sourceTitleChangedId);
+ this._sources.delete(source);
},
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]