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.
This commit is contained in:
Simon Fowler 2018-02-10 02:37:39 +10:00 committed by Zbigniew Jędrzejewski-Szmek
parent 9e42c9373c
commit e25937a3ed
8 changed files with 53 additions and 14 deletions

View File

@ -211,6 +211,7 @@
<term><varname>HandleSuspendKey=</varname></term>
<term><varname>HandleHibernateKey=</varname></term>
<term><varname>HandleLidSwitch=</varname></term>
<term><varname>HandleLidSwitchExternalPower=</varname></term>
<term><varname>HandleLidSwitchDocked=</varname></term>
<listitem><para>Controls how logind shall handle the
@ -235,12 +236,17 @@
<varname>HandleSuspendKey=</varname> and
<varname>HandleLidSwitch=</varname> default to
<literal>suspend</literal>.
<varname>HandleLidSwitchDocked=</varname> defaults to
<literal>ignore</literal>.
<varname>HandleLidSwitchExternalPower=</varname> is completely
ignored by default (for backwards compatibility) &#x2014; an explicit
value must be set before it will be used to determine
behaviour. <varname>HandleLidSwitchDocked=</varname> defaults
to <literal>ignore</literal>.
<varname>HandleHibernateKey=</varname> defaults to
<literal>hibernate</literal>. If the system is inserted in a
docking station, or if more than one display is connected, the
action specified by <varname>HandleLidSwitchDocked=</varname>
occurs; if the system is on external power the action (if any)
specified by <varname>HandleLidSwitchExternalPower=</varname>
occurs; otherwise the <varname>HandleLidSwitch=</varname>
action occurs.</para>

View File

@ -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;

View File

@ -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;
}

View File

@ -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),

View File

@ -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)

View File

@ -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;

View File

@ -22,6 +22,7 @@
#HandleSuspendKey=suspend
#HandleHibernateKey=hibernate
#HandleLidSwitch=suspend
#HandleLidSwitchExternalPower=suspend
#HandleLidSwitchDocked=ignore
#PowerKeyIgnoreInhibited=no
#SuspendKeyIgnoreInhibited=no

View File

@ -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[];