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>
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) {
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();
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();
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) {
}
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);
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;
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);
/* 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;
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;
}
#Controllers=
#ResetControllers=cpu
#InhibitDelayMaxSec=5
-#HandlePowerKey=yes
-#HandleSleepKey=yes
-#HandleLidSwitch=no
+#HandlePowerKey=no-session
+#HandleSleepKey=tty-session
+#HandleLidSwitch=off