diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-03-03 20:49:33 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-03-03 20:57:09 +0100 |
commit | f9cd6be10ece07e10488c05e270a0b5860779864 (patch) | |
tree | f236bd39b54c2b66276c7ac72a36cb565cf0b53e | |
parent | 7e9110a29d90041b0364cb93a84aec9dd72363b6 (diff) |
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.
-rw-r--r-- | src/login/logind-action.c | 15 | ||||
-rw-r--r-- | src/login/logind-dbus.c | 3 | ||||
-rw-r--r-- | src/login/logind.c | 45 | ||||
-rw-r--r-- | src/login/logind.h | 7 |
4 files changed, 69 insertions, 1 deletions
diff --git a/src/login/logind-action.c b/src/login/logind-action.c index c9d8bc541..ae7b35055 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -67,26 +67,39 @@ int manager_handle_action( /* If the key handling is turned off, don't do anything */ if (handle == HANDLE_IGNORE) { log_debug("Refusing operation, as it is turned off."); 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 */ if (inhibit_key > 0) { if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0, NULL)) { log_debug("Refusing operation, %s is inhibited.", inhibit_what_to_string(inhibit_key)); diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index fc8953155..c9c58f3f8 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1334,12 +1334,15 @@ static int execute_shutdown_or_sleep( m->action_unit = unit_name; free(m->action_job); 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; } static int delay_shutdown_or_sleep( Manager *m, InhibitWhat w, diff --git a/src/login/logind.c b/src/login/logind.c index 10f61aba3..fd113b3e7 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -141,12 +141,13 @@ void manager_free(Manager *m) { sd_event_source_unref(m->console_active_event_source); sd_event_source_unref(m->udev_seat_event_source); 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); if (m->udev_seat_monitor) udev_monitor_unref(m->udev_seat_monitor); @@ -956,12 +957,52 @@ 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; Session *session; User *user; Button *button; @@ -991,12 +1032,16 @@ int manager_startup(Manager *m) { r = manager_add_seat(m, "seat0", &m->seat0); if (r < 0) { log_error("Failed to add seat0: %s", strerror(-r)); 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) log_warning("Device enumeration failed: %s", strerror(-r)); r = manager_enumerate_seats(m); diff --git a/src/login/logind.h b/src/login/logind.h index 74d66415e..4bb8e7b65 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -39,12 +39,15 @@ typedef struct Manager Manager; #include "logind-session.h" #include "logind-user.h" #include "logind-inhibit.h" #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; Hashmap *devices; Hashmap *seats; @@ -115,12 +118,14 @@ struct Manager { bool power_key_ignore_inhibited; bool suspend_key_ignore_inhibited; bool hibernate_key_ignore_inhibited; bool lid_switch_ignore_inhibited; Hashmap *polkit_registry; + + sd_event_source *lid_switch_ignore_event_source; }; Manager *manager_new(void); void manager_free(Manager *m); int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device); @@ -175,6 +180,8 @@ int manager_job_is_active(Manager *manager, const char *path); /* gperf lookup function */ const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned length); 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); |