Blame SOURCES/0001-power-Enable-power-saver-profile-when-low-on-battery.patch

0de61d
From 8dd4c164f6ce166a5767588bd6fb8e4c3e8e1a09 Mon Sep 17 00:00:00 2001
0de61d
From: Bastien Nocera <hadess@hadess.net>
0de61d
Date: Fri, 16 Jul 2021 13:40:10 +0200
0de61d
Subject: [PATCH 1/4] power: Enable power-saver profile when low on battery
0de61d
0de61d
When low on battery, and if the feature is enabled, hold the power
0de61d
profile to "power-saver" until the battery is sufficiently recharged.
0de61d
---
0de61d
 ...ttings-daemon.plugins.power.gschema.xml.in |   5 +
0de61d
 plugins/power/gsd-power-manager.c             | 128 ++++++++++++++++++
0de61d
 plugins/power/test.py                         |  32 +++++
0de61d
 3 files changed, 165 insertions(+)
0de61d
0de61d
diff --git a/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in b/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in
0de61d
index 93c704e9..04b287bd 100644
0de61d
--- a/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in
0de61d
+++ b/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in
0de61d
@@ -41,5 +41,10 @@
0de61d
       <summary>Power button action</summary>
0de61d
       <description>The action to take when the system power button is pressed. This action is hard-coded (and the setting ignored) on virtual machines (power off) and tablets (suspend).</description>
0de61d
     </key>
0de61d
+    <key name="power-saver-profile-on-low-battery" type="b">
0de61d
+      <default>true</default>
0de61d
+      <summary>Enable power-saver profile when battery is low</summary>
0de61d
+      <description>Automatically enable the "power-saver" profile using power-profiles-daemon if the battery is low.</description>
0de61d
+    </key>
0de61d
   </schema>
0de61d
 </schemalist>
0de61d
diff --git a/plugins/power/gsd-power-manager.c b/plugins/power/gsd-power-manager.c
0de61d
index 95cec9c3..1f125a6f 100644
0de61d
--- a/plugins/power/gsd-power-manager.c
0de61d
+++ b/plugins/power/gsd-power-manager.c
0de61d
@@ -59,6 +59,10 @@
0de61d
 #define UPOWER_DBUS_INTERFACE                   "org.freedesktop.UPower"
0de61d
 #define UPOWER_DBUS_INTERFACE_KBDBACKLIGHT      "org.freedesktop.UPower.KbdBacklight"
0de61d
 
0de61d
+#define PPD_DBUS_NAME                           "net.hadess.PowerProfiles"
0de61d
+#define PPD_DBUS_PATH                           "/net/hadess/PowerProfiles"
0de61d
+#define PPD_DBUS_INTERFACE                      "net.hadess.PowerProfiles"
0de61d
+
0de61d
 #define GSD_POWER_SETTINGS_SCHEMA               "org.gnome.settings-daemon.plugins.power"
0de61d
 
0de61d
 #define GSD_POWER_DBUS_NAME                     GSD_DBUS_NAME ".Power"
0de61d
@@ -185,6 +189,10 @@ struct _GsdPowerManager
0de61d
         gdouble                  ambient_last_absolute;
0de61d
         gint64                   ambient_last_time;
0de61d
 
0de61d
+        /* Power Profiles */
0de61d
+        GDBusProxy              *power_profiles_proxy;
0de61d
+        guint32                  power_saver_cookie;
0de61d
+
0de61d
         /* Sound */
0de61d
         guint32                  critical_alert_timeout_id;
0de61d
 
0de61d
@@ -1927,6 +1935,67 @@ idle_configure (GsdPowerManager *manager)
0de61d
         }
0de61d
 }
0de61d
 
