A compact C++17 idle-detection service for Linux, built to solve the
long-standing idle-detection issues in BOINC and other distributed
computing clients. Runs as a two-tier service: a system-level daemon
aggregates raw input activity, and a per-user daemon handles
session-aware idle time with desktop inhibit propagation (KDE, GNOME,
Wayland via ext_idle_notifier_v1, X11 via XScreenSaver).
Activity state is published for any DC client to read, and bundled control scripts can drive BOINC and Folding@home (both the v7 and v8 clients) directly when a client cannot read it for itself.
Status: stable for daily use. Please file issues on GitHub for bugs or unsupported desktop configurations.
Two paths: install a pre-built package for your distribution (preferred) or compile locally.
Pick your distribution from the one-click install page:
https://software.opensuse.org//download.html?project=home%3Ajamescowens&package=idle_detect
Coverage: openSUSE Leap 15.6, Leap 16.0, Tumbleweed; Fedora 38–43 and Rawhide; Arch Linux. Multiple architectures depending on distribution (x86_64, aarch64, i586, armv7l, ppc64le).
Download the appropriate .deb for your codename and architecture from
the latest GitHub release:
https://github.com/jamescowens/idle_detect/releases
Coverage: Debian bookworm, trixie; Ubuntu jammy (22.04), noble (24.04), plucky (25.04). Architectures: amd64, arm64, armhf. Example:
sudo dpkg -i idle-detect_<version>.<codename>_<arch>.deb
sudo apt-get install -f # resolve any dependencies dpkg didn't pullSignature verification: SHA256SUMS.txt is published alongside each
release.
After the package is installed, the system service (dc_event_detection)
starts automatically via the system preset — no action needed.
The user service (dc_idle_detection) is enabled via the user preset,
but only takes effect for user sessions that start after package
install. To light it up in your current session without logging out:
systemctl --user daemon-reload
systemctl --user enable --now dc_idle_detection.serviceTo verify both services:
systemctl status dc_event_detection # system
systemctl --user status dc_idle_detection # user- System config:
/etc/event_detect.conf(edit as root, thensudo systemctl restart dc_event_detection) - User config:
~/.config/idle_detect.conf(auto-created on first run, thensystemctl --user restart dc_idle_detectionafter edits)
By default idle_detect does not call the DC-control scripts. It
publishes activity state to event_detect, which exports
/idle_detect_shmem and /run/event_detect/last_active_time.dat. A DC
client that reads either of those can decide for itself when to pause.
If your DC client does not read the shared memory segment directly —
including BOINC versions before 8.2.10, and Folding@home at any
version — enable the bundled scripts: set
execute_dc_control_scripts=1 in ~/.config/idle_detect.conf and
systemctl --user restart dc_idle_detection.
dc_pause and dc_unpause handle BOINC and Folding@home
independently. Each is attempted only if present, and the absence or
failure of one never prevents the other:
| client | how it is driven |
|---|---|
| BOINC | boinccmd --set_run_mode never / always |
| Folding@home v7 | FAHClient --send-pause / --send-unpause |
| Folding@home v8 | dc_fah_v8, bundled (see below) |
Folding@home v8 ships no command-line control, so dc_fah_v8 speaks
the client's local WebSocket API on 127.0.0.1:7396 using only the
Python 3 standard library — no pip, no fahctl. It stays on this
machine and never involves the hosted web control. It confirms the
client actually changed state rather than trusting an exit code, and
fails loudly if it cannot.
Behavior can be adjusted without editing the scripts:
| variable | effect |
|---|---|
BOINC_DATA_DIR |
BOINC data directory, skipping the probe |
DC_PAUSE_BOINC=0 |
leave BOINC alone |
DC_PAUSE_FAH=0 |
leave Folding@home alone |
DC_FAH_CLIENT |
force v7 or v8 instead of auto-detecting |
If BOINC is installed but its gui_rpc_auth.cfg is unreadable — the
usual root:boinc 0640 — the scripts say so rather than skipping
silently. Add your user to the boinc group to fix it.
BOINC 8.2.10 and later read /idle_detect_shmem directly; for those
the shipped default (scripts disabled) is correct, except on SELinux
systems — see the note below.
On SELinux systems, the shared-memory path is currently blocked. Fedora and openSUSE (Leap 16.0 and Tumbleweed on fresh installs) run SELinux in enforcing mode with a confined
boinc_tdomain. Querying the compiled policy on openSUSE Leap 16.0 showsboinc_tis granted onlygetattron atmpfs_tfile it did not create — noopen, noread— while/dev/shm/idle_detect_shmemis plaintmpfs_t(no fcontext rule exists for it). Sinceshm_open()is anopen(), the read is denied.The failure is silent: BOINC can search
/dev/shmandgetattrthe segment, so it fails at open rather than at discovery, and simply never observes user activity.Confirmed in practice on openSUSE Leap 16.0 with BOINC 8.2.15, which the BOINC project publishes as a GitHub release asset (
boinc-client-8.2.15-4612.x86_64_suse16_0.rpm). The exact denial is:avc: denied { read } for comm="boinc" name="idle_detect_shmem" dev="tmpfs" scontext=system_u:system_r:boinc_t:s0 tcontext=system_u:object_r:tmpfs_t:s0 tclass=file permissive=0It is
dontaudit-suppressed, soausearch -m AVCshows nothing; it only appears aftersemodule -DBor by grepping/var/log/audit/audit.log. The user-visible symptom is BOINC recommending that you install idle_detect while idle_detect is installed and running.A workaround ships with this release. Review it, then run as root:
sudo boinc_selinux_shmem_policy.sh # --remove to undoIt installs a small policy module granting
boinc_topen/readontmpfs_t, after which BOINC maps the segment and stops logging the legacy notice. That rule is broader than ideal — the proper fix is a dedicated type for the segment, which needs coordination with distribution policy — so treat it as a stopgap until BOINC and the distributions ship policy covering this.Distribution packages are mostly still below 8.2.10 (Fedora 43/44 package 8.2.4, openSUSE Leap 16.0 packages 8.0.4), so most users will not hit this until those update. Alternatively, on an SELinux-enforcing system set
execute_dc_control_scripts=1and use the bundled scripts regardless of BOINC version —boinccmdruns as the desktop user and is unconfined, so the script path is unaffected.Check with
sestatus. Note you cannot infer this from the distribution alone: an openSUSE system manually upgraded from Leap 15.x keeps AppArmor and is not affected.
For the full list of every setting in both config files — types, defaults, interactions, common configurations — see docs/configuration.md.
Note for upgraders from 0.9.0.0. That release shipped with
execute_dc_control_scripts=1enabled by default. Package managers preserveidle_detect.confacross upgrades (it's marked as a configuration file), so existing installs keep their prior setting — your behavior does not change on upgrade. If you want the new default-off behavior, edit~/.config/idle_detect.confmanually.
Two processes, coordinated via a named pipe and POSIX shared memory:
event_detect (system daemon, event_detect:event_detect user):
- Monitors
/dev/input/event*pointing devices (catches physical mouse and keyboard activity) - Monitors pts/tty atime (catches terminal and SSH activity)
- Receives messages from per-user
idle_detectinstances via named pipe - Exports aggregated
last_active_timeas/idle_detect_shmem(twoint64_t: update timestamp and last-active timestamp, Unix epoch seconds UTC) and optionally/run/event_detect/last_active_time.dat
idle_detect (per-user daemon, one per session):
- Continuously discovers the session's idle sources rather than deciding
once at startup, so it recovers on its own when a GUI session is
logged out, crashes, or appears after the daemon has already started:
- KDE X11 / Plasma 5:
org.kde.ksmserverGetSessionIdleTime(includes inhibit propagation) - KDE Wayland / Plasma 6:
ext_idle_notifier_v1+ D-BusPowerManagementinhibit check - GNOME:
org.gnome.SessionManager.IsInhibited+ Mutter idle time - Other Wayland:
ext_idle_notifier_v1 - X11 fallback: XScreenSaver (
libXss) - TTY: no GUI source is found, so
event_detectdecides
- KDE X11 / Plasma 5:
- More than one graphical endpoint can be live at once (a Wayland compositor and its XWayland display, say). Each is validated by connecting to it, never trusted from an environment variable, and the session's idle time is the smallest value any of them reports — unless something is inhibiting idle, which wins outright.
- Reports activity to
event_detectvia named pipe astimestamp:USER_ACTIVEmessages
A DC client polls /idle_detect_shmem once a second to decide whether
to run. This resolves ≈99% of the idle-detection issues that were seen
with BOINC directly.
If no package is available for your distribution, build from source. A C++17-capable compiler is required (GCC 9+ or Clang 10+).
# Debian / Ubuntu
sudo apt-get install build-essential cmake ninja-build pkg-config \
libevdev-dev libxss-dev libdbus-1-dev libglib2.0-dev libx11-dev \
libwayland-dev libwayland-bin wayland-protocols libgtest-dev
# Fedora
sudo dnf install gcc-c++ cmake ninja-build pkgconf \
libevdev-devel libXScrnSaver-devel dbus-devel glib2-devel \
wayland-devel wayland-protocols-devel gtest-devel
# openSUSE (note: libXss-devel, NOT libXScrnSaver-devel — that name does not exist here)
sudo zypper install gcc-c++ cmake ninja pkgconf \
libevdev-devel libXss-devel dbus-1-devel glib2-devel \
wayland-devel wayland-protocols-devel gtest
# Arch
sudo pacman -S --needed base-devel cmake ninja pkgconf \
libevdev libxss dbus glib2 libx11 wayland wayland-protocols gtestThen:
git clone https://github.com/jamescowens/idle_detect.git
cd idle_detect
sudo ./install.sh # system side
./user_install.sh # user side (not sudo)For the full build guide — CMake options, manual CMake invocation, tests, sanitizer builds, developer workflow, local package builds, and troubleshooting — see docs/building.md.
| document | covers |
|---|---|
| docs/configuration.md | every setting in both config files |
| docs/building.md | build options, tests, packaging, troubleshooting |
| docs/idle_detection_logic.md | how idle time is determined per session type |
| docs/testing.md | what was tested for the current release, and what was not |
| docs/releasing.md | release checklist: version fields, packaging audit, tag, GitHub, OBS |
| docs/ROADMAP_1.0.md | planned work toward 1.0 |
development— active developmentmaster— releases and pre-release tags
Packages published to OBS and attached to GitHub releases are built
from master tags.
MIT. See LICENSE.md.