f8dc3b88f8
We used 'bannerBody' flag to differentiate the case when we move the banner to the body when the notification is expanded from the one when we don't do that and only use the custom content set for the notification, as is the case for Telepathy notifications. We also always cleared the content of the notification on update when bannerBody was set to true. Flag named 'customContent' reflects the use case for it more clearly. The comments that accompany it were also updated and improved. We now always add the banner text as the first element in the expanded notification unless 'customContent' flag is set to true. If the 'body' parameter is specified, we use it in addition to the banner text. The earlier version of the code had a bug that resulted in the 'body' parameter not being set only in the case when the 'bannerBody' was set to true and the banner text had newlines in it. https://bugzilla.gnome.org/show_bug.cgi?id=623970
110 lines
3.9 KiB
JavaScript
110 lines
3.9 KiB
JavaScript
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
|
const Lang = imports.lang;
|
|
const Shell = imports.gi.Shell;
|
|
const Gettext = imports.gettext.domain('gnome-shell');
|
|
const _ = Gettext.gettext;
|
|
|
|
const Main = imports.ui.main;
|
|
const MessageTray = imports.ui.messageTray;
|
|
|
|
function WindowAttentionHandler() {
|
|
this._init();
|
|
}
|
|
|
|
WindowAttentionHandler.prototype = {
|
|
_init : function() {
|
|
this._startupIds = {};
|
|
this._sources = {};
|
|
|
|
let display = global.screen.get_display();
|
|
display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention));
|
|
let tracker = Shell.WindowTracker.get_default();
|
|
tracker.connect('startup-sequence-changed', Lang.bind(this, this._onStartupSequenceChanged));
|
|
},
|
|
|
|
_onStartupSequenceChanged : function(tracker) {
|
|
let sequences = tracker.get_startup_sequences();
|
|
this._startupIds = {};
|
|
for(let i = 0; i < sequences.length; i++) {
|
|
this._startupIds[sequences[i].get_id()] = true;
|
|
}
|
|
},
|
|
|
|
_getTitle : function(app, window) {
|
|
if (this._startupIds[window.get_startup_id()])
|
|
return app.get_name();
|
|
else
|
|
return window.title;
|
|
},
|
|
|
|
_getBanner : function(app, window) {
|
|
if (this._startupIds[window.get_startup_id()])
|
|
return _("%s has finished starting").format(app.get_name());
|
|
else
|
|
return _("'%s' is ready").format(window.title);
|
|
},
|
|
|
|
_onWindowDemandsAttention : function(display, window) {
|
|
// We don't want to show the notification when the window is already focused,
|
|
// because this is rather pointless.
|
|
// Some apps (like GIMP) do things like setting the urgency hint on the
|
|
// toolbar windows which would result into a notification even though GIMP itself is
|
|
// focused.
|
|
// We are just ignoring the hint on skip_taskbar windows for now.
|
|
// (Which is the same behaviour as with metacity + panel)
|
|
|
|
if (!window || window.has_focus() || window.is_skip_taskbar())
|
|
return;
|
|
|
|
let tracker = Shell.WindowTracker.get_default();
|
|
let app = tracker.get_window_app(window);
|
|
let appId = app.get_id();
|
|
|
|
let source = this._sources[appId];
|
|
if (source == null) {
|
|
source = new Source(app, window);
|
|
this._sources[appId] = source;
|
|
Main.messageTray.add(source);
|
|
source.connect('clicked', Lang.bind(this, function() { source.destroy(); }));
|
|
source.connect('destroy', Lang.bind(this, function() { delete this._sources[appId]; }));
|
|
}
|
|
|
|
let notification = new MessageTray.Notification(source, this._getTitle(app, window), this._getBanner(app, window));
|
|
source.notify(notification);
|
|
|
|
window.connect('notify::title', Lang.bind(this, function(win) {
|
|
notification.update(this._getTitle(app, win), this._getBanner(app, win));
|
|
}));
|
|
window.connect('notify::demands-attention', Lang.bind(this, function() { source.destroy(); }));
|
|
window.connect('focus', Lang.bind(this, function() { source.destroy(); }));
|
|
window.connect('unmanaged', Lang.bind(this, function() { source.destroy(); }));
|
|
|
|
}
|
|
};
|
|
|
|
function Source(app, window) {
|
|
this._init(app, window);
|
|
}
|
|
|
|
Source.prototype = {
|
|
__proto__ : MessageTray.Source.prototype,
|
|
|
|
_init: function(app, window) {
|
|
MessageTray.Source.prototype._init.call(this, app.get_name());
|
|
this._window = window;
|
|
this._app = app;
|
|
this._setSummaryIcon(this.createNotificationIcon());
|
|
},
|
|
|
|
createNotificationIcon : function() {
|
|
return this._app.create_icon_texture(this.ICON_SIZE);
|
|
},
|
|
|
|
clicked : function() {
|
|
Main.activateWindow(this._window);
|
|
MessageTray.Source.prototype.clicked.call(this);
|
|
}
|
|
|
|
};
|