Skip to content

About

A compact C++ service for idle detection on a Linux workstation

Resources

Stars

4 stars

Watchers

3 watching

Forks

Latest commit

 

History

273 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

idle_detect

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.

Installation

Two paths: install a pre-built package for your distribution (preferred) or compile locally.

A. Packages (preferred)

openSUSE, Fedora, Arch Linux

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).

Debian, Ubuntu

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 pull

Signature verification: SHA256SUMS.txt is published alongside each release.

Post-install activation

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.service

To verify both services:

systemctl status dc_event_detection          # system
systemctl --user status dc_idle_detection    # user

Configuration

  • System config: /etc/event_detect.conf (edit as root, then sudo systemctl restart dc_event_detection)
  • User config: ~/.config/idle_detect.conf (auto-created on first run, then systemctl --user restart dc_idle_detection after 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_t domain. Querying the compiled policy on openSUSE Leap 16.0 shows boinc_t is granted only getattr on a tmpfs_t file it did not create — no open, no read — while /dev/shm/idle_detect_shmem is plain tmpfs_t (no fcontext rule exists for it). Since shm_open() is an open(), the read is denied.

The failure is silent: BOINC can search /dev/shm and getattr the 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=0

It is dontaudit-suppressed, so ausearch -m AVC shows nothing; it only appears after semodule -DB or 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 undo

It installs a small policy module granting boinc_t open/read on tmpfs_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=1 and use the bundled scripts regardless of BOINC version — boinccmd runs 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=1 enabled by default. Package managers preserve idle_detect.conf across 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.conf manually.

Architecture

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_detect instances via named pipe
  • Exports aggregated last_active_time as /idle_detect_shmem (two int64_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.ksmserver GetSessionIdleTime (includes inhibit propagation)
    • KDE Wayland / Plasma 6: ext_idle_notifier_v1 + D-Bus PowerManagement inhibit 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_detect decides
  • 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_detect via named pipe as timestamp:USER_ACTIVE messages

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.

Local compilation

If no package is available for your distribution, build from source. A C++17-capable compiler is required (GCC 9+ or Clang 10+).

Quick build

# 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 gtest

Then:

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.

Documentation

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

Branching and releases

  • development — active development
  • master — releases and pre-release tags

Packages published to OBS and attached to GitHub releases are built from master tags.

License

MIT. See LICENSE.md.

About

A compact C++ service for idle detection on a Linux workstation

Resources

Stars

4 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages