From 6a32252403781b303d4ebd195932ce39c5b1c08e Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 30 Jul 2019 16:03:58 +0200 Subject: Update to 5.43 --- driver/xscreensaver-systemd.c | 232 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 driver/xscreensaver-systemd.c (limited to 'driver/xscreensaver-systemd.c') diff --git a/driver/xscreensaver-systemd.c b/driver/xscreensaver-systemd.c new file mode 100644 index 0000000..a46ed4d --- /dev/null +++ b/driver/xscreensaver-systemd.c @@ -0,0 +1,232 @@ +/* xscreensaver-systemd, Copyright (c) 2019 Martin Lucina + * + * ISC License + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * This is a small utility providing systemd integration for XScreenSaver. + * + * When run from ~/.xsession or equivalent, this will: + * + * - Lock the screen before the system goes to sleep (using + * xscreensaver-command -suspend). + * + * - Ensure the XScreenSaver password dialog is shown after the system + * is resumed (using xscreensaver-command -deactivate). + * + * This is implemented using the recommended way to do these things + * nowadays, namely inhibitor locks. sd-bus is used for DBUS communication, + * so the only dependency is libsystemd (which you already have if you + * want this). + * + * https://github.com/mato/xscreensaver-systemd + */ + +#include +#include +#include +#include +#include +#include + +#include + +struct handler_ctx { + sd_bus *bus; + sd_bus_message *lock; +}; +static struct handler_ctx global_ctx = { NULL, NULL }; + +static int handler(sd_bus_message *m, void *arg, + sd_bus_error *ret_error) +{ + struct handler_ctx *ctx = arg; + int before_sleep; + int rc; + sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus_message *reply = NULL; + int fd; + + rc = sd_bus_message_read(m, "b", &before_sleep); + if (rc < 0) { + warnx("Failed to read message: %s", strerror(-rc)); + return 0; + } + + /* Use the scheme described at + * https://www.freedesktop.org/wiki/Software/systemd/inhibit/ + * under "Taking Delay Locks". + */ + if (before_sleep) { + rc = system("xscreensaver-command -suspend"); + if (rc == -1) { + warnx("Failed to run xscreensaver-command"); + } + else if (WEXITSTATUS(rc) != 0) { + warnx("xscreensaver-command failed with %d", WEXITSTATUS(rc)); + } + + if (ctx->lock) { + /* + * This will release the lock, since we hold the only ref to the + * message, and sd_bus_message_unref() will close the underlying + * fd. + */ + sd_bus_message_unref(ctx->lock); + ctx->lock = NULL; + } + else { + warnx("Warning: ctx->lock is NULL, this should not happen?"); + } + } + else { + rc = system("xscreensaver-command -deactivate"); + if (rc == -1) { + warnx("Failed to run xscreensaver-command"); + } + else if (WEXITSTATUS(rc) != 0) { + warnx("xscreensaver-command exited with %d", WEXITSTATUS(rc)); + } + + rc = sd_bus_call_method(ctx->bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "Inhibit", + &error, + &reply, + "ssss", + "sleep", + "xscreensaver", + "lock screen on suspend", + "delay"); + if (rc < 0) { + warnx("Failed to call Inhibit(): %s", error.message); + goto out; + } + /* + * Verify that the reply actually contains a lock fd. + */ + rc = sd_bus_message_read(reply, "h", &fd); + if (rc < 0) { + warnx("Failed to read message: %s", strerror(-rc)); + goto out; + } + assert(fd >= 0); + ctx->lock = reply; + +out: + sd_bus_error_free(&error); + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + sd_bus *bus = NULL, *user_bus = NULL; + sd_bus_slot *slot = NULL; + struct handler_ctx *ctx = &global_ctx; + sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus_message *reply = NULL; + int rc; + int fd; + const char *match = + "type='signal',interface='org.freedesktop.login1.Manager'" + ",member='PrepareForSleep'"; + + rc = sd_bus_open_user(&user_bus); + if (rc < 0) { + warnx("Failed to connect to user bus: %s", strerror(-rc)); + goto out; + } + rc = sd_bus_request_name(user_bus, "org.jwz.XScreenSaver", 0); + if (rc < 0) { + warnx("Failed to acquire well-known name: %s", strerror(-rc)); + warnx("Is another copy of xscreensaver-systemd running?"); + goto out; + } + + rc = sd_bus_open_system(&bus); + if (rc < 0) { + warnx("Failed to connect to system bus: %s", strerror(-rc)); + goto out; + } + ctx->bus = bus; + + rc = sd_bus_call_method(bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "Inhibit", + &error, + &reply, + "ssss", + "sleep", + "xscreensaver", + "lock screen on suspend", + "delay"); + if (rc < 0) { + warnx("Failed to call Inhibit(): %s", error.message); + goto out; + } + /* + * Verify that the reply actually contains a lock fd. + */ + rc = sd_bus_message_read(reply, "h", &fd); + if (rc < 0) { + warnx("Failed to read message: %s", strerror(-rc)); + goto out; + } + assert(fd >= 0); + ctx->lock = reply; + + rc = sd_bus_add_match(bus, &slot, match, handler, &global_ctx); + if (rc < 0) { + warnx("Failed to add match: %s", strerror(-rc)); + goto out; + } + + for (;;) { + rc = sd_bus_process(bus, NULL); + if (rc < 0) { + warnx("Failed to process bus: %s", strerror(-rc)); + goto out; + } + if (rc > 0) + /* we processed a request, try to process another one, right-away */ + continue; + + /* Wait for the next request to process */ + rc = sd_bus_wait(bus, (uint64_t) -1); + if (rc < 0) { + warnx("Failed to wait on bus: %s", strerror(-rc)); + goto out; + } + } + +out: + if (reply) + sd_bus_message_unref(reply); + if (slot) + sd_bus_slot_unref(slot); + if (bus) + sd_bus_flush_close_unref(bus); + if (user_bus) + sd_bus_flush_close_unref(user_bus); + sd_bus_error_free(&error); + + return EXIT_FAILURE; +} -- cgit v1.2.3-55-g7522