From 5cca26a565078dce37ef083794fdd0b8affa4114 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Thu, 6 Jun 2013 17:27:25 -0400 Subject: [PATCH] status: Port to a new SystemIndicator framework We can't silently replace the old behavior of separate status icons into a new system. Replace SystemStatusButton with a new SystemIndicator class which will allow for the flexibility we need. For now, make it a subclass of Button so that it mostly feels the same, but we'll soon be swapping it out with a dummy implementation that the aggregate menu will use. I think the code cleanup here is worth it. https://bugzilla.gnome.org/show_bug.cgi?id=705845 --- data/theme/gnome-shell.css | 2 +- js/gdm/powerMenu.js | 2 +- js/ui/panelMenu.js | 48 +++++++++------------------------- js/ui/status/bluetooth.js | 10 ++++--- js/ui/status/lockScreenMenu.js | 10 +++---- js/ui/status/network.js | 25 +++++++++--------- js/ui/status/power.js | 16 ++++++------ js/ui/status/system.js | 6 +++-- js/ui/status/volume.js | 17 ++++++++---- 9 files changed, 62 insertions(+), 74 deletions(-) diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 46b5a75bb..a63c5e739 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -614,7 +614,7 @@ StScrollBar StButton#vhandle:active { -boxpointer-gap: 4px; } -.panel-status-button-box, +.panel-status-indicators-box, .panel-status-menu-box { spacing: 4px; } diff --git a/js/gdm/powerMenu.js b/js/gdm/powerMenu.js index a341619fd..487c1c6fe 100644 --- a/js/gdm/powerMenu.js +++ b/js/gdm/powerMenu.js @@ -29,7 +29,7 @@ const PopupMenu = imports.ui.popupMenu; const PowerMenuButton = new Lang.Class({ Name: 'PowerMenuButton', - Extends: PanelMenu.SystemStatusButton, + Extends: PanelMenu.SystemIndicator, _init: function() { /* Translators: accessible name of the power menu in the login screen */ diff --git a/js/ui/panelMenu.js b/js/ui/panelMenu.js index d77143b17..fb2156631 100644 --- a/js/ui/panelMenu.js +++ b/js/ui/panelMenu.js @@ -233,51 +233,29 @@ const Button = new Lang.Class({ }); Signals.addSignalMethods(Button.prototype); -/* SystemStatusButton: +/* SystemIndicator: * - * This class manages one System Status indicator (network, keyboard, - * volume, bluetooth...), which is just a PanelMenuButton with an - * icon. + * This class manages one system indicator, which are the icons + * that you see at the top right. A system indicator is composed + * of an icon and a menu section, which will be composed into the + * aggregate menu. */ -const SystemStatusButton = new Lang.Class({ - Name: 'SystemStatusButton', +const SystemIndicator = new Lang.Class({ + Name: 'SystemIndicator', Extends: Button, - _init: function(iconName, nameText) { - this.parent(0.0, nameText); + _init: function() { + this.parent(0.0); this.actor.add_style_class_name('panel-status-button'); - this._box = new St.BoxLayout({ style_class: 'panel-status-button-box' }); - this.actor.add_actor(this._box); - - if (iconName) - this.setIcon(iconName); + this.indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box' }); + this.actor.add_actor(this.indicators); }, - get icons() { - return this._box.get_children(); - }, - - addIcon: function(gicon) { + addIndicator: function(gicon) { let icon = new St.Icon({ gicon: gicon, style_class: 'system-status-icon' }); - this._box.add_actor(icon); - - this.emit('icons-changed'); - + this.indicators.add_actor(icon); return icon; - }, - - setIcon: function(iconName) { - if (!this.mainIcon) - this.mainIcon = this.addIcon(null); - this.mainIcon.icon_name = iconName; - }, - - setGIcon: function(gicon) { - if (this.mainIcon) - this.mainIcon.gicon = gicon; - else - this.mainIcon = this.addIcon(gicon); } }); diff --git a/js/ui/status/bluetooth.js b/js/ui/status/bluetooth.js index f2db97625..29f8ad811 100644 --- a/js/ui/status/bluetooth.js +++ b/js/ui/status/bluetooth.js @@ -15,10 +15,12 @@ const PopupMenu = imports.ui.popupMenu; const Indicator = new Lang.Class({ Name: 'BTIndicator', - Extends: PanelMenu.SystemStatusButton, + Extends: PanelMenu.SystemIndicator, _init: function() { - this.parent('bluetooth-disabled-symbolic', _("Bluetooth")); + this.parent(); + + this._indicator = this.addIndicator(new Gio.ThemedIcon({ name: 'bluetooth-active-symbolic' })); // The Bluetooth menu only appears when Bluetooth is in use, // so just statically build it with a "Turn Off" menu item. @@ -47,8 +49,8 @@ const Indicator = new Lang.Class({ let nDevices = connectedDevices.length; let on = nDevices > 0; - this.mainIcon.visible = on; - this.actor.visible = on; + this._indicator.visible = on; + this._item.actor.visible = on; if (on) this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices").format(nDevices); diff --git a/js/ui/status/lockScreenMenu.js b/js/ui/status/lockScreenMenu.js index e9ee6fda7..a735ae82e 100644 --- a/js/ui/status/lockScreenMenu.js +++ b/js/ui/status/lockScreenMenu.js @@ -37,26 +37,26 @@ const FakeStatusIcon = new Lang.Class({ const Indicator = new Lang.Class({ Name: 'LockScreenMenuIndicator', - Extends: PanelMenu.SystemStatusButton, + Extends: PanelMenu.SystemIndicator, _init: function() { this.parent(null, _("Volume, network, battery")); - this._box.style_class = 'lock-screen-status-button-box'; + this.indicators.style_class = 'lock-screen-status-button-box'; this._volumeControl = VolumeMenu.getMixerControl(); this._volumeMenu = new VolumeMenu.VolumeMenu(this._volumeControl); this.menu.addMenuItem(this._volumeMenu); this._volume = new FakeStatusIcon(Main.panel.statusArea.volume); - this._box.add_child(this._volume.actor); + this.indicators.add_child(this._volume.actor); // Network may not exist if the user doesn't have NetworkManager if (Main.panel.statusArea.network) { this._network = new FakeStatusIcon(Main.panel.statusArea.network); - this._box.add_child(this._network.actor); + this.indicators.add_child(this._network.actor); } this._battery = new FakeStatusIcon(Main.panel.statusArea.battery); - this._box.add_child(this._battery.actor); + this.indicators.add_child(this._battery.actor); } }); diff --git a/js/ui/status/network.js b/js/ui/status/network.js index 751711823..9c03eeb7c 100644 --- a/js/ui/status/network.js +++ b/js/ui/status/network.js @@ -1152,12 +1152,13 @@ Signals.addSignalMethods(NMVPNSection.prototype); const NMApplet = new Lang.Class({ Name: 'NMApplet', - Extends: PanelMenu.SystemStatusButton, + Extends: PanelMenu.SystemIndicator, _init: function() { - this.parent('network-offline-symbolic', _('Network')); + this.parent(); - this._vpnIcon = this.addIcon(null); + this._primaryIndicator = this.addIndicator(null); + this._vpnIndicator = this.addIndicator(null); // Device types this._dtypes = { }; @@ -1579,29 +1580,27 @@ const NMApplet = new Lang.Class({ }, _syncNMState: function() { - this.mainIcon.visible = this._client.manager_running; - this.actor.visible = this.mainIcon.visible; - this._syncActiveConnections(); + + this.indicators.visible = this._client.manager_running; this._section.actor.visible = this._client.networking_enabled; }, _updateIcon: function() { - let hasApIcon = false; - let hasMobileIcon = false; + let mc = this._mainConnection; - if (!this._client.networking_enabled || !this._mainConnection) { - this.setIcon('network-offline-symbolic'); + if (!this._client.networking_enabled || !mc) { + this._primaryIndicator.icon_name = 'network-offline-symbolic'; } else { let dev = this._mainConnection._primaryDevice; if (!dev) { log('Active connection with no primary device?'); return; } - this.setIcon(dev.getIndicatorIcon()); + this._primaryIndicator.icon_name = dev.getIndicatorIcon(mc); } - this._vpnIcon.icon_name = this._vpnSection.getIndicatorIcon(); - this._vpnIcon.visible = (this._vpnIcon.icon_name != ''); + this._vpnIndicator.icon_name = this._vpnSection.getIndicatorIcon(); + this._vpnIndicator.visible = (this._vpnIndicator.icon_name != ''); } }); diff --git a/js/ui/status/power.js b/js/ui/status/power.js index 3e7681671..f38c0bb3d 100644 --- a/js/ui/status/power.js +++ b/js/ui/status/power.js @@ -25,10 +25,12 @@ const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface); const Indicator = new Lang.Class({ Name: 'PowerIndicator', - Extends: PanelMenu.SystemStatusButton, + Extends: PanelMenu.SystemIndicator, _init: function() { - this.parent('battery-missing-symbolic', _("Battery")); + this.parent(); + + this._indicator = this.addIndicator(null); this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH, Lang.bind(this, function(proxy, error) { @@ -104,16 +106,14 @@ const Indicator = new Lang.Class({ _syncIcon: function() { let icon = this._proxy.Icon; - let hasIcon = false; - if (icon) { let gicon = Gio.icon_new_for_string(icon); - this.setGIcon(gicon); + this._indicator.gicon = gicon; + this._indicator.show(); this._item.icon.gicon = gicon; - hasIcon = true; + } else { + this._indicator.hide(); } - this.mainIcon.visible = hasIcon; - this.actor.visible = hasIcon; }, _sync: function() { diff --git a/js/ui/status/system.js b/js/ui/status/system.js index 8e889dcc4..74ab786d9 100644 --- a/js/ui/status/system.js +++ b/js/ui/status/system.js @@ -42,10 +42,12 @@ const SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIf const Indicator = new Lang.Class({ Name: 'SystemIndicator', - Extends: PanelMenu.SystemStatusButton, + Extends: PanelMenu.SystemIndicator, _init: function() { - this.parent('system-shutdown-symbolic', _("System")); + this.parent(); + + this._indicator = this.addIndicator(new Gio.ThemedIcon({ name: 'system-shutdown-symbolic' })); this._screenSaverSettings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA }); this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA }); diff --git a/js/ui/status/volume.js b/js/ui/status/volume.js index 58c5ec67d..5a9fed964 100644 --- a/js/ui/status/volume.js +++ b/js/ui/status/volume.js @@ -296,22 +296,29 @@ const VolumeMenu = new Lang.Class({ const Indicator = new Lang.Class({ Name: 'VolumeIndicator', - Extends: PanelMenu.SystemStatusButton, + Extends: PanelMenu.SystemIndicator, _init: function() { - this.parent('audio-volume-muted-symbolic', _("Volume")); + this.parent(); + + this._primaryIndicator = this.addIndicator(null); this._control = getMixerControl(); this._volumeMenu = new VolumeMenu(this._control); this._volumeMenu.connect('icon-changed', Lang.bind(this, function(menu) { let icon = this._volumeMenu.getIcon(); - this.actor.visible = (icon != null); - this.setIcon(icon); + + if (icon != null) { + this.indicators.show(); + this._primaryIndicator.icon_name = icon; + } else { + this.indicators.hide(); + } })); this.menu.addMenuItem(this._volumeMenu); - this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); + this.indicators.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); }, _onScrollEvent: function(actor, event) {