[gnome-shell] legacyTray: Add a hideable tray for legacy status icons



commit 874cf0ba158bdbaf07ab13fd3d82dde40e386032
Author: Florian Müllner <fmuellner gnome org>
Date:   Thu Feb 26 16:52:12 2015 +0100

    legacyTray: Add a hideable tray for legacy status icons
    
    Commit 5a8923ef95a2 removed support for legacy status icons from
    the notification system, as we no longer want them to appear as
    notifications. As we are unfortunately not quite at a point where
    we can remove all support for them for good, so we now need an
    alternative place to put them. Add a small dedicated tray at the
    bottom which appears when any legacy status icons are active. By
    default it is almost completely hidden to not interfere with the
    user's windows, but can be expanded on demand to interact with
    the icons.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=745162

 data/theme/gnome-shell-high-contrast.css |   21 ++++
 data/theme/gnome-shell.css               |   21 ++++
 js/js-resources.gresource.xml            |    1 +
 js/ui/legacyTray.js                      |  178 ++++++++++++++++++++++++++++++
 js/ui/main.js                            |    3 +
 5 files changed, 224 insertions(+), 0 deletions(-)
---
diff --git a/data/theme/gnome-shell-high-contrast.css b/data/theme/gnome-shell-high-contrast.css
index b9698f4..730d725 100644
--- a/data/theme/gnome-shell-high-contrast.css
+++ b/data/theme/gnome-shell-high-contrast.css
@@ -1327,6 +1327,27 @@ StScrollBar {
   color: pink; }
 
 /* Eeeky things */
