From: Lennart Poettering Date: Wed, 30 May 2012 19:40:32 +0000 (+0200) Subject: logind: rework button setting semantics X-Git-Tag: v184~15 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=6de0e0e500d9d534c6e4baab242fc2a146f021fa logind: rework button setting semantics If a graphical session without full DE that handles power/suspend events is used this can now be controlled by logind instead, optionally. --- diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 09db60014..35a7d4855 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -170,33 +170,47 @@ and sleep keys and the lid switch to trigger system power-off or suspend. Can be one of - no, - yes and + off, + no-session, + tty-session, + any-session and always. If - no logind will + off logind will never handle these keys. If - yes logind will - handle these keys when no user is + no-session logind + will handle these keys when no user is logged in and no inhibitor lock is taken, and trigger a warnig beep otherwise. If set to + tty-session logind + will handle these keys if no inhibitor + lock is taken, and either no user is + logged in or the foreground session is + a text login and the only one + existing. If + any-session is set + logind will handle these keys if no + inhibitor lock is taken, and either no + user is logged in or the foreground + session is the only one existing + (regardless whether graphical or + text). If set to always logind will - handle these keys even if a user is - logged in or an inhibitor lock is - taken. In all cases logind will not - handle these keys if a graphical - session is in the foreground under the - assumption that the graphical session - will handle these keys - internally. Only input devices with - the power-switch - udev tag will be watched for key + handle these keys in any case, even if + one or more users are logged in or an + inhibitor lock is taken. Only input + devices with the + power-switch udev + tag will be watched for key events. HandlePowerKey= - and HandleSleepKey= - default to yes, + defaults to + no-session. + HandleSleepKey= + defaults to + tty-session, HandleLidSwitch= defaults to - no. + off. diff --git a/src/login/logind-button.c b/src/login/logind-button.c index 48432e195..8b59c2b0c 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -152,20 +152,18 @@ fail: return r; } -static bool has_graphical_session(Manager *m, const char *seat) { - Seat *s; - - assert(m); - assert(seat); +static Session *button_get_session(Button *b) { + Seat *seat; + assert(b); - s = hashmap_get(m->seats, seat); - if (!s) - return false; + if (!b->seat) + return NULL; - if (!s->active) - return false; + seat = hashmap_get(b->manager->seats, b->seat); + if (!seat) + return NULL; - return s->active->type == SESSION_X11; + return seat->active; } static int button_power_off(Button *b, HandleButton handle) { @@ -174,17 +172,38 @@ static int button_power_off(Button *b, HandleButton handle) { assert(b); - if (handle == HANDLE_NO) + if (handle == HANDLE_OFF) return 0; - if (handle != HANDLE_ALWAYS) { - + if (handle == HANDLE_NO_SESSION) { if (hashmap_size(b->manager->sessions) > 0) { log_error("Refusing power-off, user is logged in."); warn_melody(); return -EPERM; } + } else if (handle == HANDLE_TTY_SESSION || + handle == HANDLE_ANY_SESSION) { + unsigned n; + Session *s; + + n = hashmap_size(b->manager->sessions); + s = button_get_session(b); + + /* Silently ignore events of graphical sessions */ + if (handle == HANDLE_TTY_SESSION && + s && s->type == SESSION_X11) + return 0; + + if (n > 1 || (n == 1 && !s)) { + log_error("Refusing power-off, other user is logged in."); + warn_melody(); + return -EPERM; + } + + } + + if (handle != HANDLE_ALWAYS) { if (manager_is_inhibited(b->manager, INHIBIT_SHUTDOWN, INHIBIT_BLOCK, NULL)) { log_error("Refusing power-off, shutdown is inhibited."); warn_melody(); @@ -210,17 +229,37 @@ static int button_suspend(Button *b, HandleButton handle) { assert(b); - if (handle == HANDLE_NO) + if (handle == HANDLE_OFF) return 0; - if (handle != HANDLE_ALWAYS) { - + if (handle == HANDLE_NO_SESSION) { if (hashmap_size(b->manager->sessions) > 0) { log_error("Refusing suspend, user is logged in."); warn_melody(); return -EPERM; } + } else if (handle == HANDLE_TTY_SESSION || + handle == HANDLE_ANY_SESSION) { + unsigned n; + Session *s; + + n = hashmap_size(b->manager->sessions); + s = button_get_session(b); + + /* Silently ignore events of graphical sessions */ + if (handle == HANDLE_TTY_SESSION && + s && s->type == SESSION_X11) + return 0; + + if (n > 1 || (n == 1 && !s)) { + log_error("Refusing suspend, other user is logged in."); + warn_melody(); + return -EPERM; + } + } + + if (handle != HANDLE_ALWAYS) { if (manager_is_inhibited(b->manager, INHIBIT_SLEEP, INHIBIT_BLOCK, NULL)) { log_error("Refusing suspend, sleeping is inhibited."); warn_melody(); @@ -252,12 +291,6 @@ int button_process(Button *b) { if ((size_t) l < sizeof(ev)) return -EIO; - /* If there's a graphical session on the seat this device - * belongs to we ignore events, it is job of the graphical - * session to handle the event. */ - if (has_graphical_session(b->manager, b->seat)) - return 0; - if (ev.type == EV_KEY && ev.value > 0) { switch (ev.code) { @@ -287,8 +320,10 @@ int button_process(Button *b) { } static const char* const handle_button_table[_HANDLE_BUTTON_MAX] = { - [HANDLE_YES] = "yes", - [HANDLE_NO] = "no", + [HANDLE_OFF] = "off", + [HANDLE_NO_SESSION] = "no-session", + [HANDLE_TTY_SESSION] = "tty-session", + [HANDLE_ANY_SESSION] = "any-session", [HANDLE_ALWAYS] = "always" }; DEFINE_STRING_TABLE_LOOKUP(handle_button, HandleButton); diff --git a/src/login/logind-button.h b/src/login/logind-button.h index 037821132..7518d05cc 100644 --- a/src/login/logind-button.h +++ b/src/login/logind-button.h @@ -25,9 +25,11 @@ typedef struct Button Button; typedef enum HandleButton { - HANDLE_NO, - HANDLE_YES, /* only if no inhibitor is taken/no session is around */ - HANDLE_ALWAYS, /* regardless if inhibitor is taken/session is around */ + HANDLE_OFF, + HANDLE_NO_SESSION, /* Only handle key when nobody is logged in; honour inhibitors */ + HANDLE_TTY_SESSION, /* Only handle key when nobody is logged in, or the fg session is the only one and non-graphical; honour inhibitors */ + HANDLE_ANY_SESSION, /* Only handle key when nobody is logged in, or the fg session is the only one; honour inhibtors */ + HANDLE_ALWAYS, /* Always handle, ignore sessions; ignore inhibitors */ _HANDLE_BUTTON_MAX, _HANDLE_BUTTON_INVALID = -1 } HandleButton; diff --git a/src/login/logind.c b/src/login/logind.c index 0382972e8..632987c8b 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -53,9 +53,9 @@ Manager *manager_new(void) { m->n_autovts = 6; m->inhibit_delay_max = 5 * USEC_PER_SEC; - m->handle_power_key = HANDLE_YES; - m->handle_sleep_key = HANDLE_YES; - m->handle_lid_switch = HANDLE_NO; + m->handle_power_key = HANDLE_NO_SESSION; + m->handle_sleep_key = HANDLE_TTY_SESSION; + m->handle_lid_switch = HANDLE_OFF; m->devices = hashmap_new(string_hash_func, string_compare_func); m->seats = hashmap_new(string_hash_func, string_compare_func); @@ -484,6 +484,11 @@ int manager_enumerate_buttons(Manager *m) { /* Loads buttons from udev */ + if (m->handle_power_key == HANDLE_OFF && + m->handle_sleep_key == HANDLE_OFF && + m->handle_lid_switch == HANDLE_OFF) + return 0; + e = udev_enumerate_new(m->udev); if (!e) { r = -ENOMEM; @@ -1234,59 +1239,62 @@ static int manager_connect_udev(Manager *m) { zero(ev); ev.events = EPOLLIN; ev.data.u32 = FD_SEAT_UDEV; - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0) return -errno; - m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_button_monitor) - return -ENOMEM; + /* Don't watch keys if nobody cares */ + if (m->handle_power_key != HANDLE_OFF || + m->handle_sleep_key != HANDLE_OFF || + m->handle_lid_switch != HANDLE_OFF) { - r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch"); - if (r < 0) - return r; + m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_button_monitor) + return -ENOMEM; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL); - if (r < 0) - return r; + r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch"); + if (r < 0) + return r; - r = udev_monitor_enable_receiving(m->udev_button_monitor); - if (r < 0) - return r; + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL); + if (r < 0) + return r; - m->udev_button_fd = udev_monitor_get_fd(m->udev_button_monitor); + r = udev_monitor_enable_receiving(m->udev_button_monitor); + if (r < 0) + return r; - zero(ev); - ev.events = EPOLLIN; - ev.data.u32 = FD_BUTTON_UDEV; + m->udev_button_fd = udev_monitor_get_fd(m->udev_button_monitor); - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_button_fd, &ev) < 0) - return -errno; + zero(ev); + ev.events = EPOLLIN; + ev.data.u32 = FD_BUTTON_UDEV; + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_button_fd, &ev) < 0) + return -errno; + } /* Don't bother watching VCSA devices, if nobody cares */ - if (m->n_autovts <= 0 || m->console_active_fd < 0) - return 0; + if (m->n_autovts > 0 && m->console_active_fd >= 0) { - m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_vcsa_monitor) - return -ENOMEM; + m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_vcsa_monitor) + return -ENOMEM; - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL); - if (r < 0) - return r; - - r = udev_monitor_enable_receiving(m->udev_vcsa_monitor); - if (r < 0) - return r; + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL); + if (r < 0) + return r; - m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor); + r = udev_monitor_enable_receiving(m->udev_vcsa_monitor); + if (r < 0) + return r; - zero(ev); - ev.events = EPOLLIN; - ev.data.u32 = FD_VCSA_UDEV; + m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor); - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0) - return -errno; + zero(ev); + ev.events = EPOLLIN; + ev.data.u32 = FD_VCSA_UDEV; + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0) + return -errno; + } return 0; } diff --git a/src/login/logind.conf b/src/login/logind.conf index 4f012e5d8..78496a0ef 100644 --- a/src/login/logind.conf +++ b/src/login/logind.conf @@ -15,6 +15,6 @@ #Controllers= #ResetControllers=cpu #InhibitDelayMaxSec=5 -#HandlePowerKey=yes -#HandleSleepKey=yes -#HandleLidSwitch=no +#HandlePowerKey=no-session +#HandleSleepKey=tty-session +#HandleLidSwitch=off