0de61d
+static void
0de61d
+hold_profile_cb (GObject      *source_object,
0de61d
+                 GAsyncResult *res,
0de61d
+                 gpointer      user_data)
0de61d
+{
0de61d
+        GsdPowerManager *manager = user_data;
0de61d
+        g_autoptr(GError) error = NULL;
0de61d
+        g_autoptr(GVariant) result = NULL;
0de61d
+
0de61d
+        result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
0de61d
+                                           res,
0de61d
+                                           &error);
0de61d
+        if (result == NULL) {
0de61d
+                g_warning ("Couldn't hold power-saver profile: %s", error->message);
0de61d
+                return;
0de61d
+        }
0de61d
+
0de61d
+        if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(u)"))) {
0de61d
+                g_variant_get (result, "(u)", &manager->power_saver_cookie);
0de61d
+                g_debug ("Holding power-saver profile with cookie %u", manager->power_saver_cookie);
0de61d
+        } else {
0de61d
+                g_warning ("Calling HoldProfile() did not return a uint32");
0de61d
+        }
0de61d
+}
0de61d
+
0de61d
+static void
0de61d
+enable_power_saver (GsdPowerManager *manager)
0de61d
+{
0de61d
+        if (!manager->power_profiles_proxy)
0de61d
+                return;
0de61d
+        if (!g_settings_get_boolean (manager->settings, "power-saver-profile-on-low-battery"))
0de61d
+                return;
0de61d
+
0de61d
+        g_debug ("Starting hold of power-saver profile");
0de61d
+
0de61d
+        g_dbus_proxy_call (manager->power_profiles_proxy,
0de61d
+                           "HoldProfile",
0de61d
+                           g_variant_new("(sss)",
0de61d
+                                         "power-saver",
0de61d
+                                         "Power saver profile when low on battery",
0de61d
+                                         GSD_POWER_DBUS_NAME),
0de61d
+                           G_DBUS_CALL_FLAGS_NONE,
0de61d
+                           -1, manager->cancellable, hold_profile_cb, manager);
0de61d
+}
0de61d
+
0de61d
+static void
0de61d
+disable_power_saver (GsdPowerManager *manager)
0de61d
+{
0de61d
+        if (!manager->power_profiles_proxy || manager->power_saver_cookie == 0)
0de61d
+                return;
0de61d
+
0de61d
+        g_debug ("Releasing power-saver profile");
0de61d
+
0de61d
+        g_dbus_proxy_call (manager->power_profiles_proxy,
0de61d
+                           "ReleaseProfile",
0de61d
+                           g_variant_new ("(u)", manager->power_saver_cookie),
0de61d
+                           G_DBUS_CALL_FLAGS_NONE,
0de61d
+                           -1, NULL, dbus_call_log_error, "ReleaseProfile failed");
0de61d
+        manager->power_saver_cookie = 0;
0de61d
+}
0de61d
+
0de61d
 static void
0de61d
 main_battery_or_ups_low_changed (GsdPowerManager *manager,
0de61d
                                  gboolean         is_low)
0de61d
@@ -1935,6 +2004,10 @@ main_battery_or_ups_low_changed (GsdPowerManager *manager,
0de61d
                 return;
0de61d
         manager->battery_is_low = is_low;
0de61d
         idle_configure (manager);
0de61d
+        if (is_low)
0de61d
+                enable_power_saver (manager);
0de61d
+        else
0de61d
+                disable_power_saver (manager);
0de61d
 }
0de61d
 
0de61d
 static gboolean
0de61d
@@ -2078,6 +2151,39 @@ screensaver_signal_cb (GDBusProxy *proxy,
0de61d
                 handle_wake_up_screen (GSD_POWER_MANAGER (user_data));
0de61d
 }
0de61d
 