+.legacy-tray {
+  background-color: #000;
+  border: 1px solid black;
+  border-bottom-width: 0; }
+  .legacy-tray:ltr {
+    border-radius: 0 6px 0 0;
+    border-left-width: 0; }
+  .legacy-tray:rtl {
+    border-radius: 6px 0 0 0;
+    border-right-width: 0; }
+
+.legacy-tray-handle StIcon {
+  icon-size: 24px; }
+
+.legacy-tray-icon-box {
+  padding: 6px;
+  spacing: 12px; }
+  .legacy-tray-icon-box StButton {
+    width: 24px;
+    height: 24px; }
+
 .magnifier-zoom-region {
   border: 2px solid #215d9c; }
   .magnifier-zoom-region.full-screen {
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 032c362..117504f 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -1327,6 +1327,27 @@ StScrollBar {
   color: pink; }
 
 /* Eeeky things */
+.legacy-tray {
+  background-color: #393f3f;
+  border: 1px solid #1c1f1f;
+  border-bottom-width: 0; }
+  .legacy-tray:ltr {
+    border-radius: 0 6px 0 0;
+    border-left-width: 0; }
+  .legacy-tray:rtl {
+    border-radius: 6px 0 0 0;
+    border-right-width: 0; }
+
+.legacy-tray-handle StIcon {
+  icon-size: 24px; }
+
+.legacy-tray-icon-box {
+  padding: 6px;
+  spacing: 12px; }
+  .legacy-tray-icon-box StButton {
+    width: 24px;
+    height: 24px; }
+
 .magnifier-zoom-region {
   border: 2px solid #215d9c; }
   .magnifier-zoom-region.full-screen {
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index 439c0aa..bd8f307 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -57,6 +57,7 @@
     <file>ui/layout.js</file>
     <file>ui/lightbox.js</file>
     <file>ui/lookingGlass.js</file>
+    <file>ui/legacyTray.js</file>
     <file>ui/magnifier.js</file>
     <file>ui/magnifierDBus.js</file>
     <file>ui/main.js</file>
diff --git a/js/ui/legacyTray.js b/js/ui/legacyTray.js
new file mode 100644
index 0000000..a167ea2
--- /dev/null
+++ b/js/ui/legacyTray.js
@@ -0,0 +1,178 @@
+const Clutter = imports.gi.Clutter;
+const GObject = imports.gi.GObject;
+const Shell = imports.gi.Shell;
+const St = imports.gi.St;
+
+const Lang = imports.lang;
+const Layout = imports.ui.layout;
+const Main = imports.ui.main;
+const Overview = imports.ui.overview;
+const OverviewControls = imports.ui.overviewControls;
+const Tweener = imports.ui.tweener;
+
+const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
+    'bluetooth-applet': 'bluetooth',
+    'gnome-volume-control-applet': 'volume', // renamed to gnome-sound-applet
+                                             // when moved to control center
+    'gnome-sound-applet': 'volume',
+    'nm-applet': 'network',
+    'gnome-power-manager': 'battery',
+    'keyboard': 'keyboard',
+    'a11y-keyboard': 'a11y',
+    'kbd-scrolllock': 'keyboard',
+    'kbd-numlock': 'keyboard',
+    'kbd-capslock': 'keyboard',
+    'ibus-ui-gtk': 'keyboard'
+};
+
+// Offset of the original position from the bottom-right corner
+const CONCEALED_VISIBLE_FRACTION = 0.2;
+const REVEAL_ANIMATION_TIME = 0.2;
+
+const LegacyTray = new Lang.Class({
+    Name: 'LegacyTray',
+
+    _init: function() {
+        this.actor = new St.Widget({ clip_to_allocation: true,
+                                     layout_manager: new Clutter.BinLayout() });
+        let constraint = new Layout.MonitorConstraint({ primary: true,
+                                                        work_area: true });
+        this.actor.add_constraint(constraint);
+
+        this._slideLayout = new OverviewControls.SlideLayout();
+        this._slideLayout.translationX = 0;
+        this._slideLayout.slideDirection = OverviewControls.SlideDirection.LEFT;
+
+        this._slider = new St.Widget({ style_class: 'legacy-tray',
+                                       x_expand: true, y_expand: true,
+                                       x_align: Clutter.ActorAlign.START,
+                                       y_align: Clutter.ActorAlign.END,
+                                       layout_manager: this._slideLayout });
+        this.actor.add_actor(this._slider);
+
+        this._box = new St.BoxLayout();
+        this._slider.add_actor(this._box);
+
+        this._concealHandle = new St.Button({ style_class: 'legacy-tray-handle' });
+        this._concealHandle.child = new St.Icon({ icon_name: 'go-previous-symbolic' });
+        this._box.add_child(this._concealHandle);
+
+        this._iconBox = new St.BoxLayout({ style_class: 'legacy-tray-icon-box' });
+        this._box.add_actor(this._iconBox);
+
+        this._revealHandle = new St.Button({ style_class: 'legacy-tray-handle' });
+        this._revealHandle.child = new St.Icon({ icon_name: 'go-next-symbolic' });
+        this._box.add_child(this._revealHandle);
+
+        this._revealHandle.bind_property('visible',
+                                         this._concealHandle, 'visible',
+                                         GObject.BindingFlags.BIDIRECTIONAL |
+                                         GObject.BindingFlags.INVERT_BOOLEAN);
+        this._revealHandle.connect('notify::visible',
+                                   Lang.bind(this, this._sync));
+        this._revealHandle.connect('notify::hover',
+                                   Lang.bind(this ,this._sync));
+        this._revealHandle.connect('clicked', Lang.bind(this,
+            function() {
+                this._concealHandle.show();
+            }));
+        this._concealHandle.connect('clicked', Lang.bind(this,
+            function() {
+                this._revealHandle.show();
+            }));
+
+        Main.layoutManager.addChrome(this.actor, { affectsInputRegion: false });
+        Main.layoutManager.trackChrome(this._slider, { affectsInputRegion: true });
+
+        this._trayManager = new Shell.TrayManager();
+        this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
+        this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
+        this._trayManager.manage_screen(global.screen, this.actor);
+
+        Main.overview.connect('showing', Lang.bind(this,
+            function() {
+                Tweener.removeTweens(this._slider);
+                Tweener.addTween(this._slider, { opacity: 0,
+                                                 time: Overview.ANIMATION_TIME,
+                                                 transition: 'easeOutQuad' });
+            }));
+        Main.overview.connect('shown', Lang.bind(this, this._sync));
+        Main.overview.connect('hiding', Lang.bind(this,
+            function() {
+                this._sync();
+                Tweener.removeTweens(this._slider);
+                Tweener.addTween(this._slider, { opacity: 255,
+                                                 time: Overview.ANIMATION_TIME,
+                                                 transition: 'easeOutQuad' });
+            }));
+
+        Main.layoutManager.connect('monitors-changed',
+                                   Lang.bind(this, this._sync));
+        global.screen.connect('in-fullscreen-changed',
+                              Lang.bind(this, this._sync));
+        Main.sessionMode.connect('updated', Lang.bind(this, this._sync));
+
+        this._sync();
+    },
+
+    _onTrayIconAdded: function(tm, icon) {
+        let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : '';
+        if (STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined)
+            return;
+
+        let button = new St.Button({ child: icon,
+                                     button_mask: St.ButtonMask.ONE |
+                                                  St.ButtonMask.TWO |
+                                                  St.ButtonMask.THREE,
+                                     x_fill: true, y_fill: true });
+        button.connect('clicked',
+            function() {
+                icon.click(Clutter.get_current_event());
+            });
+
+        this._iconBox.add_actor(button);
+        this._sync();
+    },
+
+    _onTrayIconRemoved: function(tm, icon) {
+        if (!this.actor.contains(icon))
+            return;
+
+        icon.get_parent().destroy();
+        this._sync();
+    },
+
+    _sync: function() {
+        // FIXME: we no longer treat tray icons as notifications
+        let allowed = Main.sessionMode.hasNotifications;
+        let hasIcons = this._iconBox.get_n_children() > 0;
+        let inOverview = Main.overview.visible && !Main.overview.animationInProgress;
+        let inFullscreen = Main.layoutManager.primaryMonitor.inFullscreen;
+        this.actor.visible = allowed && hasIcons && !inOverview && !inFullscreen;
+
+        if (!hasIcons)
+            this._concealHandle.hide();
+
+        let targetSlide;
+        if (this._concealHandle.visible) {
+            targetSlide = 1.0;
+        } else if (!hasIcons) {
+            targetSlide = 0.0;
+        } else {
+            let [, boxWidth] = this._box.get_preferred_width(-1);
+            let [, handleWidth] = this._revealHandle.get_preferred_width(-1);
+
+            targetSlide = handleWidth / boxWidth;
+            if (!this._revealHandle.hover)
+                targetSlide *= CONCEALED_VISIBLE_FRACTION;
+        }
+
+        if (this.actor.visible)
+            Tweener.addTween(this._slideLayout,
+                             { slideX: targetSlide,
+                               time: REVEAL_ANIMATION_TIME,
+                               transition: 'easeOutQuad' });
+        else
+            this._slideLayout.slideX = targetSlide;
+    }
+});
diff --git a/js/ui/main.js b/js/ui/main.js
index eb65458..2a80a90 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -18,6 +18,7 @@ const Environment = imports.ui.environment;
 const ExtensionSystem = imports.ui.extensionSystem;
 const ExtensionDownloader = imports.ui.extensionDownloader;
 const Keyboard = imports.ui.keyboard;
+const LegacyTray = imports.ui.legacyTray;
 const MessageTray = imports.ui.messageTray;
 const ModalDialog = imports.ui.modalDialog;
 const OsdWindow = imports.ui.osdWindow;
@@ -52,6 +53,7 @@ let overview = null;
 let runDialog = null;
 let lookingGlass = null;
 let wm = null;
+let legacyTray = null;
 let messageTray = null;
 let screenShield = null;
 let notificationDaemon = null;
@@ -159,6 +161,7 @@ function _initializeUI() {
     if (LoginManager.canLock())
         screenShield = new ScreenShield.ScreenShield();
 
+    legacyTray = new LegacyTray.LegacyTray();
     messageTray = new MessageTray.MessageTray();
     panel = new Panel.Panel();
     keyboard = new Keyboard.Keyboard();


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