[gnome-shell/message-tray] Combine notifications and the summary mode in a single message tray



commit 4ab513ca77204e1a1c4df7ce7ef4d3484347a07c
Author: Marina Zhurakhinskaya <marinaz redhat com>
Date:   Wed Jan 6 16:27:08 2010 -0500

    Combine notifications and the summary mode in a single message tray
    
    We should either be showing the message tray in the notification or the summary mode.
    This is best achieved if the message tray actor contains both, and either one is shown
    at any given time.
    
    Queue notifications so that each queued notification is shown when the previous one
    times out or when the user is done interacting with the message tray and moves
    the mouse away from it. (In the future, we will have some sort of an indication that
    there are queued notifications and a way to have the next notification displayed
    without moving the mouse away from the message tray.)

 data/theme/gnome-shell.css |   21 +++---
 js/ui/messageTray.js       |  152 ++++++++++++++++++++++++--------------------
 2 files changed, 92 insertions(+), 81 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index e82b2e6..99b70b7 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -473,25 +473,24 @@ StTooltip {
 }
 
 /* Message Tray */
+#message-tray {
+    background-gradient-direction: vertical;
+    background-gradient-start: rgba(0,0,0,0.01);
+    background-gradient-end: rgba(0,0,0,0.95);
+    height: 28px;
+}
+
 #notification {
     border-radius: 5px;
     background: rgba(0,0,0,0.9);
-    border: 1px solid rgba(128,128,128,0.45);
     color: white;
-    padding: 4px;
+    padding: 2px 10px;
     spacing: 10px;
 }
 
-#message-tray {
-    border-radius: 5px;
-    background: rgba(0,0,0,0.9);
-    border: 1px solid rgba(128,128,128,0.45);
-    padding: 4px;
-    height: 40px;
-}
-
-#message-tray-inner {
+#summary-mode {
     spacing: 10px;
+    padding: 2px 4px;
 }
 
 /* App Switcher */
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index be21c42..3522a1a 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -16,11 +16,22 @@ const MESSAGE_TRAY_TIMEOUT = 0.2;
 
 const ICON_SIZE = 24;
 
