[MessageTray] Clean up source-vs-notification icon handling
A Source needs exactly one summary icon (which in the case of a trayicon-based source won't even be just an image), but possibly many notification icons, which may vary for successive notifications (particularly in the case of NotificationDaemon notifications). So differentiate these cases in the API. https://bugzilla.gnome.org/show_bug.cgi?id=627303
This commit is contained in:
parent
1951812a47
commit
6f57f07214
@ -19,7 +19,6 @@ const SUMMARY_TIMEOUT = 1;
|
||||
|
||||
const HIDE_TIMEOUT = 0.2;
|
||||
|
||||
const ICON_SIZE = 24;
|
||||
const BUTTON_ICON_SIZE = 36;
|
||||
|
||||
const MAX_SOURCE_TITLE_WIDTH = 180;
|
||||
@ -46,10 +45,14 @@ function _cleanMarkup(text) {
|
||||
// @banner: the banner text
|
||||
// @params: optional additional params
|
||||
//
|
||||
// Creates a notification. In banner mode, it will show
|
||||
// @source's icon, @title (in bold) and @banner, all on a single line
|
||||
// Creates a notification. In banner mode, it will show an
|
||||
// icon, @title (in bold) and @banner, all on a single line
|
||||
// (with @banner ellipsized if necessary).
|
||||
//
|
||||
// By default, the icon shown is created by calling
|
||||
// source.createNotificationIcon(). However, you can override this
|
||||
// by passing an 'icon' parameter in @params.
|
||||
//
|
||||
// Additional notification details can be added, in which case the
|
||||
// notification can be expanded by moving the pointer into it. In
|
||||
// expanded mode, the banner text disappears, and there can be one or
|
||||
@ -150,6 +153,7 @@ Notification.prototype = {
|
||||
update: function(title, banner, params) {
|
||||
params = Params.parse(params, { bannerBody: this._bannerBody,
|
||||
body: null,
|
||||
icon: null,
|
||||
clear: false });
|
||||
|
||||
if (this._icon)
|
||||
@ -167,7 +171,7 @@ Notification.prototype = {
|
||||
|
||||
this._bannerBody = params.bannerBody;
|
||||
|
||||
this._icon = this.source.createIcon(ICON_SIZE);
|
||||
this._icon = params.icon || this.source.createNotificationIcon();
|
||||
this.actor.add(this._icon, { row: 0,
|
||||
col: 0,
|
||||
x_expand: false,
|
||||
@ -560,21 +564,30 @@ Notification.prototype = {
|
||||
};
|
||||
Signals.addSignalMethods(Notification.prototype);
|
||||
|
||||
function Source(title, createIcon) {
|
||||
this._init(title, createIcon);
|
||||
function Source(title) {
|
||||
this._init(title);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
_init: function(title, createIcon) {
|
||||
ICON_SIZE: 24,
|
||||
|
||||
_init: function(title) {
|
||||
this.title = title;
|
||||
if (createIcon)
|
||||
this.createIcon = createIcon;
|
||||
this._iconBin = new St.Bin({ width: this.ICON_SIZE,
|
||||
height: this.ICON_SIZE });
|
||||
},
|
||||
|
||||
// This can be overridden by a subclass, or by the createIcon
|
||||
// parameter to _init()
|
||||
createIcon: function(size) {
|
||||
throw new Error('no implementation of createIcon in ' + this);
|
||||
// Called to create a new icon actor (of size this.ICON_SIZE).
|
||||
// Must be overridden by the subclass if you do not pass icons
|
||||
// explicitly to the Notification() constructor.
|
||||
createNotificationIcon: function() {
|
||||
throw new Error('no implementation of createNotificationIcon in ' + this);
|
||||
},
|
||||
|
||||
// Unlike createNotificationIcon, this always returns the same actor;
|
||||
// there is only one summary icon actor for a Source.
|
||||
getSummaryIcon: function() {
|
||||
return this._iconBin;
|
||||
},
|
||||
|
||||
notify: function(notification) {
|
||||
@ -600,6 +613,15 @@ Source.prototype = {
|
||||
|
||||
destroy: function() {
|
||||
this.emit('destroy');
|
||||
},
|
||||
|
||||
//// Protected methods ////
|
||||
|
||||
// The subclass must call this at least once to set the summary icon.
|
||||
_setSummaryIcon: function(icon) {
|
||||
if (this._iconBin.child)
|
||||
this._iconBin.child.destroy();
|
||||
this._iconBin.child = icon;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Source.prototype);
|
||||
@ -626,7 +648,7 @@ SummaryItem.prototype = {
|
||||
this._sourceBox.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this._sourceBox.connect('allocate', Lang.bind(this, this._allocate));
|
||||
|
||||
this._sourceIcon = source.createIcon(ICON_SIZE);
|
||||
this._sourceIcon = source.getSummaryIcon();
|
||||
this._sourceTitleBin = new St.Bin({ y_align: St.Align.MIDDLE, x_fill: true });
|
||||
this._sourceTitle = new St.Label({ style_class: 'source-title',
|
||||
text: source.title });
|
||||
|
@ -141,6 +141,37 @@ NotificationDaemon.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_iconForNotificationData: function(icon, hints, size) {
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
|
||||
if (icon) {
|
||||
if (icon.substr(0, 7) == 'file://')
|
||||
return textureCache.load_uri_async(icon, size, size);
|
||||
else if (icon[0] == '/') {
|
||||
let uri = GLib.filename_to_uri(icon, null);
|
||||
return textureCache.load_uri_async(uri, size, size);
|
||||
} else
|
||||
return textureCache.load_icon_name(icon, size);
|
||||
} else if (hints.icon_data) {
|
||||
let [width, height, rowStride, hasAlpha,
|
||||
bitsPerSample, nChannels, data] = hints.icon_data;
|
||||
return textureCache.load_from_raw(data, data.length, hasAlpha,
|
||||
width, height, rowStride, size);
|
||||
} else {
|
||||
let stockIcon;
|
||||
switch (hints.urgency) {
|
||||
case Urgency.LOW:
|
||||
case Urgency.NORMAL:
|
||||
stockIcon = 'gtk-dialog-info';
|
||||
break;
|
||||
case Urgency.CRITICAL:
|
||||
stockIcon = 'gtk-dialog-error';
|
||||
break;
|
||||
}
|
||||
return textureCache.load_icon_name(stockIcon, size);
|
||||
}
|
||||
},
|
||||
|
||||
Notify: function(appName, replacesId, icon, summary, body,
|
||||
actions, hints, timeout) {
|
||||
let source = this._sources[appName];
|
||||
@ -164,7 +195,7 @@ NotificationDaemon.prototype = {
|
||||
// been acknowledged.
|
||||
if (source == null) {
|
||||
let title = appNameMap[appName] || appName;
|
||||
source = new Source(title, icon, hints);
|
||||
source = new Source(title);
|
||||
Main.messageTray.add(source);
|
||||
this._sources[appName] = source;
|
||||
|
||||
@ -184,8 +215,6 @@ NotificationDaemon.prototype = {
|
||||
if (app)
|
||||
source.setApp(app);
|
||||
});
|
||||
} else {
|
||||
source.update(icon, hints);
|
||||
}
|
||||
|
||||
summary = GLib.markup_escape_text(summary, -1);
|
||||
@ -205,10 +234,12 @@ NotificationDaemon.prototype = {
|
||||
notification = this._currentNotifications[id];
|
||||
}
|
||||
|
||||
let iconActor = this._iconForNotificationData(icon, hints, source.ICON_SIZE);
|
||||
if (notification == null) {
|
||||
id = nextNotificationId++;
|
||||
notification = new MessageTray.Notification(source, summary, body,
|
||||
{ bannerBody: true });
|
||||
{ bannerBody: true,
|
||||
icon: iconActor });
|
||||
this._currentNotifications[id] = notification;
|
||||
notification.connect('dismissed', Lang.bind(this,
|
||||
function(n) {
|
||||
@ -220,7 +251,8 @@ NotificationDaemon.prototype = {
|
||||
}));
|
||||
notification.connect('action-invoked', Lang.bind(this, this._actionInvoked, source, id));
|
||||
} else {
|
||||
notification.update(summary, body, { clear: true });
|
||||
notification.update(summary, body, { icon: iconActor,
|
||||
clear: true });
|
||||
}
|
||||
|
||||
if (actions.length) {
|
||||
@ -230,7 +262,8 @@ NotificationDaemon.prototype = {
|
||||
|
||||
notification.setUrgent(hints.urgency == Urgency.CRITICAL);
|
||||
|
||||
source.notify(notification);
|
||||
let sourceIconActor = this._iconForNotificationData(icon, hints, source.ICON_SIZE);
|
||||
source.notify(sourceIconActor, notification);
|
||||
return id;
|
||||
},
|
||||
|
||||
@ -300,57 +333,23 @@ NotificationDaemon.prototype = {
|
||||
|
||||
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
|
||||
|
||||
function Source(title, icon, hints) {
|
||||
this._init(title, icon, hints);
|
||||
function Source(title) {
|
||||
this._init(title);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(title, icon, hints) {
|
||||
_init: function(title) {
|
||||
MessageTray.Source.prototype._init.call(this, title);
|
||||
|
||||
this.app = null;
|
||||
this._openAppRequested = false;
|
||||
|
||||
this.update(icon, hints);
|
||||
},
|
||||
|
||||
update: function(icon, hints) {
|
||||
this._icon = icon;
|
||||
this._iconData = hints.icon_data;
|
||||
this._urgency = hints.urgency;
|
||||
},
|
||||
|
||||
createIcon: function(size) {
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
|
||||
if (this._icon) {
|
||||
if (this._icon.substr(0, 7) == 'file://')
|
||||
return textureCache.load_uri_async(this._icon, size, size);
|
||||
else if (this._icon[0] == '/') {
|
||||
let uri = GLib.filename_to_uri(this._icon, null);
|
||||
return textureCache.load_uri_async(uri, size, size);
|
||||
} else
|
||||
return textureCache.load_icon_name(this._icon, size);
|
||||
} else if (this._iconData) {
|
||||
let [width, height, rowStride, hasAlpha,
|
||||
bitsPerSample, nChannels, data] = this._iconData;
|
||||
return textureCache.load_from_raw(data, data.length, hasAlpha,
|
||||
width, height, rowStride, size);
|
||||
} else {
|
||||
let stockIcon;
|
||||
switch (this._urgency) {
|
||||
case Urgency.LOW:
|
||||
case Urgency.NORMAL:
|
||||
stockIcon = 'gtk-dialog-info';
|
||||
break;
|
||||
case Urgency.CRITICAL:
|
||||
stockIcon = 'gtk-dialog-error';
|
||||
break;
|
||||
}
|
||||
return textureCache.load_icon_name(stockIcon, size);
|
||||
}
|
||||
notify: function(icon, notification) {
|
||||
this._setSummaryIcon(icon);
|
||||
MessageTray.Source.prototype.notify.call(this, notification);
|
||||
},
|
||||
|
||||
clicked: function() {
|
||||
|
@ -475,10 +475,13 @@ Source.prototype = {
|
||||
this._receivedId = this._channelText.connect('Received', Lang.bind(this, this._messageReceived));
|
||||
|
||||
this._channelText.ListPendingMessagesRemote(false, Lang.bind(this, this._gotPendingMessages));
|
||||
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
},
|
||||
|
||||
createIcon: function(size) {
|
||||
return contactManager.createAvatar(this._conn, this._targetHandle, size);
|
||||
createNotificationIcon: function() {
|
||||
return contactManager.createAvatar(this._conn, this._targetHandle,
|
||||
this.ICON_SIZE);
|
||||
},
|
||||
|
||||
clicked: function() {
|
||||
|
@ -94,10 +94,11 @@ Source.prototype = {
|
||||
MessageTray.Source.prototype._init.call(this, app.get_name());
|
||||
this._window = window;
|
||||
this._app = app;
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
},
|
||||
|
||||
createIcon : function(size) {
|
||||
return this._app.create_icon_texture(size);
|
||||
createNotificationIcon : function() {
|
||||
return this._app.create_icon_texture(this.ICON_SIZE);
|
||||
},
|
||||
|
||||
clicked : function() {
|
||||
|
Loading…
Reference in New Issue
Block a user