diff --git a/files/usr/share/cinnamon/applets/notifications@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/notifications@cinnamon.org/applet.js index 8aa2d6778a..22ee08e1d0 100644 --- a/files/usr/share/cinnamon/applets/notifications@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/notifications@cinnamon.org/applet.js @@ -1,5 +1,4 @@ const Applet = imports.ui.applet; -const Lang = imports.lang; const Main = imports.ui.main; const Gtk = imports.gi.Gtk; const Gio = imports.gi.Gio; @@ -11,6 +10,7 @@ const NotificationDestroyedReason = imports.ui.messageTray.NotificationDestroyed const Settings = imports.ui.settings; const Gettext = imports.gettext.domain("cinnamon-applets"); const Util = imports.misc.util; +const SignalManager = imports.misc.signalManager; const PANEL_EDIT_MODE_KEY = "panel-edit-mode"; @@ -32,34 +32,51 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { // Layout this._orientation = orientation; this.menuManager = new PopupMenu.PopupMenuManager(this); + this.menu = new Applet.AppletPopupMenu(this, orientation); + this.menuManager.addMenu(this.menu); // Lists this.notifications = []; // The list of notifications, in order from oldest to newest. // Events - Main.messageTray.connect('notify-applet-update', Lang.bind(this, this._notification_added)); - global.settings.connect('changed::' + PANEL_EDIT_MODE_KEY, Lang.bind(this, this._on_panel_edit_mode_changed)); + this.signals = new SignalManager.SignalManager(null); + this.signals.connect(Main.messageTray, 'notify-applet-update', this._notification_added.bind(this)); + this.signals.connect(global.settings, 'changed::' + PANEL_EDIT_MODE_KEY, this._on_panel_edit_mode_changed.bind(this)); + this.signals.connect(this.menu, 'menu-animated-closed', this._onMenuClosed.bind(this)); // States this._blinking = false; this._blink_toggle = false; + + this._display(); } _setKeybinding() { - Main.keybindingManager.addHotKey("notification-open-" + this.instance_id, this.keyOpen, Lang.bind(this, this._openMenu)); - Main.keybindingManager.addHotKey("notification-clear-" + this.instance_id, this.keyClear, Lang.bind(this, this._clear_all)); + Main.keybindingManager.addHotKey("notification-open-" + this.instance_id, this.keyOpen, this._openMenu.bind(this)); + Main.keybindingManager.addHotKey("notification-clear-" + this.instance_id, this.keyClear, this._clear_all.bind(this)); } on_applet_removed_from_panel () { Main.keybindingManager.removeHotKey("notification-open-" + this.instance_id); Main.keybindingManager.removeHotKey("notification-clear-" + this.instance_id); + + this.destroy(); } _openMenu() { this._update_timestamp(); + + this.notifications.forEach(notification => { + global.reparentActor(notification.actor, this._notificationbin); + }); + this.menu.toggle(); } + _onMenuClosed() { + this._notificationbin.remove_all_children(); + } + _display() { // Always start the applet empty, void of any notifications. this.set_applet_icon_symbolic_name("empty-notif"); @@ -68,7 +85,6 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { // Setup the notification container. this._maincontainer = new St.BoxLayout({name: 'traycontainer', vertical: true}); this._notificationbin = new St.BoxLayout({vertical:true}); - this.button_label_box = new St.BoxLayout(); // Setup the tray icon. this.menu_label = new PopupMenu.PopupMenuItem(stringify(this.notifications.length)); @@ -79,21 +95,14 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { this.clear_separator = new PopupMenu.PopupSeparatorMenuItem(); this.clear_action = new PopupMenu.PopupMenuItem(_("Clear notifications")); - this.clear_action.connect('activate', Lang.bind(this, this._clear_all)); + this.clear_action.connect('activate', this._clear_all.bind(this)); this.clear_action.actor.hide(); - if (this._orientation == St.Side.BOTTOM) { - this.menu.addMenuItem(this.menu_label); - this.menu.addActor(this._maincontainer); - this.menu.addMenuItem(this.clear_separator); - this.menu.addMenuItem(this.clear_action); - } else { - this.menu.addMenuItem(this.clear_action); - this.menu.addMenuItem(this.clear_separator); - this.menu.addMenuItem(this.menu_label); - this.menu.addActor(this._maincontainer); - } - + this.menu.addMenuItem(this.clear_action); + this.menu.addMenuItem(this.clear_separator); + this.menu.addMenuItem(this.menu_label); + this.menu.addActor(this._maincontainer); + this.scrollview = new St.ScrollView({ x_fill: true, y_fill: true, y_align: St.Align.START, style_class: "vfade"}); this._maincontainer.add(this.scrollview); this.scrollview.add_actor(this._notificationbin); @@ -101,12 +110,8 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { this.scrollview.set_clip_to_allocation(true); let vscroll = this.scrollview.get_vscroll_bar(); - vscroll.connect('scroll-start', Lang.bind(this, function() { - this.menu.passEvents = true; - })); - vscroll.connect('scroll-stop', Lang.bind(this, function() { - this.menu.passEvents = false; - })); + vscroll.connect('scroll-start', () => this.menu.passEvents = true); + vscroll.connect('scroll-stop', () => this.menu.passEvents = false); // Alternative tray icons. this._crit_icon = new St.Icon({icon_name: 'critical-notif', icon_type: St.IconType.SYMBOLIC, reactive: true, track_hover: true, style_class: 'system-status-icon' }); @@ -114,7 +119,26 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { this._on_panel_edit_mode_changed(); - this.menu.addSettingsAction(_("Notification Settings"), 'notifications'); + this.settingsMenuItem = this.menu.addSettingsAction(_("Notification Settings"), 'notifications'); + } + + _arrangeDisplay() { + // Remove menu actors so we can put them back in a different order according to orientation. + this.menu.box.remove_all_children(); + + if (this._orientation == St.Side.BOTTOM) { + this.menu.addActor(this.menu_label.actor); + this.menu.addActor(this._maincontainer); + this.menu.addActor(this.clear_separator.actor); + this.menu.addActor(this.clear_action.actor); + } else { + this.menu.addActor(this.clear_action.actor); + this.menu.addActor(this.clear_separator.actor); + this.menu.addActor(this.menu_label.actor); + this.menu.addActor(this._maincontainer); + } + + this.menu.addActor(this.settingsMenuItem.actor); } _notification_added (mtray, notification) { // Notification event handler. @@ -130,8 +154,6 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { if (notification._destroyed) { this.notifications.splice(existing_index, 1); } else { - notification._inNotificationBin = true; - global.reparentActor(notification.actor, this._notificationbin); notification._timeLabel.show(); } this.update_list(); @@ -140,11 +162,8 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { return; } // Add notification to list. - notification._inNotificationBin = true; this.notifications.push(notification); - // Steal the notification panel. - this._notificationbin.add(notification.actor); - notification.actor._parent_container = this._notificationbin; + notification.actor.add_style_class_name('notification-applet-padding'); // Register for destruction. notification.connect('scrolling-changed', (notif, scrolling) => { this.menu.passEvents = scrolling }); @@ -161,7 +180,7 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { update_list () { try { - let count = this.notifications.length; + const count = this.notifications.length; if (count > 0) { // There are notifications. this.actor.show(); this.clear_action.actor.show(); @@ -249,12 +268,7 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { on_orientation_changed (orientation) { this._orientation = orientation; - if (this.menu) { - this.menu.destroy(); - } - this.menu = new Applet.AppletPopupMenu(this, orientation); - this.menuManager.addMenu(this.menu); - this._display(); + this._arrangeDisplay(); } on_applet_clicked(event) { @@ -285,7 +299,14 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { this._applet_icon_box.child = this._alt_crit_icon; } this._blink_toggle = !this._blink_toggle; - Mainloop.timeout_add_seconds(1, Lang.bind(this, this.critical_blink)); + Mainloop.timeout_add_seconds(1, this.critical_blink.bind(this)); + } + + destroy() { + this.signals.disconnectAllSignals(); + this._crit_icon.destroy(); + this._alt_crit_icon.destroy(); + this.menu.destroy(); } } diff --git a/files/usr/share/cinnamon/applets/notifications@cinnamon.org/metadata.json b/files/usr/share/cinnamon/applets/notifications@cinnamon.org/metadata.json index 6daa046102..38ac5d9ff5 100644 --- a/files/usr/share/cinnamon/applets/notifications@cinnamon.org/metadata.json +++ b/files/usr/share/cinnamon/applets/notifications@cinnamon.org/metadata.json @@ -3,5 +3,6 @@ "name": "Notifications", "description": "Click to display and manage system notifications", "role": "notifications", -"icon": "cs-notifications" +"icon": "cs-notifications", +"max-instances": -1 } diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js index 8d590249c8..e561a41f17 100644 --- a/js/ui/messageTray.js +++ b/js/ui/messageTray.js @@ -258,12 +258,10 @@ var Notification = class Notification { this._actionArea = null; this._imageBin = null; this._timestamp = new Date(); - this._inNotificationBin = false; source.connect('destroy', (source, reason) => { this.destroy(reason) }); this.actor = new St.Button({ accessible_role: Atk.Role.NOTIFICATION }); - this.actor._parent_container = null; this.actor.connect('clicked', () => this._onClicked()); this.actor.connect('destroy', () => this._onDestroy()); @@ -344,7 +342,6 @@ var Notification = class Notification { */ update(title, body, params) { this._timestamp = new Date(); - this._inNotificationBin = false; params = Params.parse(params, { icon: null, titleMarkup: false, @@ -951,8 +948,8 @@ MessageTray.prototype = { _showNotification: function () { this._notification = this._notificationQueue.shift(); - if (this._notification.actor._parent_container) { - this._notification.actor._parent_container.remove_actor(this._notification.actor); + if (this._notification.actor.get_parent()) { + this._notification.actor.get_parent().remove_actor(this._notification.actor); } this._notificationBin.child = this._notification.actor;