forked from pool/systemd
175 lines
6.1 KiB
Diff
175 lines
6.1 KiB
Diff
|
From f9cd6be10ece07e10488c05e270a0b5860779864 Mon Sep 17 00:00:00 2001
|
||
|
From: Lennart Poettering <lennart@poettering.net>
|
||
|
Date: Mon, 3 Mar 2014 20:49:33 +0100
|
||
|
Subject: [PATCH] logind: ignore lid switch events for 30s after each suspend
|
||
|
and 3min after startup
|
||
|
|
||
|
This is needed to give USB docking stations and suchlike time to settle,
|
||
|
so that a display connected to an USB docking station can actually act
|
||
|
as a lid swith inhibitor correctly.
|
||
|
|
||
|
With this change we should have somewhat reliable docking station
|
||
|
support in place.
|
||
|
---
|
||
|
src/login/logind-action.c | 15 ++++++++++++++-
|
||
|
src/login/logind-dbus.c | 3 +++
|
||
|
src/login/logind.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
|
||
|
src/login/logind.h | 7 +++++++
|
||
|
4 files changed, 69 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git src/login/logind-action.c src/login/logind-action.c
|
||
|
index c9d8bc5..ae7b350 100644
|
||
|
--- src/login/logind-action.c
|
||
|
+++ src/login/logind-action.c
|
||
|
@@ -70,20 +70,33 @@ int manager_handle_action(
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
- /* If we are docked don't react to lid closing */
|
||
|
if (inhibit_key == INHIBIT_HANDLE_LID_SWITCH) {
|
||
|
int n;
|
||
|
|
||
|
+ /* If we are docked don't react to lid closing */
|
||
|
if (manager_is_docked(m)) {
|
||
|
log_debug("Ignoring lid switch request, system is docked.");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+ /* If we have more than one or no displays connected,
|
||
|
+ * don't react to lid closing. The no display case we
|
||
|
+ * treat like this under the assumption that there is
|
||
|
+ * no modern drm driver available. */
|
||
|
n = manager_count_displays(m);
|
||
|
if (n != 1) {
|
||
|
log_debug("Ignoring lid switch request, %i displays connected.", n);
|
||
|
return 0;
|
||
|
}
|
||
|
+
|
||
|
+ /* If the last system suspend or startup is too close,
|
||
|
+ * let's not suspend for now, to give USB docking
|
||
|
+ * stations some time to settle so that we can
|
||
|
+ * properly watch its displays. */
|
||
|
+ if (m->lid_switch_ignore_event_source) {
|
||
|
+ log_debug("Ignoring lid switch request, system startup or resume too close.");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
/* If the key handling is inhibited, don't do anything */
|
||
|
diff --git src/login/logind-dbus.c src/login/logind-dbus.c
|
||
|
index fc89531..c9c58f3 100644
|
||
|
--- src/login/logind-dbus.c
|
||
|
+++ src/login/logind-dbus.c
|
||
|
@@ -1337,6 +1337,9 @@ static int execute_shutdown_or_sleep(
|
||
|
m->action_job = c;
|
||
|
m->action_what = w;
|
||
|
|
||
|
+ /* Make sure the lid switch is ignored for a while */
|
||
|
+ manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + IGNORE_LID_SWITCH_SUSPEND_USEC);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git src/login/logind.c src/login/logind.c
|
||
|
index 10f61ab..fd113b3 100644
|
||
|
--- src/login/logind.c
|
||
|
+++ src/login/logind.c
|
||
|
@@ -144,6 +144,7 @@ void manager_free(Manager *m) {
|
||
|
sd_event_source_unref(m->udev_device_event_source);
|
||
|
sd_event_source_unref(m->udev_vcsa_event_source);
|
||
|
sd_event_source_unref(m->udev_button_event_source);
|
||
|
+ sd_event_source_unref(m->lid_switch_ignore_event_source);
|
||
|
|
||
|
if (m->console_active_fd >= 0)
|
||
|
close_nointr_nofail(m->console_active_fd);
|
||
|
@@ -959,6 +960,46 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
|
||
|
+ Manager *m = userdata;
|
||
|
+
|
||
|
+ assert(e);
|
||
|
+ assert(m);
|
||
|
+
|
||
|
+ m->lid_switch_ignore_event_source = sd_event_source_unref(m->lid_switch_ignore_event_source);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int manager_set_lid_switch_ignore(Manager *m, usec_t until) {
|
||
|
+ int r;
|
||
|
+
|
||
|
+ assert(m);
|
||
|
+
|
||
|
+ if (until <= now(CLOCK_MONOTONIC))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ /* We want to ignore the lid switch for a while after each
|
||
|
+ * suspend, and after boot-up. Hence let's install a timer for
|
||
|
+ * this. As long as the event source exists we ignore the lid
|
||
|
+ * switch. */
|
||
|
+
|
||
|
+ if (m->lid_switch_ignore_event_source) {
|
||
|
+ usec_t u;
|
||
|
+
|
||
|
+ r = sd_event_source_get_time(m->lid_switch_ignore_event_source, &u);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
+ if (until <= u)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ r = sd_event_source_set_time(m->lid_switch_ignore_event_source, until);
|
||
|
+ } else
|
||
|
+ r = sd_event_add_monotonic(m->event, &m->lid_switch_ignore_event_source, until, 0, lid_switch_ignore_handler, m);
|
||
|
+
|
||
|
+ return r;
|
||
|
+}
|
||
|
+
|
||
|
int manager_startup(Manager *m) {
|
||
|
int r;
|
||
|
Seat *seat;
|
||
|
@@ -994,6 +1035,10 @@ int manager_startup(Manager *m) {
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
+ r = manager_set_lid_switch_ignore(m, 0 + IGNORE_LID_SWITCH_STARTUP_USEC);
|
||
|
+ if (r < 0)
|
||
|
+ log_warning("Failed to set up lid switch ignore event source: %s", strerror(-r));
|
||
|
+
|
||
|
/* Deserialize state */
|
||
|
r = manager_enumerate_devices(m);
|
||
|
if (r < 0)
|
||
|
diff --git src/login/logind.h src/login/logind.h
|
||
|
index 74d6641..4bb8e7b 100644
|
||
|
--- src/login/logind.h
|
||
|
+++ src/login/logind.h
|
||
|
@@ -42,6 +42,9 @@ typedef struct Manager Manager;
|
||
|
#include "logind-button.h"
|
||
|
#include "logind-action.h"
|
||
|
|
||
|
+#define IGNORE_LID_SWITCH_STARTUP_USEC (3 * USEC_PER_MINUTE)
|
||
|
+#define IGNORE_LID_SWITCH_SUSPEND_USEC (30 * USEC_PER_SEC)
|
||
|
+
|
||
|
struct Manager {
|
||
|
sd_event *event;
|
||
|
sd_bus *bus;
|
||
|
@@ -118,6 +121,8 @@ struct Manager {
|
||
|
bool lid_switch_ignore_inhibited;
|
||
|
|
||
|
Hashmap *polkit_registry;
|
||
|
+
|
||
|
+ sd_event_source *lid_switch_ignore_event_source;
|
||
|
};
|
||
|
|
||
|
Manager *manager_new(void);
|
||
|
@@ -178,3 +183,5 @@ const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned lengt
|
||
|
|
||
|
int manager_watch_busname(Manager *manager, const char *name);
|
||
|
void manager_drop_busname(Manager *manager, const char *name);
|
||
|
+
|
||
|
+int manager_set_lid_switch_ignore(Manager *m, usec_t until);
|
||
|
--
|
||
|
1.7.9.2
|
||
|
|