xautolock-inhibit
Makes screen locking with xautolock respect the "don't lock the screen" requests that apps send, on X11 sessions without a desktop environment (for example a plain window manager like xmonad).
Browsers, Steam, gamemode and other apps ask the desktop not to lock or blank the screen while a video or game is running, through the D-Bus service org.freedesktop.ScreenSaver. Without a desktop environment nothing provides that service, so the requests are dropped and the screen locks in the middle of a video. xautolock-inhibit provides it:
- While at least one request is active, it runs
xautolock -disableand pauses X screen blanking and DPMS. - When the last request is released, it waits a few seconds, then runs
xautolock -enableand resumes blanking.
xautolock stays your locker; xautolock-inhibit only switches it off and on.
How it works
- Owns
org.freedesktop.ScreenSaveron the session bus at both/org/freedesktop/ScreenSaverand/ScreenSaver(apps differ on the path), and implementsInhibitandUnInhibit. - Tracks requests per D-Bus client. If a client disconnects without releasing them (for example a browser crash), its requests are released.
- Runs
xautolockonly when the number of active requests goes from 0 to 1 or back to 0. Re-enabling waits a few seconds (--release-delay), because browsers send short bursts of requests when a video starts. - Pauses X blanking with
XScreenSaverSuspend, the same mechanism mpv uses, instead of changingxsetsettings. The X server ends the pause by itself if the daemon exits or crashes. - Requests whose reason is on an ignore list (default:
Playing audio) are accepted and logged, but don't block locking. Firefox-based browsers send one for audio playback, which would otherwise keep the screen unlocked while music plays with nobody at the computer. - Keeps the requests it holds in
$XDG_RUNTIME_DIR/xautolock-inhibit.json, so a restarted or crashed daemon takes them over. They are taken over only if the previous daemon stopped at most 30 seconds ago (--restore-window) on the same session bus, and only for clients still connected. A request released while no daemon was running can't be seen, so an old file isn't trusted. - On exit (including SIGTERM), it re-enables xautolock. The systemd unit also runs
xautolock -enablewhen it stops, as a fallback. - If another program (a desktop environment) already owns
org.freedesktop.ScreenSaver, it exits with status 2 instead of taking over.
Requirements
xautolock, already running in the sessionpython,python-gobjectlibx11,libxss
Installation
Build and install the package with the included PKGBUILD:
makepkg -si
Then start it from your window manager's startup, after xautolock. For xmonad:
spawnOnce "xautolock -time 10 -locker slock -detectsleep"
spawnOnce "systemctl --user start xautolock-inhibit"
The unit has no [Install] section on purpose. Enabling it at login would also start it in a desktop environment, or before X is up; starting it from the window manager limits it to that session. The user service manager needs DISPLAY (and XAUTHORITY) in its environment, which /etc/X11/xinit/xinitrc.d/50-systemd-user.sh sets up for startx sessions.
Usage
xautolock-inhibit [-i REASON] [--count-all] [-d SECONDS] [--restore-window SECONDS]
-i,--ignore-reason REASON: request reason that doesn't block locking. Can be repeated; replaces the default (Playing audio).--count-all: every request blocks locking; no reasons are ignored.-d,--release-delay SECONDS: wait this long after the last release before re-enabling xautolock (default 5).--restore-window SECONDS: take over requests from a previous daemon that stopped at most this long ago (default 30; 0 disables).
To change the options used by the service:
systemctl --user edit xautolock-inhibit.service
[Service]
ExecStart=
ExecStart=/usr/bin/xautolock-inhibit --count-all
Every request, release and xautolock call is logged to the journal:
journalctl --user -u xautolock-inhibit
App notes
-
Sandboxed apps may be blocked from reaching the service. For a firejail profile that filters D-Bus (
dbus-user filter, as the Firefox-based profiles do), allow it in the app's.localfile, e.g.zen-browser.local:dbus-user.talk org.freedesktop.ScreenSaver -
Games: Steam's overlay and gamemode (
inhibit_screensaver=1) send requests on their own. -
scrcpy only sends a request when started with
--disable-screensaver. -
mpv talks to the X server directly and doesn't need this daemon.
Limitations
- A release sent while the daemon is down is lost: if the daemon is back within
--restore-window, that request stays active until its app exits. After a longer stop, all held requests are dropped and apps don't send them again. SimulateUserActivityis accepted but does nothing. Calls are logged once when a client starts sending them and once, with a count, after 5 minutes without any.GetActivealways returnsfalse.
License
GPL-3.0-or-later. See LICENSE.