-function Notification() {
-    this._init();
+function Notification(icon, text) {
+    this._init(icon, text);
 }
 
 Notification.prototype = {
+    _init: function(icon, text) {
+        this.icon = icon;
+        this.text = text;
+    }
+}
+
+function NotificationBox() {
+    this._init();
+}
+
+NotificationBox.prototype = {
     _init: function() {
         this.actor = new St.BoxLayout({ name: 'notification' });
 
@@ -29,55 +40,11 @@ Notification.prototype = {
 
         this._text = new St.Label();
         this.actor.add(this._text, { expand: true, x_fill: false, y_fill: false, y_align: St.Align.MIDDLE });
-
-        Main.chrome.addActor(this.actor, { affectsStruts: false });
-
-        let primary = global.get_primary_monitor();
-        this.actor.y = primary.height;
-
-        this._hideTimeoutId = 0;
     },
 
-    show: function(icon, text) {
-        let primary = global.get_primary_monitor();
-
-        if (this._hideTimeoutId > 0) 
-            Mainloop.source_remove(this._hideTimeoutId);
-        this._hideTimeoutId = Mainloop.timeout_add(NOTIFICATION_TIMEOUT * 1000, Lang.bind(this, this.hide));
-
-        this._iconBox.child = icon;
-        this._text.text = text;
-
-        this.actor.x = Math.round((primary.width - this.actor.width) / 2);
-        this.actor.show();
-        Tweener.addTween(this.actor,
-                         { y: primary.height - this.actor.height,
-                           time: ANIMATION_TIME,
-                           transition: "easeOutQuad"
-                         });
-    },
-
-    hide: function() {
-        let primary = global.get_primary_monitor();
-        this._hideTimeoutId = 0;
-
-        Tweener.addTween(this.actor,
-                         { y: primary.height,
-                           time: ANIMATION_TIME,
-                           transition: "easeOutQuad",
-                           onComplete: this.hideComplete,
-                           onCompleteScope: this
-                         });
-        return false;
-    },
-
-    hideComplete: function() {
-        if (this._iconBox.child)
-            this._iconBox.child.destroy();
-
-        // Don't hide the notification if we are showing a new one.
-        if (this._hideTimeoutId == 0)
-            this.actor.hide();
+    setContent: function(notification) {
+        this._iconBox.child = notification.icon;
+        this._text.text = notification.text;
     }
 };
 
@@ -99,7 +66,7 @@ Source.prototype = {
     },
 
     notify: function(text) {
-        Main.notificationPopup.show(this.createIcon(ICON_SIZE), text);
+        Main.messageTray.showNotification(new Notification(this.createIcon(ICON_SIZE), text));
     },
 
     clicked: function() {
@@ -118,10 +85,8 @@ function MessageTray() {
 
 MessageTray.prototype = {
     _init: function() {
-        this.actor = new St.Bin({ name: 'message-tray',
-                                  reactive: true,
-                                  x_align: St.Align.END });
-        Main.chrome.addActor(this.actor, { affectsStruts: false });
+        this.actor = new St.BoxLayout({ name: 'message-tray',
+                                        reactive: true });
 
         let primary = global.get_primary_monitor();
         this.actor.x = 0;
@@ -129,6 +94,17 @@ MessageTray.prototype = {
 
         this.actor.width = primary.width;
 
+        this._summaryBin = new St.Bin({ x_align: St.Align.END });
+        this.actor.add(this._summaryBin, { expand: true });
+        this._summaryBin.hide();
+
+        this._notificationBox = new NotificationBox();
+        this._notificationQueue = [];
+        this.actor.add(this._notificationBox.actor);
+        this._notificationBox.actor.hide();
+
+        Main.chrome.addActor(this.actor, { affectsStruts: false });
+
         this.actor.connect('enter-event',
                            Lang.bind(this, this._onMessageTrayEntered));
         this.actor.connect('leave-event',
@@ -136,9 +112,9 @@ MessageTray.prototype = {
         this._isShowing = false;
         this.actor.show();
 
-        this._tray = new St.BoxLayout({ name: 'message-tray-inner' });
-        this.actor.child = this._tray;
-        this._tray.expand = true;
+        this._summary = new St.BoxLayout({ name: 'summary-mode' });
+        this._summaryBin.child = this._summary;
+
         this._sources = {};
         this._icons = {};
     },
@@ -155,7 +131,7 @@ MessageTray.prototype = {
 
         let iconBox = new St.Bin({ reactive: true });
         iconBox.child = source.createIcon(ICON_SIZE);
-        this._tray.insert_actor(iconBox, 0);
+        this._summary.insert_actor(iconBox, 0);
         this._icons[source.id] = iconBox;
         this._sources[source.id] = source;
 
@@ -174,7 +150,7 @@ MessageTray.prototype = {
         if (!this.contains(source))
             return;
 
-        this._tray.remove_actor(this._icons[source.id]);
+        this._summary.remove_actor(this._icons[source.id]);
         delete this._icons[source.id];
         delete this._sources[source.id];
     },
@@ -184,30 +160,39 @@ MessageTray.prototype = {
     },
 
     _onMessageTrayEntered: function() {
+        // Don't hide the message tray after a timeout if the user has moved the mouse over it.
+        // We might have a timeout in place if the user moved the mouse away from the message tray for a very short period of time
+        // or if we are showing a notification.
         if (this._hideTimeoutId > 0)
             Mainloop.source_remove(this._hideTimeoutId);
 
         if (this._isShowing)
             return;
 
-        this._isShowing = true;
-        let primary = global.get_primary_monitor();
-        Tweener.addTween(this.actor,
-                         { y: primary.height - this.actor.height,
-                           time: ANIMATION_TIME,
-                           transition: "easeOutQuad"
-                         });
+        // If the message tray was not already showing, we'll show it in the summary mode.
+        this._summaryBin.show();
+        this._show();
     },
 
     _onMessageTrayLeft: function() {
         if (!this._isShowing)
             return;
 
+        // We wait just a little before hiding the message tray in case the user will quickly move the mouse back over it.
         this._hideTimeoutId = Mainloop.timeout_add(MESSAGE_TRAY_TIMEOUT * 1000, Lang.bind(this, this._hide));
     },
 
+    _show: function() {
+        this._isShowing = true;
+        let primary = global.get_primary_monitor();
+        Tweener.addTween(this.actor,
+                         { y: primary.height - this.actor.height,
+                           time: ANIMATION_TIME,
+                           transition: "easeOutQuad"
+                         });
+    },
+
     _hide: function() {
-        this._isShowing = false;
         this._hideTimeoutId = 0;
 
         let primary = global.get_primary_monitor();
@@ -215,9 +200,36 @@ MessageTray.prototype = {
         Tweener.addTween(this.actor,
                          { y: primary.height - 1,
                            time: ANIMATION_TIME,
-                           transition: "easeOutQuad"
+                           transition: "easeOutQuad",
+                           onComplete: this._hideComplete,
+                           onCompleteScope: this
                          });
         return false;
-    }
-};
+    },
 
+    _hideComplete: function() {
+        this._isShowing = false;
+        this._summaryBin.hide();
+        this._notificationBox.actor.hide();
+        if (this._notificationQueue.length > 0)
+            this.showNotification(this._notificationQueue.shift());
+    },
+
+    showNotification: function(notification) {
+        if (this._isShowing) {
+            this._notificationQueue.push(notification);
+            return;
+        }
+
+        this._notificationBox.setContent(notification);
+
+        this._notificationBox.actor.x = Math.round((this.actor.width - this._notificationBox.actor.width) / 2);
+        this._notificationBox.actor.show();
+
+        // Because we set up the timeout before we do the animation, we add ANIMATION_TIME to NOTIFICATION_TIMEOUT, so that
+        // NOTIFICATION_TIMEOUT represents the time the notifiation is fully shown.
+        this._hideTimeoutId = Mainloop.timeout_add((NOTIFICATION_TIMEOUT + ANIMATION_TIME) * 1000, Lang.bind(this, this._hide));
+
+        this._show();
+     }
+};



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]