mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
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.
This commit is contained in:
parent
632c2e4123
commit
6de0e0e500
@ -170,33 +170,47 @@
|
||||
and sleep keys and the lid switch to
|
||||
trigger system power-off or
|
||||
suspend. Can be one of
|
||||
<literal>no</literal>,
|
||||
<literal>yes</literal> and
|
||||
<literal>off</literal>,
|
||||
<literal>no-session</literal>,
|
||||
<literal>tty-session</literal>,
|
||||
<literal>any-session</literal> and
|
||||
<literal>always</literal>. If
|
||||
<literal>no</literal> logind will
|
||||
<literal>off</literal> logind will
|
||||
never handle these keys. If
|
||||
<literal>yes</literal> logind will
|
||||
handle these keys when no user is
|
||||
<literal>no-session</literal> 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
|
||||
<literal>tty-session</literal> 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
|
||||
<literal>any-session</literal> 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
|
||||
<literal>always</literal> 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 <literal>power-switch</literal>
|
||||
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
|
||||
<literal>power-switch</literal> udev
|
||||
tag will be watched for key
|
||||
events. <varname>HandlePowerKey=</varname>
|
||||
and <varname>HandleSleepKey=</varname>
|
||||
default to <literal>yes</literal>,
|
||||
defaults to
|
||||
<literal>no-session</literal>.
|
||||
<varname>HandleSleepKey=</varname>
|
||||
defaults to
|
||||
<literal>tty-session</literal>,
|
||||
<varname>HandleLidSwitch=</varname>
|
||||
defaults to
|
||||
<literal>no</literal>.</para></listitem>
|
||||
<literal>off</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
@ -152,20 +152,18 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool has_graphical_session(Manager *m, const char *seat) {
|
||||
Seat *s;
|
||||
static Session *button_get_session(Button *b) {
|
||||
Seat *seat;
|
||||
assert(b);
|
||||
|
||||
assert(m);
|
||||
assert(seat);
|
||||
if (!b->seat)
|
||||
return NULL;
|
||||
|
||||
s = hashmap_get(m->seats, seat);
|
||||
if (!s)
|
||||
return false;
|
||||
seat = hashmap_get(b->manager->seats, b->seat);
|
||||
if (!seat)
|
||||
return NULL;
|
||||
|
||||
if (!s->active)
|
||||
return false;
|
||||
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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_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_enable_receiving(m->udev_vcsa_monitor);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
|
||||
m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
@ -15,6 +15,6 @@
|
||||
#Controllers=
|
||||
#ResetControllers=cpu
|
||||
#InhibitDelayMaxSec=5
|
||||
#HandlePowerKey=yes
|
||||
#HandleSleepKey=yes
|
||||
#HandleLidSwitch=no
|
||||
#HandlePowerKey=no-session
|
||||
#HandleSleepKey=tty-session
|
||||
#HandleLidSwitch=off
|
||||
|
Loading…
Reference in New Issue
Block a user