0de61d
+static void
0de61d
+power_profiles_proxy_signal_cb (GDBusProxy  *proxy,
0de61d
+                               const gchar *sender_name,
0de61d
+                               const gchar *signal_name,
0de61d
+                               GVariant    *parameters,
0de61d
+                               gpointer     user_data)
0de61d
+{
0de61d
+        GsdPowerManager *manager = GSD_POWER_MANAGER (user_data);
0de61d
+
0de61d
+        if (g_strcmp0 (signal_name, "ProfileReleased") != 0)
0de61d
+                return;
0de61d
+        manager->power_saver_cookie = 0;
0de61d
+}
0de61d
+
0de61d
+static void
0de61d
+power_profiles_proxy_ready_cb (GObject             *source_object,
0de61d
+                              GAsyncResult        *res,
0de61d
+                              gpointer             user_data)
0de61d
+{
0de61d
+        g_autoptr(GError) error = NULL;
0de61d
+        GsdPowerManager *manager = GSD_POWER_MANAGER (user_data);
0de61d
+
0de61d
+        manager->power_profiles_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
0de61d
+        if (manager->power_profiles_proxy == NULL) {
0de61d
+                g_debug ("Could not connect to power-profiles-daemon: %s", error->message);
0de61d
+                return;
0de61d
+        }
0de61d
+
0de61d
+        g_signal_connect (manager->power_profiles_proxy, "g-signal",
0de61d
+                          G_CALLBACK (power_profiles_proxy_signal_cb),
0de61d
+                          manager);
0de61d
+}
0de61d
+
0de61d
 static void
0de61d
 power_keyboard_proxy_ready_cb (GObject             *source_object,
0de61d
                                GAsyncResult        *res,
0de61d
@@ -2289,6 +2395,14 @@ engine_settings_key_changed_cb (GSettings *settings,
0de61d
                 idle_configure (manager);
0de61d
                 return;
0de61d
         }
0de61d
+        if (g_str_equal (key, "power-saver-profile-on-low-battery")) {
0de61d
+                if (manager->battery_is_low &&
0de61d
+                    g_settings_get_boolean (settings, key))
0de61d
+                        enable_power_saver (manager);
0de61d
+                else
0de61d
+                        disable_power_saver (manager);
0de61d
+                return;
0de61d
+        }
0de61d
 }
0de61d
 
0de61d
 static void
0de61d
@@ -2599,6 +2713,17 @@ on_rr_screen_acquired (GObject      *object,
0de61d
         g_signal_connect (manager->up_client, "notify::on-battery",
0de61d
                           G_CALLBACK (up_client_on_battery_cb), manager);
0de61d
 
0de61d
+        /* connect to power-profiles-daemon */
0de61d
+        g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
0de61d
+                                  G_DBUS_PROXY_FLAGS_NONE,
0de61d
+                                  NULL,
0de61d
+                                  PPD_DBUS_NAME,
0de61d
+                                  PPD_DBUS_PATH,
0de61d
+                                  PPD_DBUS_INTERFACE,
0de61d
+                                  manager->cancellable,
0de61d
+                                  power_profiles_proxy_ready_cb,
0de61d
+                                  manager);
0de61d
+
0de61d
         /* connect to UPower for keyboard backlight control */
0de61d
         manager->kbd_brightness_now = -1;
0de61d
         g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
0de61d
@@ -2862,6 +2987,9 @@ gsd_power_manager_stop (GsdPowerManager *manager)
0de61d
 
0de61d
         g_clear_object (&manager->screensaver_proxy);
0de61d
 
0de61d
+        disable_power_saver (manager);
0de61d
+        g_clear_object (&manager->power_profiles_proxy);
0de61d
+
0de61d
         play_loop_stop (&manager->critical_alert_timeout_id);
0de61d
 
0de61d
         g_clear_object (&manager->idle_monitor);
0de61d
diff --git a/plugins/power/test.py b/plugins/power/test.py
0de61d
index bb5861a4..f554400e 100755
0de61d
--- a/plugins/power/test.py
0de61d
+++ b/plugins/power/test.py
0de61d
@@ -76,6 +76,13 @@ class PowerPluginBase(gsdtestcase.GSDTestCase):
0de61d
             'gnome_screensaver', stdout=subprocess.PIPE)
0de61d
         gsdtestcase.set_nonblock(self.screensaver.stdout)
0de61d
 
0de61d
+        # start mock power-profiles-daemon
0de61d
+        try:
0de61d
+            (self.ppd, self.obj_ppd) = self.spawn_server_template('power_profiles_daemon')
0de61d
+            self.addCleanup(self.stop_process, self.ppd)
0de61d
+        except ModuleNotFoundError:
0de61d
+            self.ppd = None
0de61d
+
0de61d
         self.session_log = OutputChecker()
