Files
moonarch/defaults/xdg/stasis/stasis.rune
T
nevaforget a172f90c1c
Update PKGBUILD version / update-pkgver (push) Successful in 5s
feat(lock): open the lock screen on the focused monitor
gtklock shows its input form on one monitor, chosen from its own -M
priority list, while niri assigns the lock screen's keyboard focus by
cursor position. Locking from any other monitor left form and focus
apart, so typing went nowhere until the mouse was moved.

moonarch-lock resolves the focused output and passes it as -M. All five
call sites go through it; "$@" is forwarded unchanged, so -d stays the
caller's decision.
2026-09-14 18:41:40 +02:00

145 lines
4.9 KiB
Plaintext

# Stasis idle manager configuration for Moonarch
# Manages screen dimming, DPMS, lock, and suspend timers
@author "Moonarch"
@description "Idle management for Moonarch (Niri + gtklock)"
# TIMEOUTS ARE CUMULATIVE, NOT ABSOLUTE.
#
# Each `timeout` counts from the moment the *previous* step in the same block
# fired, not from the last input event. Only the first step measures raw idle
# time. Verified against a running daemon: with `dpms 120` followed by
# `lock_screen 180`, dpms fired at 18:43:30 and the lock at 18:46:31 -- 181
# seconds later, not 60.
#
# This file previously carried the upstream template's numbers while reading
# them as absolute. The result was a screen that went dark after 2 minutes when
# 6 were intended, and a `brightness 300` step behind a `dpms 120` step that
# could never run, because the display was already off when its turn came.
#
# Step order inside a block is execution order. Lock before DPMS, so the
# session is already secured when the display shuts off, and the display then
# stays off instead of being lit again to show the locker.
default:
# monitor_media: detect active media via PipeWire/PulseAudio sink-inputs
# (pactl), not MPRIS. Non-browser players (mpv, vlc, ...) are counted and
# inhibit idle. Browser audio is excluded by design; browser idle-inhibit is
# expected via D-Bus (enable_dbus_inhibit), which Waterfox/Firefox only send
# in fullscreen -- so windowed browser video is NOT caught by stasis.
# ignore_remote_media false: also count remote players (Spotify-remote,
# KDEConnect, Chromecast); has no effect on windowed browser video.
monitor_media true
ignore_remote_media false
# Both empty on purpose: nothing here should keep the machine awake beyond
# what inhibit_apps already covers. They are set rather than omitted because
# stasis discards any config missing a knob its own template carries, backing
# it up and starting over from that template.
suspend_inhibit_apps [ ]
suspend_inhibit_media [ ]
# App/process inhibit patterns (apps that don't use D-Bus idle-inhibit)
inhibit_apps [
"vlc"
"mpv"
"celluloid"
r"steam_app_.*"
"gamescope"
"virt-manager"
"qemu"
"obs"
"kdenlive"
"handbrake"
"blender"
]
# Lid actions (laptop only). Locks only; the suspend on lid close comes from
# logind's HandleLidSwitch default, not from here.
lid_close_action "moonarch-lock -d"
lid_open_action ""
# Every binary named in a command below has to be on the PATH of the unit
# that starts stasis -- stasis does not run the actions through a login
# shell, so /etc/profile never applies. A missing binary fails silently: the
# step is logged as started, exits immediately, and the plan stops there.
# In moonix that PATH lives in modules/services.nix.
# Desktop plan (machines without a battery)
#
# These blocks sit directly under `default:` on purpose: stasis builds the
# desktop plan from exactly those, with the ac:/battery: containers excluded
# (src/config/mod.rs, parse_plan_block "default"). A machine whose chassis
# reports no battery gets PlanSource::Desktop, and select_plan_source only
# ever falls back *onto* the desktop plan, never from it onto ac: -- so with
# the action blocks living in ac:/battery: alone, a desktop ran a plan of
# disabled steps: no DPMS, no lock, "waiting for idle" forever.
#
# Only brightness is left out: brightnessctl drives an internal panel, and
# external monitors need DDC/CI, which it does not speak. /sys/class/backlight
# is empty on a desktop, so the step would be a no-op.
lock_screen:
timeout 300 # 5 min idle
command "moonarch-lock"
end
dpms:
timeout 60 # 1 min after the lock, so 6 min idle
command "niri msg action power-off-monitors"
resume_command "niri msg action power-on-monitors"
end
suspend:
timeout 1800 # 30 min after the blank, so 36 min idle
command "systemctl suspend"
end
# AC power plan (relaxed)
ac:
brightness:
timeout 300 # 5 min idle
command "brightnessctl set 50%"
end
lock_screen:
timeout 60 # 6 min idle
command "moonarch-lock"
end
dpms:
timeout 60 # 7 min idle
command "niri msg action power-off-monitors"
resume_command "niri msg action power-on-monitors"
end
suspend:
timeout 1800 # 37 min idle
command "systemctl suspend"
end
end
# Battery plan (aggressive)
battery:
brightness:
timeout 60 # 1 min idle
command "brightnessctl set 30%"
end
lock_screen:
timeout 60 # 2 min idle
command "moonarch-lock"
end
dpms:
timeout 30 # 2.5 min idle
command "niri msg action power-off-monitors"
resume_command "niri msg action power-on-monitors"
end
suspend:
timeout 300 # 7.5 min idle
command "systemctl suspend"
end
end
end