1
0
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:
Lennart Poettering 2012-05-30 21:40:32 +02:00
parent 632c2e4123
commit 6de0e0e500
5 changed files with 148 additions and 89 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -15,6 +15,6 @@
#Controllers=
#ResetControllers=cpu
#InhibitDelayMaxSec=5
#HandlePowerKey=yes
#HandleSleepKey=yes
#HandleLidSwitch=no
#HandlePowerKey=no-session
#HandleSleepKey=tty-session
#HandleLidSwitch=off