diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index ee7a75654..2657f14ea 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -561,6 +561,28 @@ StTooltip { spacing-columns: 10px; } +#notification-actions { + spacing: 5px; +} + +.notification-button { + border: 2px rgba(0,0,0,0.0); + border-radius: 5px; + padding: 5px; + background: #c0c0c0; + color: black; + font-weight: bold; +} + +.notification-button:hover { + border: 2px solid white; +} + +.notification-button:active { + border: 2px solid white; + background: #808080; +} + #summary-mode { spacing: 10px; padding: 2px 4px; diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js index 2e5ad5a98..4c01bb3b2 100644 --- a/js/ui/messageTray.js +++ b/js/ui/messageTray.js @@ -103,6 +103,25 @@ Notification.prototype = { this.actor.add(this._bodyText, { row: 1, col: 1 }); + this.actions = {}; + this._buttonBox = null; + }, + + addAction: function(id, label) { + if (!this._buttonBox) { + this._buttonBox = new St.BoxLayout({ name: 'notification-actions' }); + this.actor.add(this._buttonBox, { row: 2, + col: 1, + x_expand: false, + x_fill: false, + x_align: 1.0 }); + this._canPopOut = true; + } + + let button = new St.Button({ style_class: 'notification-button', + label: label }); + this._buttonBox.add(button); + button.connect('clicked', Lang.bind(this, function() { this.emit('action-invoked', id); })); }, _bannerBoxGetPreferredWidth: function(actor, forHeight, alloc) { @@ -167,6 +186,7 @@ Notification.prototype = { return true; } }; +Signals.addSignalMethods(Notification.prototype); function Source(id, createIcon) { this._init(id, createIcon); diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js index ce8dd8b42..cd50b7943 100644 --- a/js/ui/notificationDaemon.js +++ b/js/ui/notificationDaemon.js @@ -124,6 +124,12 @@ NotificationDaemon.prototype = { summary = GLib.markup_escape_text(summary, -1); let notification = new MessageTray.Notification(source, summary, body); + if (actions.length) { + for (let i = 0; i < actions.length - 1; i += 2) + notification.addAction(actions[i], actions[i + 1]); + notification.connect('action-invoked', Lang.bind(this, this._actionInvoked, source, id)); + } + source.notify(notification); return id; }, @@ -137,7 +143,7 @@ NotificationDaemon.prototype = { GetCapabilities: function() { return [ - // 'actions', + 'actions', 'body', // 'body-hyperlinks', // 'body-images', @@ -157,11 +163,23 @@ NotificationDaemon.prototype = { ]; }, + _actionInvoked: function(notification, action, source, id) { + this._emitActionInvoked(id, action); + source.destroy(); + }, + _emitNotificationClosed: function(id, reason) { DBus.session.emit_signal('/org/freedesktop/Notifications', 'org.freedesktop.Notifications', 'NotificationClosed', 'uu', [id, reason]); + }, + + _emitActionInvoked: function(id, action) { + DBus.session.emit_signal('/org/freedesktop/Notifications', + 'org.freedesktop.Notifications', + 'ActionInvoked', 'us', + [id, action]); } };