logind: ignore lid switch if more than 1 display is connected

Previously we expected the desktop environment to take an inhibitor
lock, but this opened a race on boot-up where logind might already be
running but no DE is active.

Hence, let's move checking for additional displays into logind. This
also opens up this logic for other DEs, given that only GNOME
implemented the inhibitor logic so far.
This commit is contained in:
Lennart Poettering
2014-03-03 19:32:43 +01:00
parent ae833394d6
commit 6a79c58603
4 changed files with 71 additions and 7 deletions
+9 -5
View File
@@ -242,10 +242,10 @@
<literal>ignore</literal>, logind will
never handle these keys. If
<literal>lock</literal>, all running
sessions will be screen-locked; otherwise,
the specified action
will be taken in the respective
event. Only input devices with the
sessions will be screen-locked;
otherwise, the specified action will
be taken in the respective event. Only
input devices with the
<literal>power-switch</literal> udev
tag will be watched for key/lid switch
events. <varname>HandlePowerKey=</varname>
@@ -257,7 +257,11 @@
default to <literal>suspend</literal>.
<varname>HandleHibernateKey=</varname>
defaults to
<literal>hibernate</literal>.</para></listitem>
<literal>hibernate</literal>. Note
that the lid switch is ignored if the
system is inserted in a docking
station, or if more than one display
is connected.</para></listitem>
</varlistentry>
<varlistentry>
+8
View File
@@ -72,10 +72,18 @@ int manager_handle_action(
/* If we are docked don't react to lid closing */
if (inhibit_key == INHIBIT_HANDLE_LID_SWITCH) {
int n;
if (manager_is_docked(m)) {
log_debug("Ignoring lid switch request, system is docked.");
return 0;
}
n = manager_count_displays(m);
if (n != 1) {
log_debug("Ignoring lid switch request, %s displays connected.");
return 0;
}
}
/* If the key handling is inhibited, don't do anything */
+53 -2
View File
@@ -32,6 +32,7 @@
#include "audit.h"
#include "bus-util.h"
#include "bus-error.h"
#include "udev-util.h"
#include "logind.h"
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
@@ -276,9 +277,11 @@ int manager_process_seat_device(Manager *m, struct udev_device *d) {
return 0;
}
/* ignore non-master devices for unknown seats */
seat = hashmap_get(m->seats, sn);
master = udev_device_has_tag(d, "master-of-seat");
if (!master && !(seat = hashmap_get(m->seats, sn)))
/* Ignore non-master devices for unknown seats */
if (!master && !seat)
return 0;
r = manager_add_device(m, udev_device_get_syspath(d), master, &device);
@@ -514,3 +517,51 @@ bool manager_is_docked(Manager *m) {
return false;
}
int manager_count_displays(Manager *m) {
_cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
int r;
int n = 0;
e = udev_enumerate_new(m->udev);
if (!e)
return -ENOMEM;
r = udev_enumerate_add_match_subsystem(e, "drm");
if (r < 0)
return r;
r = udev_enumerate_scan_devices(e);
if (r < 0)
return r;
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
struct udev_device *p;
const char *status;
d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
if (!d)
return -ENOMEM;
p = udev_device_get_parent(d);
if (!p)
return -ENOMEM;
/* If the parent shares the same subsystem as the
* device we are looking at then it is a connector,
* which is what we are interested in. */
if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
continue;
/* We count any connector which is not explicitly
* "disconnected" as connected. */
status = udev_device_get_sysattr_value(d, "status");
if (!streq_ptr(status, "disconnected"))
n++;
}
return n;
}
+1
View File
@@ -149,6 +149,7 @@ int manager_get_user_by_pid(Manager *m, pid_t pid, User **user);
int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session);
bool manager_is_docked(Manager *m);
int manager_count_displays(Manager *m);
extern const sd_bus_vtable manager_vtable[];