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