From 80d1f68c77bb10673868ce8b149094a0da480ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Sat, 30 Jul 2022 16:52:39 +0200 Subject: [PATCH] status/power: Port to quick settings The power indicator should not be a regular quick toggle, but instead be part of a "system area" row at the top of the menu. But as in the end it is still a simple button, we can do the port to quick settings now, and move it later when the system row is implemented. Part-of: --- js/ui/panel.js | 7 +- js/ui/status/power.js | 189 ++++++++++++++++++++---------------------- 2 files changed, 93 insertions(+), 103 deletions(-) diff --git a/js/ui/panel.js b/js/ui/panel.js index 614f71606..0b0c50153 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -378,7 +378,6 @@ class AggregateMenu extends PanelMenu.Button { else this._network = null; - this._power = new imports.ui.status.power.Indicator(); this._powerProfiles = new imports.ui.status.powerProfiles.Indicator(); this._volume = new imports.ui.status.volume.Indicator(); this._brightness = new imports.ui.status.brightness.Indicator(); @@ -387,7 +386,6 @@ class AggregateMenu extends PanelMenu.Button { if (this._network) this._indicators.add_child(this._network); this._indicators.add_child(this._volume); - this._indicators.add_child(this._power); this._indicators.add_child(this._powerProfiles); this.menu.addMenuItem(this._volume.menu); @@ -396,12 +394,10 @@ class AggregateMenu extends PanelMenu.Button { if (this._network) this.menu.addMenuItem(this._network.menu); - this.menu.addMenuItem(this._power.menu); this.menu.addMenuItem(this._powerProfiles.menu); this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.menu.addMenuItem(this._system.menu); - menuLayout.addSizeChild(this._power.menu.actor); menuLayout.addSizeChild(this._powerProfiles.menu.actor); menuLayout.addSizeChild(this._system.menu.actor); } @@ -430,6 +426,7 @@ class QuickSettings extends PanelMenu.Button { this._nightLight = new imports.ui.status.nightLight.Indicator(); this._rfkill = new imports.ui.status.rfkill.Indicator(); this._unsafeMode = new UnsafeModeIndicator(); + this._power = new imports.ui.status.power.Indicator(); this._indicators.add_child(this._remoteAccess); this._indicators.add_child(this._thunderbolt); @@ -439,6 +436,7 @@ class QuickSettings extends PanelMenu.Button { this._indicators.add_child(this._bluetooth); this._indicators.add_child(this._rfkill); this._indicators.add_child(this._unsafeMode); + this._indicators.add_child(this._power); this._addItems(this._remoteAccess.quickSettingsItems); this._addItems(this._thunderbolt.quickSettingsItems); @@ -448,6 +446,7 @@ class QuickSettings extends PanelMenu.Button { this._addItems(this._nightLight.quickSettingsItems); this._addItems(this._rfkill.quickSettingsItems); this._addItems(this._unsafeMode.quickSettingsItems); + this._addItems(this._power.quickSettingsItems); } _addItems(items, colSpan = 1) { diff --git a/js/ui/status/power.js b/js/ui/status/power.js index 5d23006f5..de363d0ce 100644 --- a/js/ui/status/power.js +++ b/js/ui/status/power.js @@ -1,13 +1,12 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- /* exported Indicator */ -const { Clutter, Gio, GObject, St, UPowerGlib: UPower } = imports.gi; +const {Atk, Clutter, Gio, GObject, Shell, St, UPowerGlib: UPower} = imports.gi; const Main = imports.ui.main; -const PanelMenu = imports.ui.panelMenu; -const PopupMenu = imports.ui.popupMenu; +const {QuickToggle, SystemIndicator} = imports.ui.quickSettings; -const { loadInterfaceXML } = imports.misc.fileUtils; +const {loadInterfaceXML} = imports.misc.fileUtils; const BUS_NAME = 'org.freedesktop.UPower'; const OBJECT_PATH = '/org/freedesktop/UPower/devices/DisplayDevice'; @@ -15,106 +14,54 @@ const OBJECT_PATH = '/org/freedesktop/UPower/devices/DisplayDevice'; const DisplayDeviceInterface = loadInterfaceXML('org.freedesktop.UPower.Device'); const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface); -const SHOW_BATTERY_PERCENTAGE = 'show-battery-percentage'; +const SHOW_BATTERY_PERCENTAGE = 'show-battery-percentage'; -var Indicator = GObject.registerClass( -class Indicator extends PanelMenu.SystemIndicator { +const PowerToggle = GObject.registerClass({ + Properties: { + 'fallback-icon-name': GObject.ParamSpec.string('fallback-icon-name', '', '', + GObject.ParamFlags.READWRITE, + ''), + }, +}, class PowerToggle extends QuickToggle { _init() { - super._init(); - - this._desktopSettings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.interface', + super._init({ + accessible_role: Atk.Role.PUSH_BUTTON, }); - this._desktopSettings.connect( - `changed::${SHOW_BATTERY_PERCENTAGE}`, this._sync.bind(this)); - - this._indicator = this._addIndicator(); - this._percentageLabel = new St.Label({ - y_expand: true, - y_align: Clutter.ActorAlign.CENTER, - }); - this.add_child(this._percentageLabel); - this.add_style_class_name('power-status'); this._proxy = new PowerManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH, (proxy, error) => { - if (error) { - log(error.message); - } else { - this._proxy.connect('g-properties-changed', - this._sync.bind(this)); - } + if (error) + console.error(error.message); + else + this._proxy.connect('g-properties-changed', () => this._sync()); this._sync(); }); - this._item = new PopupMenu.PopupSubMenuMenuItem('', true); - this._item.menu.addSettingsAction(_('Power Settings'), - 'gnome-power-panel.desktop'); - this.menu.addMenuItem(this._item); + this.bind_property('fallback-icon-name', + this._icon, 'fallback-icon-name', + GObject.BindingFlags.SYNC_CREATE); - Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); + this.connect('clicked', () => { + const app = Shell.AppSystem.get_default().lookup_app('gnome-power-panel.desktop'); + Main.overview.hide(); + Main.panel.closeQuickSettings(); + app.activate(); + }); + + Main.sessionMode.connect('updated', () => this._sessionUpdated()); this._sessionUpdated(); + this._sync(); } _sessionUpdated() { - let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter; - this.menu.setSensitive(sensitive); - } - - _getStatus() { - let seconds = 0; - - if (this._proxy.State === UPower.DeviceState.FULLY_CHARGED) - return _('Fully Charged'); - else if (this._proxy.State === UPower.DeviceState.CHARGING) - seconds = this._proxy.TimeToFull; - else if (this._proxy.State === UPower.DeviceState.DISCHARGING) - seconds = this._proxy.TimeToEmpty; - else if (this._proxy.State === UPower.DeviceState.PENDING_CHARGE) - return _('Not Charging'); - // state is PENDING_DISCHARGE - else - return _('Estimating…'); - - let time = Math.round(seconds / 60); - if (time === 0) { - // 0 is reported when UPower does not have enough data - // to estimate battery life - return _('Estimating…'); - } - - let minutes = time % 60; - let hours = Math.floor(time / 60); - - if (this._proxy.State === UPower.DeviceState.DISCHARGING) { - // Translators: this is : Remaining () - return _('%d\u2236%02d Remaining (%d\u2009%%)').format( - hours, minutes, this._proxy.Percentage); - } - - if (this._proxy.State === UPower.DeviceState.CHARGING) { - // Translators: this is : Until Full () - return _('%d\u2236%02d Until Full (%d\u2009%%)').format( - hours, minutes, this._proxy.Percentage); - } - - return null; + this.reactive = Main.sessionMode.allowSettings; } _sync() { // Do we have batteries or a UPS? - let visible = this._proxy.IsPresent; - if (visible) { - this._item.show(); - this._percentageLabel.visible = - this._desktopSettings.get_boolean(SHOW_BATTERY_PERCENTAGE); - } else { - // If there's no battery, then we use the power icon. - this._item.hide(); - this._indicator.icon_name = 'system-shutdown-symbolic'; - this._percentageLabel.hide(); + this.visible = this._proxy.IsPresent; + if (!this.visible) return; - } // The icons let chargingState = this._proxy.State === UPower.DeviceState.CHARGING @@ -129,23 +76,67 @@ class Indicator extends PanelMenu.SystemIndicator { // Make sure we fall back to fallback-icon-name and not GThemedIcon's // default fallbacks - let gicon = new Gio.ThemedIcon({ + const gicon = new Gio.ThemedIcon({ name: icon, use_default_fallbacks: false, }); - this._indicator.gicon = gicon; - this._item.icon.gicon = gicon; - - let fallbackIcon = this._proxy.IconName; - this._indicator.fallback_icon_name = fallbackIcon; - this._item.icon.fallback_icon_name = fallbackIcon; - - // The icon label - const label = _('%d\u2009%%').format(this._proxy.Percentage); - this._percentageLabel.text = label; - - // The status label - this._item.label.text = this._getStatus(); + this.set({ + label: _('%d\u2009%%').format(this._proxy.Percentage), + fallback_icon_name: this._proxy.IconName, + gicon, + }); + } +}); + +var Indicator = GObject.registerClass( +class Indicator extends SystemIndicator { + _init() { + super._init(); + + this._desktopSettings = new Gio.Settings({ + schema_id: 'org.gnome.desktop.interface', + }); + this._desktopSettings.connect( + `changed::${SHOW_BATTERY_PERCENTAGE}`, () => this._sync()); + + this._indicator = this._addIndicator(); + this._percentageLabel = new St.Label({ + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this.add_child(this._percentageLabel); + this.add_style_class_name('power-status'); + + this._powerToggle = new PowerToggle(); + + this._powerToggle.bind_property('label', + this._percentageLabel, 'text', + GObject.BindingFlags.SYNC_CREATE); + + this._powerToggle.connectObject( + 'notify::visible', () => this._sync(), + 'notify::gicon', () => this._sync(), + 'notify::fallback-icon-name', () => this._sync(), + this); + + this.quickSettingsItems.push(this._powerToggle); + + this._sync(); + } + + _sync() { + if (this._powerToggle.visible) { + this._indicator.set({ + gicon: this._powerToggle.gicon, + fallback_icon_name: this._powerToggle.fallback_icon_name, + }); + this._percentageLabel.visible = + this._desktopSettings.get_boolean(SHOW_BATTERY_PERCENTAGE); + } else { + // If there's no battery, then we use the power icon. + this._indicator.icon_name = 'system-shutdown-symbolic'; + this._percentageLabel.hide(); + } } });