How the Omarchy Idle, Lock, and Screensaver Service Works
The Omarchy idle service monitors user input through Quickshell’s IdleMonitor and automatically triggers screensaver windows and session locks after configurable timeouts, while exposing runtime state via shell IPC for integration with status bars and scripts.
Omarchy implements its idle, lock, and screensaver functionality as a first-party service plugin (omarchy.idle) within its Quickshell-based desktop environment. The service coordinates with the lock plugin to secure the session after periods of inactivity, reading timeout values from user configuration and providing command-line controls to override behavior on demand.
Core Architecture and Configuration
The idle service is modular, separating concerns between monitoring, configuration parsing, and window management across distinct source files.
Service.qml and IdleModel.js
The primary implementation resides in shell/plugins/services/idle/Service.qml, which instantiates an IdleMonitor and manages the idle cycle timers. Helper utilities for parsing timeout strings and tracking screensaver windows live in shell/plugins/services/idle/IdleModel.js.
The service reads idle thresholds from ~/.config/omarchy/idle.json or the idle block within the global Omarchy configuration. Two critical values control behavior:
screensaver– Seconds of inactivity before the screensaver window appears.lock– Seconds of inactivity before the system locks (only triggers if the screensaver is already active).
{
"idle": {
"screensaver": 120,
"lock": 300
}
}
The IdleModel.secondsFromConfig() function converts these configuration values into seconds for internal timer use.
The Idle Detection Cycle
When the IdleMonitor detects no input events for the configured duration, it emits the isIdle signal. The service checks the idleEnabled property (which is false when stay-awake mode is active) before invoking startIdleCycle().
Screensaver Activation
Upon entering the idle cycle, the service starts a screensaver timer. If it expires, the service calls idle.screensaverWindowsAfter(), which creates a new window via shellApi.createWindow() and appends it to the screensaverWindows list. The screensaverWindowCount property increments, allowing UI components like the status bar to reflect active screensaver states.
Automatic Locking
A separate lock timer runs concurrently. When this timer fires—only if the screensaver is already showing—the service invokes root.lockSystem("lock-timeout"). This delegates to shell/plugins/lock/Service.qml, which blanks the screen and prompts for authentication via its idleBlankTimer.
Wake-Up and Reset
Any user activity (mouse or keyboard) resets the IdleMonitor, which triggers cancelIdleCycle(). This function destroys all screensaver windows by clearing root.screensaverWindows = {}, cancels both timers, and resets flags like screensaverStartedThisCycle.
State Management and IPC Interface
The service exposes its runtime state through the shell IPC interface, accessible via the shell_ipc command:
shell_ipc idle status | jq .
This returns a JSON object containing idleEnabled, stayAwake, screensaverStartedThisCycle, and screensaverWindowCount. The bar indicator at shell/plugins/bar/indicators/StayAwake.qml consumes these properties to display whether idle detection is currently active.
CLI Control and User Interaction
Users can override idle behavior without modifying configuration files using the omarchy-toggle-idle utility.
Prevent the screensaver and lock from triggering:
omarchy-toggle-idle stay-awake
Re-enable normal idle handling:
omarchy-toggle-idle allow-idle
These commands toggle the stayAwake flag, which sets idleEnabled to false within Service.qml, effectively pausing the idle monitor until explicitly re-enabled.
Summary
- The idle service is implemented in
shell/plugins/services/idle/Service.qmlwith helpers inIdleModel.js. - Configuration resides in
~/.config/omarchy/idle.json, definingscreensaverandlocktimeouts. - The IdleMonitor triggers
startIdleCycle(), which schedules screensaver windows first, then locks the session viashell/plugins/lock/Service.qml. - The lock only activates if the screensaver is already visible and the lock timeout expires.
- Use
omarchy-toggle-idleto temporarily disable idle detection, and query state withshell_ipc idle status.
Frequently Asked Questions
How do I check if the idle service is currently enabled?
Run shell_ipc idle status from a terminal. The JSON output includes the idleEnabled boolean (which is false when stay-awake mode is active) and the current window count, allowing you to verify whether the service is monitoring inactivity or suspended.
Why does the lock only trigger after the screensaver appears?
According to the implementation in Service.qml, the lock timer only fires if screensaverStartedThisCycle is true. This ensures the screensaver acts as a visual warning before the session locks, preventing immediate lockouts during brief periods of inactivity.
Can I create custom screensaver windows?
Yes. Create a QML window that registers itself via idle.screensaverWindowsAfter(). The idle service automatically manages the lifecycle of these windows, destroying them when cancelIdleCycle() runs due to user activity or manual wake commands.
Where does the lock logic actually execute?
While Service.qml in the idle plugin initiates the lock via lockSystem("lock-timeout"), the actual screen blanking and authentication prompt are handled by shell/plugins/lock/Service.qml, which receives the call through the shell’s plugin communication layer.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →