diff --git a/data/dbus-interfaces/net.hadess.PowerProfiles.xml b/data/dbus-interfaces/net.hadess.PowerProfiles.xml new file mode 100644 index 000000000..fce04a86d --- /dev/null +++ b/data/dbus-interfaces/net.hadess.PowerProfiles.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/data/gnome-shell-dbus-interfaces.gresource.xml b/data/gnome-shell-dbus-interfaces.gresource.xml index e7972f6cb..6682c462d 100644 --- a/data/gnome-shell-dbus-interfaces.gresource.xml +++ b/data/gnome-shell-dbus-interfaces.gresource.xml @@ -1,6 +1,7 @@ + net.hadess.PowerProfiles.xml net.hadess.SensorProxy.xml net.reactivated.Fprint.Device.xml net.reactivated.Fprint.Manager.xml diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml index e65e0e9cf..6d7940f06 100644 --- a/js/js-resources.gresource.xml +++ b/js/js-resources.gresource.xml @@ -133,6 +133,7 @@ ui/status/nightLight.js ui/status/network.js ui/status/power.js + ui/status/powerProfiles.js ui/status/rfkill.js ui/status/volume.js ui/status/bluetooth.js diff --git a/js/ui/panel.js b/js/ui/panel.js index 1474886ef..c039112d7 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -684,6 +684,7 @@ class AggregateMenu extends PanelMenu.Button { this._remoteAccess = new imports.ui.status.remoteAccess.RemoteAccessApplet(); this._power = new imports.ui.status.power.Indicator(); + this._powerProfiles = new imports.ui.status.powerProfiles.Indicator(); this._rfkill = new imports.ui.status.rfkill.Indicator(); this._volume = new imports.ui.status.volume.Indicator(); this._brightness = new imports.ui.status.brightness.Indicator(); @@ -703,6 +704,7 @@ class AggregateMenu extends PanelMenu.Button { this._indicators.add_child(this._rfkill); this._indicators.add_child(this._volume); this._indicators.add_child(this._power); + this._indicators.add_child(this._powerProfiles); this.menu.addMenuItem(this._volume.menu); this.menu.addMenuItem(this._brightness.menu); @@ -717,6 +719,7 @@ class AggregateMenu extends PanelMenu.Button { this.menu.addMenuItem(this._location.menu); this.menu.addMenuItem(this._rfkill.menu); this.menu.addMenuItem(this._power.menu); + this.menu.addMenuItem(this._powerProfiles.menu); this.menu.addMenuItem(this._nightLight.menu); this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.menu.addMenuItem(this._system.menu); @@ -724,6 +727,7 @@ class AggregateMenu extends PanelMenu.Button { menuLayout.addSizeChild(this._location.menu.actor); menuLayout.addSizeChild(this._rfkill.menu.actor); menuLayout.addSizeChild(this._power.menu.actor); + menuLayout.addSizeChild(this._powerProfiles.menu.actor); menuLayout.addSizeChild(this._system.menu.actor); } }); diff --git a/js/ui/status/powerProfiles.js b/js/ui/status/powerProfiles.js new file mode 100644 index 000000000..f6bc5835b --- /dev/null +++ b/js/ui/status/powerProfiles.js @@ -0,0 +1,111 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- +/* exported Indicator */ + +const { Gio, GObject } = imports.gi; + +const Main = imports.ui.main; +const PanelMenu = imports.ui.panelMenu; +const PopupMenu = imports.ui.popupMenu; + +const { loadInterfaceXML } = imports.misc.fileUtils; + +const BUS_NAME = 'net.hadess.PowerProfiles'; +const OBJECT_PATH = '/net/hadess/PowerProfiles'; + +const PowerProfilesIface = loadInterfaceXML('net.hadess.PowerProfiles'); +const PowerProfilesProxy = Gio.DBusProxy.makeProxyWrapper(PowerProfilesIface); + +const PROFILE_LABELS = { + 'performance': _('Performance Mode'), + 'balanced': _('Balanced Power'), + 'power-saver': _('Power Saver'), +}; +const PROFILE_ICONS = { + 'performance': 'power-profile-performance-symbolic', + 'balanced': 'power-profile-balanced-symbolic', + 'power-saver': 'power-profile-power-saver-symbolic', +}; + +var Indicator = GObject.registerClass( +class Indicator extends PanelMenu.SystemIndicator { + _init() { + super._init(); + + this._profileItems = new Map(); + this._updateProfiles = true; + + this._proxy = new PowerProfilesProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH, + (proxy, error) => { + if (error) { + log(error.message); + } else { + this._proxy.connect('g-properties-changed', + (p, properties) => { + const propertyNames = properties.deep_unpack(); + this._updateProfiles = 'Profiles' in propertyNames; + this._sync(); + }); + } + this._sync(); + }); + + this._item = new PopupMenu.PopupSubMenuMenuItem('', true); + + this._profileSection = new PopupMenu.PopupMenuSection(); + this._item.menu.addMenuItem(this._profileSection); + this._item.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this._item.menu.addSettingsAction(_('Power Settings'), + 'gnome-power-panel.desktop'); + this.menu.addMenuItem(this._item); + + Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); + this._sessionUpdated(); + this._sync(); + } + + _sessionUpdated() { + const sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter; + this.menu.setSensitive(sensitive); + } + + _sync() { + this._item.visible = this._proxy.g_name_owner !== null; + + if (!this._item.visible) + return; + + if (this._updateProfiles) { + this._profileSection.removeAll(); + this._profileItems.clear(); + + const profiles = this._proxy.Profiles + .map(p => p.Profile.unpack()) + .reverse(); + for (const profile of profiles) { + const label = PROFILE_LABELS[profile]; + if (!label) + continue; + + const item = new PopupMenu.PopupMenuItem(label); + item.connect('activate', + () => (this._proxy.ActiveProfile = profile)); + this._profileItems.set(profile, item); + this._profileSection.addMenuItem(item); + } + this._updateProfiles = false; + } + + for (const [profile, item] of this._profileItems) { + item.setOrnament(profile === this._proxy.ActiveProfile + ? PopupMenu.Ornament.DOT + : PopupMenu.Ornament.NONE); + } + + const perfItem = this._profileItems.get('performance'); + if (perfItem) + perfItem.sensitive = this._proxy.PerformanceInhibited === ''; + + this._item.label.text = PROFILE_LABELS[this._proxy.ActiveProfile]; + this._item.icon.icon_name = PROFILE_ICONS[this._proxy.ActiveProfile]; + } +}); diff --git a/po/POTFILES.in b/po/POTFILES.in index f96d79666..8e763c8f2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -62,6 +62,7 @@ js/ui/status/location.js js/ui/status/network.js js/ui/status/nightLight.js js/ui/status/power.js +js/ui/status/powerProfiles.js js/ui/status/remoteAccess.js js/ui/status/rfkill.js js/ui/status/system.js