1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-10-27 18:55:09 +03:00

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.
This commit is contained in:
Lennart Poettering 2014-03-03 20:49:33 +01:00
parent 7e9110a29d
commit f9cd6be10e
4 changed files with 69 additions and 1 deletions

View File

@ -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 */

View File

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

View File

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

View File

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