0de61d
         self.session = subprocess.Popen(['gnome-session', '-f',
0de61d
                                          '-a', os.path.join(self.workdir, 'autostart'),
0de61d
@@ -1302,5 +1309,30 @@ class PowerPluginTest8(PowerPluginBase):
0de61d
 
0de61d
         self.assertEqual(exc.exception.get_dbus_message(), 'No usable backlight could be found!')
0de61d
 
0de61d
+    def test_power_saver_on_low_battery(self):
0de61d
+        '''Check that the power-saver profile gets held when low on battery'''
0de61d
+
0de61d
+        if not self.ppd:
0de61d
+            self.skipTest("power-profiles-daemon dbusmock support is not available")
0de61d
+
0de61d
+        obj_props = dbus.Interface(self.obj_ppd, dbus.PROPERTIES_IFACE)
0de61d
+
0de61d
+        self.set_composite_battery_discharging()
0de61d
+        time.sleep(0.5)
0de61d
+        holds = obj_props.Get('net.hadess.PowerProfiles', 'ActiveProfileHolds')
0de61d
+        self.assertEqual(len(holds), 0)
0de61d
+
0de61d
+        self.set_composite_battery_critical()
0de61d
+        time.sleep(0.5)
0de61d
+        holds = obj_props.Get('net.hadess.PowerProfiles', 'ActiveProfileHolds')
0de61d
+        self.assertEqual(len(holds), 1)
0de61d
+        self.assertEqual(holds[0]['Profile'], 'power-saver')
0de61d
+        self.assertEqual(holds[0]['ApplicationId'], 'org.gnome.SettingsDaemon.Power')
0de61d
+
0de61d
+        self.set_composite_battery_discharging()
0de61d
+        time.sleep(0.5)
0de61d
+        holds = obj_props.Get('net.hadess.PowerProfiles', 'ActiveProfileHolds')
0de61d
+        self.assertEqual(len(holds), 0)
0de61d
+
0de61d
 # avoid writing to stderr
0de61d
 unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
0de61d
-- 
0de61d
2.31.1
0de61d
0de61d
0de61d
From 74ed476d1a37a43eeba8c8bee8f5be5d499b0805 Mon Sep 17 00:00:00 2001
0de61d
From: Bastien Nocera <hadess@hadess.net>
0de61d
Date: Wed, 28 Jul 2021 16:40:24 +0200
0de61d
Subject: [PATCH 2/4] power: Dim screen faster if power saver mode is on
0de61d
0de61d
As done on other platforms, aggressively dim the screen after a
0de61d
short period when the user has selected to enter power saver mode.
0de61d
0de61d
The same aggressive screen dim will be used if the battery is low and
0de61d
power-profiles-daemon is not available. If it is available, then it
0de61d
fixes a screen dim happening when the battery was low which might
0de61d
have been unwanted.
0de61d
0de61d
See https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/232
0de61d
0de61d
Prior art:
0de61d
https://support.apple.com/en-us/HT205234
0de61d
---
0de61d
 plugins/power/gsd-power-manager.c | 46 +++++++++++++++++++++++++++++--
0de61d
 1 file changed, 44 insertions(+), 2 deletions(-)
0de61d
0de61d
diff --git a/plugins/power/gsd-power-manager.c b/plugins/power/gsd-power-manager.c
0de61d
index 1f125a6f..cfef9718 100644
0de61d
--- a/plugins/power/gsd-power-manager.c
0de61d
+++ b/plugins/power/gsd-power-manager.c
0de61d
@@ -192,6 +192,7 @@ struct _GsdPowerManager
0de61d
         /* Power Profiles */
0de61d
         GDBusProxy              *power_profiles_proxy;
0de61d
         guint32                  power_saver_cookie;
0de61d
+        gboolean                 power_saver_enabled;
0de61d
 
0de61d
         /* Sound */
0de61d
         guint32                  critical_alert_timeout_id;
0de61d
@@ -1780,6 +1781,20 @@ clear_idle_watch (GnomeIdleMonitor *monitor,
0de61d
         *id = 0;
0de61d
 }
0de61d
 
0de61d
+static gboolean
0de61d
+is_power_save_active (GsdPowerManager *manager)
0de61d
+{
0de61d
+        /*
0de61d
+         * If we have power-profiles-daemon, then we follow its setting,
0de61d
+         * otherwise we go into power-save mode when the battery is low.
0de61d
+         */
0de61d
+        if (manager->power_profiles_proxy &&
0de61d
+            g_dbus_proxy_get_name_owner (manager->power_profiles_proxy))
0de61d
+                return manager->power_saver_enabled;
0de61d
+        else
0de61d
+                return manager->battery_is_low;
0de61d
+}
0de61d
+
0de61d
 static void
0de61d
 idle_configure (GsdPowerManager *manager)
0de61d
 {
0de61d
@@ -1903,8 +1918,8 @@ idle_configure (GsdPowerManager *manager)
0de61d
                 /* Don't dim when the screen lock is active */
0de61d
         } else if (!on_battery) {
0de61d
                 /* Don't dim when charging */
0de61d
-        } else if (manager->battery_is_low) {
0de61d
-                /* Aggressively blank when battery is low */
0de61d
+        } else if (is_power_save_active (manager)) {
0de61d
+                /* Try to save power by dimming agressively */
0de61d
                 timeout_dim = SCREENSAVER_TIMEOUT_BLANK;
0de61d
         } else {
0de61d
                 if (g_settings_get_boolean (manager->settings, "idle-dim")) {
0de61d
@@ -2165,6 +2180,27 @@ power_profiles_proxy_signal_cb (GDBusProxy  *proxy,
0de61d
         manager->power_saver_cookie = 0;
0de61d
 }
0de61d
 
0de61d
+static void
0de61d
+update_active_power_profile (GsdPowerManager *manager)
0de61d
+{
0de61d
+        g_autoptr(GVariant) v = NULL;
0de61d
+        const char *active_profile;
0de61d
+        gboolean power_saver_enabled;
0de61d
+
0de61d
+        v = g_dbus_proxy_get_cached_property (manager->power_profiles_proxy, "ActiveProfile");
0de61d
+        if (v) {
0de61d
+                active_profile = g_variant_get_string (v, NULL);
0de61d
+                power_saver_enabled = g_strcmp0 (active_profile, "power-saver") == 0;
0de61d
+                if (power_saver_enabled != manager->power_saver_enabled) {
0de61d
+                        manager->power_saver_enabled = power_saver_enabled;
0de61d
+                        idle_configure (manager);
0de61d
+                }
0de61d
+        } else {
0de61d
+                /* p-p-d might have disappeared from the bus */
0de61d
+                idle_configure (manager);
0de61d
+        }
0de61d
+}
0de61d
+
0de61d
 static void
0de61d
 power_profiles_proxy_ready_cb (GObject             *source_object,
0de61d
                               GAsyncResult        *res,
0de61d
@@ -2179,9 +2215,15 @@ power_profiles_proxy_ready_cb (GObject             *source_object,
0de61d
                 return;
0de61d
         }
0de61d
 
0de61d
+        g_signal_connect_swapped (manager->power_profiles_proxy,
0de61d
+                                  "g-properties-changed",
0de61d
+                                  G_CALLBACK (update_active_power_profile),
0de61d
+                                  manager);
0de61d
         g_signal_connect (manager->power_profiles_proxy, "g-signal",
0de61d
                           G_CALLBACK (power_profiles_proxy_signal_cb),
0de61d
                           manager);
0de61d
+
0de61d
+        update_active_power_profile (manager);
0de61d
 }
0de61d
 
0de61d
 static void
0de61d
-- 
0de61d
2.31.1
0de61d
0de61d
0de61d
From 89e25ed7871258aa6df7f824e226a7b8a28f23f3 Mon Sep 17 00:00:00 2001
0de61d
From: Bastien Nocera <hadess@hadess.net>
0de61d
Date: Thu, 29 Jul 2021 12:05:40 +0200
0de61d
Subject: [PATCH 3/4] power: Respect dim screen settings when not on battery
0de61d
0de61d
The dim screen settings in the UI was not well respected as it only
0de61d
worked on discharging laptops.
0de61d
0de61d
Closes: https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/837
0de61d
---
0de61d
 plugins/power/gsd-power-manager.c | 2 --
0de61d
 1 file changed, 2 deletions(-)
0de61d
0de61d
diff --git a/plugins/power/gsd-power-manager.c b/plugins/power/gsd-power-manager.c
0de61d
index cfef9718..e7b9752f 100644
0de61d
--- a/plugins/power/gsd-power-manager.c
0de61d
+++ b/plugins/power/gsd-power-manager.c
0de61d
@@ -1916,8 +1916,6 @@ idle_configure (GsdPowerManager *manager)
0de61d
         timeout_dim = 0;
0de61d
         if (manager->screensaver_active) {
0de61d
                 /* Don't dim when the screen lock is active */
0de61d
-        } else if (!on_battery) {
0de61d
-                /* Don't dim when charging */
0de61d
         } else if (is_power_save_active (manager)) {
0de61d
                 /* Try to save power by dimming agressively */
0de61d
                 timeout_dim = SCREENSAVER_TIMEOUT_BLANK;
0de61d
-- 
0de61d
2.31.1
0de61d
0de61d
0de61d
From f91abc0033b9cf17fd0e171cb7d652f88edac294 Mon Sep 17 00:00:00 2001
0de61d
From: Bastien Nocera <hadess@hadess.net>
0de61d
Date: Mon, 9 Aug 2021 17:57:11 +0200
0de61d
Subject: [PATCH 4/4] power: When dimming the screen, dim it quicker by default
0de61d
0de61d
Now that we respect the "dim when idle" setting[1], dim quicker to try
0de61d
and save more power. 4/5 of the timeout to the screensaver was always a
0de61d
bit too undecided as a fraction, even when using the dimming as a
0de61d
warning that the screen was going to go to the screensaver (see commit
0de61d
7bc750a5).
0de61d
0de61d
[1]: Except in power-saver mode where we always dim aggressively
0de61d
---
0de61d
 plugins/power/gsd-power-constants.h | 2 +-
0de61d
 plugins/power/gsdpowerconstants.py  | 2 +-
0de61d
 2 files changed, 2 insertions(+), 2 deletions(-)
0de61d
0de61d
diff --git a/plugins/power/gsd-power-constants.h b/plugins/power/gsd-power-constants.h
0de61d
index 91e2296a..8bf9c641 100644
0de61d
--- a/plugins/power/gsd-power-constants.h
0de61d
+++ b/plugins/power/gsd-power-constants.h
0de61d
@@ -25,7 +25,7 @@
0de61d
 #define IDLE_DIM_BLANK_DISABLED_MIN                     60 /* seconds */
0de61d
 
0de61d
 /* Which fraction of the idle-delay is the idle-dim delay */
0de61d
-#define IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER                4.0/5.0
0de61d
+#define IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER                1.0/2.0
0de61d
 
0de61d
 /* The dim delay under which we do not bother dimming */
0de61d
 #define MINIMUM_IDLE_DIM_DELAY                          10 /* seconds */
0de61d
diff --git a/plugins/power/gsdpowerconstants.py b/plugins/power/gsdpowerconstants.py
0de61d
index a07798ee..26fa5bfc 100644
0de61d
--- a/plugins/power/gsdpowerconstants.py
0de61d
+++ b/plugins/power/gsdpowerconstants.py
0de61d
@@ -8,7 +8,7 @@
0de61d
 
0de61d
 SCREENSAVER_TIMEOUT_BLANK = 15;
0de61d
 IDLE_DIM_BLANK_DISABLED_MIN = 60;
0de61d
-IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER = 4.0/5.0;
0de61d
+IDLE_DELAY_TO_IDLE_DIM_MULTIPLIER = 1.0/2.0;
0de61d
 MINIMUM_IDLE_DIM_DELAY = 10;
0de61d
 POWER_UP_TIME_ON_AC = 15;
0de61d
 GSD_MOCK_DEFAULT_BRIGHTNESS = 50;
0de61d
-- 
0de61d
2.31.1
0de61d