From e25937a3ed740ed0618a8943dee32e8966541cdf Mon Sep 17 00:00:00 2001 From: Simon Fowler Date: Sat, 10 Feb 2018 02:37:39 +1000 Subject: [PATCH] Suspend on lid close based on power status. (#8016) This change adds support for controlling the suspend-on-lid-close behaviour based on the power status as well as whether the machine is docked or has an external monitor. For backwards compatibility the new configuration file variable is ignored completely by default, and must be set explicitly before being considered in any decisions. --- man/logind.conf.xml | 10 ++++++++-- src/login/logind-button.c | 6 +++++- src/login/logind-core.c | 31 +++++++++++++++++++++++++++++++ src/login/logind-dbus.c | 1 + src/login/logind-gperf.gperf | 1 + src/login/logind.c | 14 +++----------- src/login/logind.conf.in | 1 + src/login/logind.h | 3 +++ 8 files changed, 53 insertions(+), 14 deletions(-) diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 8d2bfc5d5b..4a64ddb827 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -211,6 +211,7 @@ HandleSuspendKey= HandleHibernateKey= HandleLidSwitch= + HandleLidSwitchExternalPower= HandleLidSwitchDocked= Controls how logind shall handle the @@ -235,12 +236,17 @@ HandleSuspendKey= and HandleLidSwitch= default to suspend. - HandleLidSwitchDocked= defaults to - ignore. + HandleLidSwitchExternalPower= is completely + ignored by default (for backwards compatibility) — an explicit + value must be set before it will be used to determine + behaviour. HandleLidSwitchDocked= defaults + to ignore. HandleHibernateKey= defaults to hibernate. If the system is inserted in a docking station, or if more than one display is connected, the action specified by HandleLidSwitchDocked= + occurs; if the system is on external power the action (if any) + specified by HandleLidSwitchExternalPower= occurs; otherwise the HandleLidSwitch= action occurs. diff --git a/src/login/logind-button.c b/src/login/logind-button.c index 94945f0bcb..2da6e69952 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -110,9 +110,13 @@ static void button_lid_switch_handle_action(Manager *manager, bool is_edge) { assert(manager); - /* If we are docked, handle the lid switch differently */ + /* If we are docked or on external power, handle the lid switch + * differently */ if (manager_is_docked_or_external_displays(manager)) handle_action = manager->handle_lid_switch_docked; + else if (manager->handle_lid_switch_ep != _HANDLE_ACTION_INVALID && + manager_is_on_external_power()) + handle_action = manager->handle_lid_switch_ep; else handle_action = manager->handle_lid_switch; diff --git a/src/login/logind-core.c b/src/login/logind-core.c index e338682f41..cd10536ce5 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -602,3 +602,34 @@ bool manager_is_docked_or_external_displays(Manager *m) { return false; } + +bool manager_is_on_external_power(void) { + int r; + + /* For now we only check for AC power, but 'external power' can apply + * to anything that isn't an internal battery */ + r = on_ac_power(); + if (r < 0) + log_warning_errno(r, "Failed to read AC power status: %m"); + else if (r > 0) + return true; + + return false; +} + +bool manager_all_buttons_ignored(Manager *m) { + if (m->handle_power_key != HANDLE_IGNORE) + return false; + if (m->handle_suspend_key != HANDLE_IGNORE) + return false; + if (m->handle_hibernate_key != HANDLE_IGNORE) + return false; + if (m->handle_lid_switch != HANDLE_IGNORE) + return false; + if (m->handle_lid_switch_ep != _HANDLE_ACTION_INVALID && + m->handle_lid_switch_ep != HANDLE_IGNORE) + return false; + if (m->handle_lid_switch_docked != HANDLE_IGNORE) + return false; + return true; +} diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index ae36ececb5..ed9eba1ee0 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -2653,6 +2653,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandleLidSwitchExternalPower", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_ep), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HandleLidSwitchDocked", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_docked), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HoldoffTimeoutUSec", "t", NULL, offsetof(Manager, holdoff_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index ee62db63a5..f6f57526f6 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -27,6 +27,7 @@ Login.HandlePowerKey, config_parse_handle_action, 0, offsetof(Manag Login.HandleSuspendKey, config_parse_handle_action, 0, offsetof(Manager, handle_suspend_key) Login.HandleHibernateKey, config_parse_handle_action, 0, offsetof(Manager, handle_hibernate_key) Login.HandleLidSwitch, config_parse_handle_action, 0, offsetof(Manager, handle_lid_switch) +Login.HandleLidSwitchExternalPower,config_parse_handle_action, 0, offsetof(Manager, handle_lid_switch_ep) Login.HandleLidSwitchDocked, config_parse_handle_action, 0, offsetof(Manager, handle_lid_switch_docked) Login.PowerKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, power_key_ignore_inhibited) Login.SuspendKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, suspend_key_ignore_inhibited) diff --git a/src/login/logind.c b/src/login/logind.c index d15d4cec5b..d9b5f026cf 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -53,6 +53,7 @@ static void manager_reset_config(Manager *m) { m->handle_suspend_key = HANDLE_SUSPEND; m->handle_hibernate_key = HANDLE_HIBERNATE; m->handle_lid_switch = HANDLE_SUSPEND; + m->handle_lid_switch_ep = _HANDLE_ACTION_INVALID; m->handle_lid_switch_docked = HANDLE_IGNORE; m->power_key_ignore_inhibited = false; m->suspend_key_ignore_inhibited = false; @@ -253,11 +254,7 @@ static int manager_enumerate_buttons(Manager *m) { /* Loads buttons from udev */ - if (m->handle_power_key == HANDLE_IGNORE && - m->handle_suspend_key == HANDLE_IGNORE && - m->handle_hibernate_key == HANDLE_IGNORE && - m->handle_lid_switch == HANDLE_IGNORE && - m->handle_lid_switch_docked == HANDLE_IGNORE) + if (manager_all_buttons_ignored(m)) return 0; e = udev_enumerate_new(m->udev); @@ -905,12 +902,7 @@ static int manager_connect_udev(Manager *m) { return r; /* Don't watch keys if nobody cares */ - if (m->handle_power_key != HANDLE_IGNORE || - m->handle_suspend_key != HANDLE_IGNORE || - m->handle_hibernate_key != HANDLE_IGNORE || - m->handle_lid_switch != HANDLE_IGNORE || - m->handle_lid_switch_docked != HANDLE_IGNORE) { - + if (!manager_all_buttons_ignored(m)) { m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); if (!m->udev_button_monitor) return -ENOMEM; diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in index 6f720b7708..40a77dc7be 100644 --- a/src/login/logind.conf.in +++ b/src/login/logind.conf.in @@ -22,6 +22,7 @@ #HandleSuspendKey=suspend #HandleHibernateKey=hibernate #HandleLidSwitch=suspend +#HandleLidSwitchExternalPower=suspend #HandleLidSwitchDocked=ignore #PowerKeyIgnoreInhibited=no #SuspendKeyIgnoreInhibited=no diff --git a/src/login/logind.h b/src/login/logind.h index 8262367135..918bc1f919 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -118,6 +118,7 @@ struct Manager { HandleAction handle_suspend_key; HandleAction handle_hibernate_key; HandleAction handle_lid_switch; + HandleAction handle_lid_switch_ep; HandleAction handle_lid_switch_docked; bool power_key_ignore_inhibited; @@ -160,6 +161,8 @@ int manager_get_user_by_pid(Manager *m, pid_t pid, User **user); int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session); bool manager_is_docked_or_external_displays(Manager *m); +bool manager_is_on_external_power(void); +bool manager_all_buttons_ignored(Manager *m); extern const sd_bus_vtable manager_vtable[];