diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js index a1f6509af..2b11387e3 100644 --- a/js/ui/messageTray.js +++ b/js/ui/messageTray.js @@ -328,6 +328,7 @@ Source.prototype = { this.text = null; if (createIcon) this.createIcon = createIcon; + this.handleReplacing = true; }, // This can be overridden by a subclass, or by the createIcon @@ -520,7 +521,7 @@ MessageTray.prototype = { }, _onNotify: function(source, notification) { - if (this._getNotification(notification.id, source) == null) { + if (!notification.source.handleReplacing || this._getNotification(notification.id, source) == null) { notification.connect('destroy', Lang.bind(this, this.removeNotification)); this._notificationQueue.push(notification); diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js index deb735226..7f5dfcf7e 100644 --- a/js/ui/notificationDaemon.js +++ b/js/ui/notificationDaemon.js @@ -10,6 +10,8 @@ const Main = imports.ui.main; const MessageTray = imports.ui.messageTray; const Params = imports.misc.params; +const EMPATHY = 'Empathy'; + let nextNotificationId = 1; // Should really be defined in dbus.js @@ -131,13 +133,46 @@ NotificationDaemon.prototype = { Notify: function(appName, replacesId, icon, summary, body, actions, hints, timeout) { - let source = Main.messageTray.getSource(this._sourceId(appName)); - let id = null; + let notification, id; + // We associate each application with a source and set the source id to be based on + // the appName. We support application updates by creating a new Notification object + // only if replacesId was not specified or if we no longer have the notification with + // the specified replacesId. + // + // We are planning to add Empathy-specific features in the message tray, but in the + // meantime we handle Empathy notifications received through the notification daemon + // differently from other notifications. + // 1) We display different people sending messages as different sources. So we use + // notification id instead of the appName when creating id for the source. + // 2) We queue notification with different messages to show them one after another, + // rather than replace the notification on the spot. So we create a new Notification + // object each time, disregarding the fact that we might already have another + // notification with the same replacesId. + // Empathy uses replacesId for all the notifications from the same window until the + // notification with that id is dismissed. Notifications from different people in + // different tabs have the same replacesId. So while being closer to the eventual design, + // our special-handling of Empathy notifications is somewhat buggy. The user might end up + // with multiple icons for the same person if the user dismisses the window for that person + // (which doesn't result in removing the icon) or the user might not get the icon for + // the person after a new notification in one of the tabs of the chat window for which + // another person's icon is already displayed. + + let isEmpathy = appName == EMPATHY; + if (replacesId != 0) { + id = replacesId; + if (!isEmpathy) + notification = this._currentNotifications[id]; + } else { + id = nextNotificationId++; + } + + let sourceId = this._sourceId(isEmpathy ? id : appName); + let source = Main.messageTray.getSource(sourceId); // Source may be null if we have never received a notification from // this app or if all notifications from this app have been acknowledged. if (source == null) { - source = new Source(this._sourceId(appName), icon, hints); + source = new Source(sourceId, icon, hints); Main.messageTray.add(source); source.connect('clicked', Lang.bind(this, @@ -166,15 +201,14 @@ NotificationDaemon.prototype = { } } - let notification; - if (replacesId != 0) { - id = replacesId; - notification = this._currentNotifications[id]; - } - if (notification == null) { - id = nextNotificationId++; notification = new MessageTray.Notification(id, source, summary, body, true); + // This will result in us keeping only the latest Empathy notification with the given + // id in this._currentNotifications, which will only affect not being able to close all + // the Empathy notifications with a given id in CloseNotification(). Since this not a + // a likely scenario and this special-casing of Empathy in the notification daemon is + // temporary, it doesn't seem worthwhile to change this._currentNotifications to + // {id, [array of notifications]} just for that case. this._currentNotifications[id] = notification; notification.connect('dismissed', Lang.bind(this, function(n) { @@ -313,6 +347,9 @@ Source.prototype = { this.app = app; if (this._openAppRequested) this.openApp(); + + if (app.get_name() == EMPATHY) + this.handleReplacing = false; }, openApp: function() {