[systemd-devel] improve lid switch event handling

2014-07-22 Thread Thomas Blume

The current inhibitors for going into suspend at lid closure are based on the
presence of a docking station, multiple or no displays and a fixed timeout
after the last suspend event.
I understand the goal to prevent an immediate suspend when the system is booted
with closed lid and other inhibitors are not yet present.

But, ignoring the lid close event for a certain time, might not give the
best user experience.
I wondering wheter we couldn't set the inhibitors in a more userfriendly way.

My approach is based on the assumption that a user only wants a suspend at lid
closure, if there was a lid open before.
If the lid was not opened before, we can IMHO savely assume that there is
another display connected or there is a docking station or the user just want
to boot without display for any reason.

If so, we could record a previous lid open event e.g. in a status file.
We could then inhibit the suspend if there was no previous lid open event or
 allow it without timeout, if there was one.

I'm attaching a little example patch to visualize my approach.
Any comment is appreciated.


Regards
Thomas Blume

--
SUSE LINUX Products GmbH GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer, HRB 
16746 (AG Nürnberg)
Maxfeldstr. 5 / D-90409 Nürnberg / Phone: +49-911-740 53 - 0
GPG 2048R/2CD4D3E8 9A50 048F 1C73 59AA 4D2E  424E B3C6 3FD9 2CD4 D3E8diff --git a/src/login/logind-button.c b/src/login/logind-button.c
index 2561d13..43d645d 100644
--- a/src/login/logind-button.c
+++ b/src/login/logind-button.c
@@ -32,6 +32,8 @@
 #include "util.h"
 #include "special.h"
 #include "logind-button.h"
+#include 
+#include 
 
 Button* button_new(Manager *m, const char *name) {
 Button *b;
@@ -99,11 +101,21 @@ int button_set_seat(Button *b, const char *sn) {
 
 static int button_recheck(sd_event_source *e, void *userdata) {
 Button *b = userdata;
+struct stat st;
 
 assert(b);
 assert(b->lid_closed);
 
-manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false);
+if (stat("/run/systemd/systemd-lid-opened", &st) == 0) {
+int r;
+
+if (unlink("/run/systemd/systemd-lid-opened") < 0) {
+log_error("Failed to remove /run/systemd/systemd-lid-opened file: %m");
+r = -errno;
+}
+manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false);
+}
+
 return 1;
 }
 
@@ -125,7 +137,7 @@ static int button_install_check_event_source(Button *b) {
 
 static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
 Button *b = userdata;
-struct input_event ev;
+struct input_event ev, stat st;
 ssize_t l;
 
 assert(s);
@@ -186,7 +198,17 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
NULL);
 
 b->lid_closed = true;
-manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
+
+if (stat("/run/systemd/systemd-lid-opened", &st) == 0) {
+int r;
+
+if (unlink("/run/systemd/systemd-lid-opened") < 0) {
+log_error("Failed to remove /run/systemd/systemd-lid-opened file: %m");
+r = -errno;
+}
+manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true);
+}
+
 button_install_check_event_source(b);
 
 } else if (ev.code == SW_DOCK) {
@@ -201,12 +223,21 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
 } else if (ev.type == EV_SW && ev.value == 0) {
 
 if (ev.code == SW_LID) {
+_cleanup_fclose_ FILE *f = NULL;
 log_struct(LOG_INFO,
"MESSAGE=Lid opened.",
MESSAGE_ID(SD_MESSAGE_LID_OPENED),
NULL);
 
 b->lid_closed = false;
+
+//save lid open state
+f = fopen("/run/systemd/systemd-lid-opened", "we");
+if (!f) {
+log_error("Failed to write Lid state file: %m");
+return -errno;
+}
+
 b->check_event_source = sd_event_source_unref(b->check_event_source);
 
 } else if (ev.code ==

Re: [systemd-devel] improve lid switch event handling

2014-07-23 Thread Lennart Poettering
On Tue, 22.07.14 12:35, Thomas Blume (thomas.bl...@suse.com) wrote:

> If so, we could record a previous lid open event e.g. in a status file.
> We could then inhibit the suspend if there was no previous lid open event or
>  allow it without timeout, if there was one.

Not following here... Note that the lid switch is actually an input
"switch" exposed by the kernel, not a "key". This means that it is a
binary thing anyway, and lid switch close events are never generated
when the device is already closed...

I am also pretty sure we should always react to lid switch state. Many
laptops have a power button accessible even if the device is closed (in
particular all "convertible" devices, such as the Lenovo Yoga I
have). Devices like that are prone to "accidental" resumes in backpacks
and such (because something presses on the power button), and we want
them to go back to suspend again, so that they don't stay on forever in
the backpack.

It's really annoying that we have to employ a timeout though before
going back to suspend. This is required because there's no point in time
when USB devices have to have shown up, and we want to allow USB docking
stations with VGA to block the suspend...

Lennart

-- 
Lennart Poettering, Red Hat
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel