chiark / gitweb /
logind: rework display counting when detecting whether the system is docked
authorLennart Poettering <lennart@poettering.net>
Tue, 16 Jun 2015 22:24:05 +0000 (00:24 +0200)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 09:03:02 +0000 (10:03 +0100)
Previously, we'd just count connected displays, and if there was 2 or
more we assumed a "docked" state.

With this change we now:

- Only count external displays, ignore internal ones (which we detect by
  checking the connector name against a whitelist of known external plug
  types)

- We ignore connectors which are explicitly disabled

- We then compare the count with >= 1 rather than >= 2 as before

This new logic has the benefit that systems that disconnect the internal
display when the lid is closed are better supported. Also, explicitly
disabled ports do not confuse the algorithm anymore.

This new algorithm has been suggested here:

http://lists.freedesktop.org/archives/intel-gfx/2015-June/068821.html

This also makes two functions static, that are not used outside of their
.c files.

src/login/logind-button.c
src/login/logind-core.c
src/login/logind-dbus.c
src/login/logind.h

index 8079d0b5aa93231341570bfbb1386becae99edf2..210b889c4f987cd7998b38ac69e0578c77e98603 100644 (file)
@@ -100,7 +100,7 @@ static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
         assert(manager);
 
         /* If we are docked, handle the lid switch differently */
         assert(manager);
 
         /* If we are docked, handle the lid switch differently */
-        if (manager_is_docked_or_multiple_displays(manager))
+        if (manager_is_docked_or_external_displays(manager))
                 handle_action = manager->handle_lid_switch_docked;
         else
                 handle_action = manager->handle_lid_switch;
                 handle_action = manager->handle_lid_switch_docked;
         else
                 handle_action = manager->handle_lid_switch;
index 44cae8963cc991fa9d64a718e6d40ea3b2f02029..e1e288f0fe574b350c79cca1454c591d0a0ee91e 100644 (file)
@@ -429,7 +429,7 @@ static int vt_is_busy(unsigned int vtnr) {
         return r;
 }
 
         return r;
 }
 
-bool manager_is_docked(Manager *m) {
+static bool manager_is_docked(Manager *m) {
         Iterator i;
         Button *b;
 
         Iterator i;
         Button *b;
 
@@ -440,7 +440,7 @@ bool manager_is_docked(Manager *m) {
         return false;
 }
 
         return false;
 }
 
-int manager_count_displays(Manager *m) {
+static int manager_count_external_displays(Manager *m) {
         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
         struct udev_list_entry *item = NULL, *first = NULL;
         int r;
         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
         struct udev_list_entry *item = NULL, *first = NULL;
         int r;
@@ -462,7 +462,8 @@ int manager_count_displays(Manager *m) {
         udev_list_entry_foreach(item, first) {
                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
                 struct udev_device *p;
         udev_list_entry_foreach(item, first) {
                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
                 struct udev_device *p;
-                const char *status;
+                const char *status, *enabled, *dash, *nn, *i;
+                bool external = false;
 
                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
                 if (!d)
 
                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
                 if (!d)
@@ -478,6 +479,40 @@ int manager_count_displays(Manager *m) {
                 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
                         continue;
 
                 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
                         continue;
 
+                nn = udev_device_get_sysname(d);
+                if (!nn)
+                        continue;
+
+                /* Ignore internal displays: the type is encoded in
+                 * the sysfs name, as the second dash seperated item
+                 * (the first is the card name, the last the connector
+                 * number). We implement a whitelist of external
+                 * displays here, rather than a whitelist, to ensure
+                 * we don't block suspends too eagerly. */
+                dash = strchr(nn, '-');
+                if (!dash)
+                        continue;
+
+                dash++;
+                FOREACH_STRING(i, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
+                               "Composite-", "SVIDEO-", "Component-",
+                               "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
+
+                        if (startswith(dash, i)) {
+                                external = true;
+                                break;
+                        }
+                }
+                if (!external)
+                        continue;
+
+                /* Ignore ports that are not enabled */
+                enabled = udev_device_get_sysattr_value(d, "enabled");
+                if (!enabled)
+                        continue;
+                if (!streq_ptr(enabled, "enabled"))
+                        continue;
+
                 /* We count any connector which is not explicitly
                  * "disconnected" as connected. */
                 status = udev_device_get_sysattr_value(d, "status");
                 /* We count any connector which is not explicitly
                  * "disconnected" as connected. */
                 status = udev_device_get_sysattr_value(d, "status");
@@ -488,7 +523,7 @@ int manager_count_displays(Manager *m) {
         return n;
 }
 
         return n;
 }
 
-bool manager_is_docked_or_multiple_displays(Manager *m) {
+bool manager_is_docked_or_external_displays(Manager *m) {
         int n;
 
         /* If we are docked don't react to lid closing */
         int n;
 
         /* If we are docked don't react to lid closing */
@@ -499,11 +534,11 @@ bool manager_is_docked_or_multiple_displays(Manager *m) {
 
         /* If we have more than one display connected,
          * assume that we are docked. */
 
         /* If we have more than one display connected,
          * assume that we are docked. */
-        n = manager_count_displays(m);
+        n = manager_count_external_displays(m);
         if (n < 0)
                 log_warning_errno(n, "Display counting failed: %m");
         if (n < 0)
                 log_warning_errno(n, "Display counting failed: %m");
-        else if (n > 1) {
-                log_debug("Multiple (%i) displays connected.", n);
+        else if (n >= 1) {
+                log_debug("External (%i) displays connected.", n);
                 return true;
         }
 
                 return true;
         }
 
index 93711fec24a4a723515aa080012e1ff4aec55c4d..640ae92f7f9cbdb1f8de6ca0a85c0450cce51fe0 100644 (file)
@@ -258,7 +258,7 @@ static int property_get_docked(
         assert(reply);
         assert(m);
 
         assert(reply);
         assert(m);
 
-        return sd_bus_message_append(reply, "b", manager_is_docked_or_multiple_displays(m));
+        return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m));
 }
 
 static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
 }
 
 static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
index e12c59a012254880b5f663b1d92a86ba8180e791..ad437b72cb923859d01bca502e31aa707037994c 100644 (file)
@@ -156,9 +156,7 @@ int manager_get_idle_hint(Manager *m, dual_timestamp *t);
 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);
 
 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);
-bool manager_is_docked_or_multiple_displays(Manager *m);
+bool manager_is_docked_or_external_displays(Manager *m);
 
 extern const sd_bus_vtable manager_vtable[];
 
 
 extern const sd_bus_vtable manager_vtable[];