You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
333 lines
13 KiB
333 lines
13 KiB
From 2103c5fcf994bb6aebd978553b338436e85fa7ed Mon Sep 17 00:00:00 2001 |
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org> |
|
Date: Wed, 7 Jul 2021 22:05:25 +0200 |
|
Subject: [PATCH 1/2] status/powerProfiles: Add power mode selection |
|
|
|
Settings' power panel gained support for switchable power profiles |
|
in GNOME 40. It's useful to have that functionality more readily |
|
available, so expose it in the system status menu as well. |
|
|
|
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3944 |
|
|
|
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1907> |
|
--- |
|
.../net.hadess.PowerProfiles.xml | 76 ++++++++++++ |
|
.../gnome-shell-dbus-interfaces.gresource.xml | 1 + |
|
js/js-resources.gresource.xml | 1 + |
|
js/ui/panel.js | 4 + |
|
js/ui/status/powerProfiles.js | 111 ++++++++++++++++++ |
|
po/POTFILES.in | 1 + |
|
6 files changed, 194 insertions(+) |
|
create mode 100644 data/dbus-interfaces/net.hadess.PowerProfiles.xml |
|
create mode 100644 js/ui/status/powerProfiles.js |
|
|
|
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 @@ |
|
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" |
|
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> |
|
+ |
|
+<node> |
|
+ |
|
+ <!-- |
|
+ net.hadess.PowerProfiles: |
|
+ @short_description: Power Profiles daemon |
|
+ |
|
+ The power-profiles-daemon API is meant to be used by parts of the OS or |
|
+ desktop environment to switch system power profiles based on user choice, |
|
+ or user intent. |
|
+ |
|
+ OS components would typically use the "Profiles" property to construct |
|
+ their UI (2 or 3 profiles available), and monitor the "ActiveProfile" |
|
+ and the "PerformanceInhibited" properties to update that UI. The UI |
|
+ would try to set the "ActiveProfile" property if the user selected |
|
+ a different one. |
|
+ |
|
+ Note that the reason why the project exists and how it is different from |
|
+ existing projects is explained <ulink href=" https://gitlab.freedesktop.org/hadess/power-profiles-daemon/-/blob/master/README.md"> |
|
+ in the project's README file</ulink>. |
|
+ |
|
+ The object path will be "/net/hadess/PowerProfiles". |
|
+ --> |
|
+ <interface name="net.hadess.PowerProfiles"> |
|
+ <!-- |
|
+ ActiveProfile: |
|
+ |
|
+ The type of the currently active profile. It might change automatically |
|
+ if the "performance" profile was selected but it got inhibited, in which |
|
+ case the "PerformanceInhibited" property will reflect the reason. |
|
+ --> |
|
+ <property name="ActiveProfile" type="s" access="readwrite"/> |
|
+ |
|
+ <!-- |
|
+ PerformanceInhibited: |
|
+ |
|
+ This will be set if the performance power profile is unavailable, with |
|
+ the value being used to identify the reason for unavailability. As new |
|
+ reasons can be added, it is recommended that front-ends show a generic |
|
+ reason if they do not recognise the value. Possible values are: |
|
+ - "lap-detected" (the computer is sitting on the user's lap) |
|
+ - "high-operating-temperature" (the computer is close to overheating) |
|
+ - "" (the empty string, if not inhibited) |
|
+ --> |
|
+ <property name="PerformanceInhibited" type="s" access="read"/> |
|
+ |
|
+ <!-- |
|
+ Profiles: |
|
+ |
|
+ An array of key-pair values representing each profile. The key named |
|
+ "Driver" (s) identifies the power-profiles-daemon backend code used to |
|
+ implement the profile. |
|
+ |
|
+ The key named "Profile" (s) will be one of: |
|
+ - "power-saver" (battery saving profile) |
|
+ - "balanced" (the default profile) |
|
+ - "performance" (a profile that does not care about noise or battery consumption) |
|
+ |
|
+ Only one of each type of profile will be listed, with the daemon choosing the |
|
+ more appropriate "driver" for each profile type. |
|
+ --> |
|
+ <property name="Profiles" type="aa{sv}" access="read"/> |
|
+ |
|
+ <!-- |
|
+ Actions: |
|
+ |
|
+ An array of strings listing each one of the "actions" implemented in |
|
+ the running daemon. This is used by API users to figure out whether |
|
+ particular functionality is available in a version of the daemon. |
|
+ --> |
|
+ <property name="Actions" type="as" access="read"/> |
|
+ |
|
+ </interface> |
|
+</node> |
|
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 @@ |
|
<?xml version="1.0" encoding="UTF-8"?> |
|
<gresources> |
|
<gresource prefix="/org/gnome/shell/dbus-interfaces"> |
|
+ <file preprocess="xml-stripblanks">net.hadess.PowerProfiles.xml</file> |
|
<file preprocess="xml-stripblanks">net.hadess.SensorProxy.xml</file> |
|
<file preprocess="xml-stripblanks">net.reactivated.Fprint.Device.xml</file> |
|
<file preprocess="xml-stripblanks">net.reactivated.Fprint.Manager.xml</file> |
|
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml |
|
index b2c603a55..7a94e2ff1 100644 |
|
--- a/js/js-resources.gresource.xml |
|
+++ b/js/js-resources.gresource.xml |
|
@@ -134,6 +134,7 @@ |
|
<file>ui/status/nightLight.js</file> |
|
<file>ui/status/network.js</file> |
|
<file>ui/status/power.js</file> |
|
+ <file>ui/status/powerProfiles.js</file> |
|
<file>ui/status/rfkill.js</file> |
|
<file>ui/status/volume.js</file> |
|
<file>ui/status/bluetooth.js</file> |
|
diff --git a/js/ui/panel.js b/js/ui/panel.js |
|
index ad11f4ba2..84668e96e 100644 |
|
--- a/js/ui/panel.js |
|
+++ b/js/ui/panel.js |
|
@@ -693,6 +693,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(); |
|
@@ -712,6 +713,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); |
|
@@ -726,6 +728,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); |
|
@@ -733,6 +736,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 cb279c1ee..727cb01a8 100644 |
|
--- a/po/POTFILES.in |
|
+++ b/po/POTFILES.in |
|
@@ -61,6 +61,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 |
|
-- |
|
2.31.1 |
|
|
|
|
|
From 0f8a2e2c6c3119492670efce5aff1224f2c3c47f Mon Sep 17 00:00:00 2001 |
|
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org> |
|
Date: Fri, 6 Aug 2021 21:04:24 +0200 |
|
Subject: [PATCH 2/2] powerProfiles: Tweak profile names |
|
|
|
After some more discussion, we settled on slightly different |
|
profile names. |
|
|
|
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4530 |
|
|
|
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1939> |
|
--- |
|
js/ui/status/powerProfiles.js | 6 +++--- |
|
1 file changed, 3 insertions(+), 3 deletions(-) |
|
|
|
diff --git a/js/ui/status/powerProfiles.js b/js/ui/status/powerProfiles.js |
|
index f6bc5835b..61205bbc6 100644 |
|
--- a/js/ui/status/powerProfiles.js |
|
+++ b/js/ui/status/powerProfiles.js |
|
@@ -16,9 +16,9 @@ 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'), |
|
+ 'performance': C_('Power profile', 'Performance'), |
|
+ 'balanced': C_('Power profile', 'Balanced'), |
|
+ 'power-saver': C_('Power profile', 'Power Saver'), |
|
}; |
|
const PROFILE_ICONS = { |
|
'performance': 'power-profile-performance-symbolic', |
|
-- |
|
2.31.1 |
|
|
|
|