diff options
author | Benjamin Barenblat <bbaren@google.com> | 2019-10-21 10:56:55 -0400 |
---|---|---|
committer | Benjamin Barenblat <bbaren@google.com> | 2019-10-21 10:56:55 -0400 |
commit | cd8509637458c2e3ceedbe173ff20180ce0ea25a (patch) | |
tree | cd3e569be1e50a95e6af08813983e1cf308c9ae2 |
xssxss, an LD_PRELOAD to suspend XScreenSaver with XScreenSaverSuspend
-rw-r--r-- | .gitignore | 8 | ||||
-rw-r--r-- | CONTRIBUTING.md | 33 | ||||
-rw-r--r-- | LICENSE | 202 | ||||
-rw-r--r-- | Makefile | 32 | ||||
-rw-r--r-- | README.md | 54 | ||||
-rw-r--r-- | xssbase.c | 17 | ||||
-rw-r--r-- | xssbase.h | 20 | ||||
-rw-r--r-- | xsslog.c | 61 | ||||
-rw-r--r-- | xsslog.h | 27 | ||||
-rw-r--r-- | xssxss.c | 141 |
10 files changed, 595 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae5540b --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Editor backup files +*~ +\#* +.\#* +.*.swp + +*.o +*.so diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d0c4879 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +How to contribute +================= + +We'd love to accept your patches and contributions to this project. There are +just a few small guidelines you need to follow. + + +Contributor License Agreement +----------------------------- + +Contributions to this project must be accompanied by a Contributor License +Agreement. You (or your employer) retain the copyright to your contribution; +this simply gives us permission to use and redistribute your contributions as +part of the project. Head over to <https://cla.developers.google.com/> to see +your current agreements on file or to sign a new one. + +You generally only need to submit a CLA once, so if you've already submitted one +(even if it was for a different project), you probably don't need to do it +again. + + +Submitting code +--------------- + +Submit patches either via a GitHub pull request or by sending mail to +bbaren@google.com. + + +Community Guidelines +-------------------- + +This project follows +[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/). @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..05b4a83 --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +CPPFLAGS = -D_GNU_SOURCE +CFLAGS = -O2 -flto -Wall -Werror=format-security -fvisibility=hidden -fpic -pthread +LDFLAGS = -Wl,-O2 -flto -Wl,-z,relro -Wl,-z,now -fpic -pthread -shared -s +LDLIBS = -lX11 -ldl + +.PHONY: all +all: libxssxss.so + +libxssxss.so: xssbase.o xsslog.o xssxss.o + $(LINK.o) $^ $(LDLIBS) -o $@ + +xssbase.o: xssbase.c xssbase.h +xsslog.o: xsslog.c xssbase.h xsslog.h +xssxss.o: xssxss.c xssbase.h xsslog.h + +.PHONY: clean +clean: + $(RM) xssbase.o xsslog.o xssxss.o libxssxss.so diff --git a/README.md b/README.md new file mode 100644 index 0000000..cd83dcf --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +xssxss +====== + +Normally, [Chrome](https://www.google.com/chrome/) pauses your screensaver while +you’re watching video. If you use [xmonad](https://xmonad.org/) and +[XScreenSaver](https://www.jwz.org/xscreensaver/) together, though, it won’t. +xssxss fixes this behavior; simply run + + make + LD_PRELOAD=$PWD/libxssxss.so google-chrome + +and ta-da, Chrome will disable your screensaver like it’s supposed to. + +Motivation +---------- + +Chromium disables the screensaver through D-Bus. Neither XScreenSaver nor xmonad +implements a D-Bus interface, so [Chromium falls back][XSSSuspendSet] to calling +[`XScreenSaverSuspend`][Xss(3)]. Despite its name, this is an X library function +and [completely unrelated to XScreenSaver][Ubuntu 718176 comment 3], so +XScreenSaver never picks up on it and remains active. + +xssxss (“`XScreenSaver`/XScreenSaver”) translates between X’s `XScreenSaver` +functions and XScreenSaver’s interface by executing `xdg-screensaver reset` when +Chrome calls `XScreenSaverSuspend`. + +[Ubuntu 718176 comment 3]: https://bugs.launchpad.net/ubuntu/+source/xscreensaver/+bug/718176/comments/3 +[XSSSuspendSet]: https://cs.chromium.org/chromium/src/services/device/wake_lock/power_save_blocker/power_save_blocker_x11.cc?l=225&rcl=2edab67ba89b69c8b6117440faf1b8397a62ace6 +[Xss(3)]: https://www.x.org/releases/X11R7.7/doc/man/man3/Xss.3.xhtml + +Future work +----------- + +Ideally, users would be able to control XScreenSaver using D-Bus. However, I +think adding a D-Bus dependency to XScreenSaver is not the best approach; +instead, someone should write an adapter daemon that implements [a reasonable +D-Bus interface][idle-inhibition-spec] and executes `xscreensaver-command` to +control XScreenSaver. + +Once that daemon’s written, Chromium will need to use it. There are multiple +D-Bus interfaces for disabling various screensavers, and Chromium [currently +picks based on the running desktop environment][SelectAPI]. Chromium will need +modification to probe the available interfaces on the bus and select an +appropriate one. There’s a [`TODO` to this effect][SelectAPI TODO], which +suggests the project would be receptive to a patch. + +[idle-inhibition-spec]: https://people.freedesktop.org/~hadess/idle-inhibition-spec/re01.html +[SelectAPI]: https://cs.chromium.org/chromium/src/services/device/wake_lock/power_save_blocker/power_save_blocker_x11.cc?l=450&rcl=fdece9dd1e1f7840a643c85e2d89f356b153fe2c +[SelectAPI TODO]: https://cs.chromium.org/chromium/src/services/device/wake_lock/power_save_blocker/power_save_blocker_x11.cc?l=447-448&rcl=999b2f18d8c62250dd19c85f6c2bb370e68fba8f + +Disclaimer +---------- + +This is not an official Google product. diff --git a/xssbase.c b/xssbase.c new file mode 100644 index 0000000..f8b8055 --- /dev/null +++ b/xssbase.c @@ -0,0 +1,17 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "xssbase.h" + +const char kProjectName[] = "xssxss"; diff --git a/xssbase.h b/xssbase.h new file mode 100644 index 0000000..ec3ea87 --- /dev/null +++ b/xssbase.h @@ -0,0 +1,20 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#pragma once + +#define LOCAL __attribute__((visibility("hidden"))) +#define PUBLIC __attribute__((visibility("default"))) + +LOCAL extern const char kProjectName[]; diff --git a/xsslog.c b/xsslog.c new file mode 100644 index 0000000..e6d7a63 --- /dev/null +++ b/xsslog.c @@ -0,0 +1,61 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "xsslog.h" + +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void StrAppend4(char target[], const char a[], const char b[], + const char c[], const char d[]) { + stpcpy(stpcpy(stpcpy(stpcpy(target, a), b), c), d); +} + +void CheckErrnoImpl(const bool condition, const char description[]) { + if (condition) { + return; + } + const int e = errno; + char buf[128]; + fprintf(stderr, "%s: check %s failed: %s\n", kProjectName, description, + strerror_r(e, buf, 128)); + _Exit(1); +} + +void CheckRetImpl(const int e, const char description[]) { + if (e == 0) { + return; + } + char buf[128]; + fprintf(stderr, "%s: %s failed: %s\n", kProjectName, description, + strerror_r(e, buf, 128)); + _Exit(1); +} + +void LogDebug(const char* const format, ...) { + const char colon_space[] = ": "; + char* const prefixed_format = + calloc(strlen(kProjectName) + strlen(colon_space) + strlen(format) + 2, + sizeof(char)); + CHECK_ERRNO(prefixed_format != NULL); + StrAppend4(prefixed_format, kProjectName, ": ", format, "\n"); + va_list args; + va_start(args, format); + vfprintf(stderr, prefixed_format, args); + va_end(args); + free(prefixed_format); +} diff --git a/xsslog.h b/xsslog.h new file mode 100644 index 0000000..cc897c5 --- /dev/null +++ b/xsslog.h @@ -0,0 +1,27 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#pragma once + +#include <stdbool.h> + +#include "xssbase.h" + +LOCAL void CheckErrnoImpl(const bool condition, const char description[]); +#define CHECK_ERRNO(condition) (CheckErrnoImpl((condition), #condition)) + +LOCAL void CheckRetImpl(const int, const char description[]); +#define CHECK_RET(call) (CheckRetImpl((call), #call)) + +LOCAL void LogDebug(const char* const format, ...); diff --git a/xssxss.c b/xssxss.c new file mode 100644 index 0000000..17966de --- /dev/null +++ b/xssxss.c @@ -0,0 +1,141 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include <stdbool.h> +#include <stddef.h> +#include <string.h> + +#include <X11/Xlib.h> +#include <dlfcn.h> +#include <pthread.h> +#include <signal.h> +#include <spawn.h> +#include <unistd.h> + +#include "xssbase.h" +#include "xsslog.h" + +static const int kWakeupSeconds = 10; + +// Runs `xdg-screensaver reset` every `kWakeupSeconds` seconds. +static void* WakerThreadMain(void* const ignored) { + // We'd like the new process to start with all signals in the default state. + // Set up the appropriate attributes to pass to `posix_spawn`. + sigset_t sigset; + posix_spawnattr_t attr; + CHECK_RET(posix_spawnattr_init(&attr)); + CHECK_ERRNO(sigfillset(&sigset) == 0); + CHECK_RET(posix_spawnattr_setsigdefault(&attr, &sigset)); + CHECK_ERRNO(sigemptyset(&sigset) == 0); + CHECK_RET(posix_spawnattr_setsigmask(&attr, &sigset)); + CHECK_RET(posix_spawnattr_setflags( + &attr, POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK)); + + while (true) { + LogDebug("resetting screensaver"); + + // Start the process to wake up xscreensaver. When it exits, we'll get + // SIGCHLD, but we don't care; see notes in `SpawnWakerThread`. + pid_t waker_pid; + char* const waker[] = {"xdg-screensaver", "reset", NULL}; + const int e = posix_spawnp(&waker_pid, waker[0], /*file_action=*/NULL, + &attr, waker, environ); + if (e != 0) { + char buf[128]; + LogDebug("failed to spawn waker: %d", strerror_r(e, buf, 128)); + } + sleep(kWakeupSeconds); + } + + CHECK_RET(posix_spawnattr_destroy(&attr)); + return NULL; +} + +// Starts a new thread at `WakerThreadMain`. +static pthread_t SpawnWakerThread(void) { + // We'd like the new thread to start with all signals masked. The new thread + // inherits the state of our signal mask, so we need to temporarily mask off + // all signals before we call pthread_create. + // + // The new thread is going to be launching new processes, so you might think + // we should attract `SIGCHLD` to it. If this process has left the `SIGCHLD` + // handler at its default (i.e., to ignore it), this isn't necessary. If, on + // the other hand, this process has some thread with an actual `SIGCHLD` + // handler, we're screwed: that handler's going to get called spuriously when + // the new thread's child exits, and attracting `SIGCHLD` to the new thread + // won't solve that problem (the kernel will deliver the signal to an + // arbitrary thread that accepts it, so the original `SIGCHLD` handler might + // get called anyway). Hope that this process has no `SIGCHLD` handler active, + // and just ignore it. + sigset_t parent, child; + CHECK_ERRNO(sigfillset(&child) == 0); + CHECK_ERRNO(pthread_sigmask(SIG_SETMASK, &child, &parent) == 0); + + pthread_t thread; + CHECK_ERRNO(pthread_create(&thread, /*attr=*/NULL, WakerThreadMain, + /*arg=*/NULL) == 0); + + CHECK_ERRNO(pthread_sigmask(SIG_SETMASK, &parent, /*oldset=*/NULL) == 0); + return thread; +} + +static void CancelThread(const pthread_t thread) { + CHECK_ERRNO(pthread_cancel(thread) == 0); + CHECK_ERRNO(pthread_join(thread, /*retval=*/NULL) == 0); +} + +// This function must be thread-safe (it overrides a function that is also +// thread-safe.) +PUBLIC void XScreenSaverSuspend(Display* const display, const Bool suspend) { + // These variables are guarded by the Xlib display lock. The real + // XScreenSaverSuspend also locks the Xlib display, but the lock is a + // recursive mutex, so the double-locking is safe. + static void (*real_XScreenSaverSuspend)(Display*, Bool) = NULL; + static int suspends_active = 0; + static pthread_t waker_thread; + + LogDebug("%s requested", suspend ? "suspend" : "resume"); + + XLockDisplay(display); + + if (real_XScreenSaverSuspend == NULL && + (real_XScreenSaverSuspend = dlsym(RTLD_NEXT, "XScreenSaverSuspend")) == + NULL) { + // We couldn't get the real function. This isn't a huge deal, because we can + // still shut off xscreensaver, but the user probably wants to know about + // it. + LogDebug("can't forward to real XScreenSaverSuspend: %s", dlerror()); + } + + if (real_XScreenSaverSuspend != NULL) { + real_XScreenSaverSuspend(display, suspend); + } + + if (suspends_active == 0) { + if (suspend) { + LogDebug("starting waker thread"); + waker_thread = SpawnWakerThread(); + } else { + LogDebug("resume requested, but no suspends are active; ignoring"); + } + } else if (suspends_active == 1 && !suspend) { + LogDebug("canceling waker thread"); + CancelThread(waker_thread); + } + suspends_active += suspend ? 1 : -1; + LogDebug("%d suspend%s now active", suspends_active, + suspends_active == 1 ? " is" : "s are"); + + XUnlockDisplay(display); +} |