Files
Nomarchy/modules/home/idle.nix
Bernardo Magri 1b0eeeaf6c fix(idle): don't lock before an encrypted hibernate (was: unlock after)
The previous nomarchy-hibernate-unlock ran `pkill hyprlock` after a
hibernate resume, but killing a Wayland session-lock client without
releasing the lock trips hyprlock's "go to a tty" crash failsafe -- the
compositor keeps the screen locked for safety. So resume showed a hyprlock
error screen instead of unlocking.

Fix it the right way: never engage the lock before an encrypted hibernate
(the LUKS passphrase at resume is the gate). Replace the post-resume unlock
with a nomarchy-lock-before-sleep unit that takes over hypridle's
before_sleep_cmd: it locks on the RAM-resume sleeps (suspend / hybrid-sleep
/ suspend-then-hibernate) always, and on hibernate.target only when the disk
is unencrypted. idle.nix drops before_sleep_cmd accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 10:15:31 +01:00

96 lines
3.2 KiB
Nix

# hyprlock + hypridle — screen locking and idle management, themed from
# theme-state.json. One concern, one file: hypridle drives WHEN (idle
# lock, display off, suspend, lock-before-sleep), hyprlock is the
# themed lock screen itself (also behind the power menu's Lock entry).
{ config, lib, pkgs, ... }:
let
cfg = config.nomarchy;
t = cfg.theme;
c = t.colors;
inherit (config.nomarchy.lib) rgb;
# Exits 0 when running on AC: a mains adapter reports `online` 1 (battery
# supplies have no `online` node, so they never match). Used as
# `${onAc} || <action>` so the action is skipped while plugged in.
onAc = pkgs.writeShellScript "nomarchy-on-ac" ''
for f in /sys/class/power_supply/*/online; do
[ -r "$f" ] && [ "$(cat "$f")" = "1" ] && exit 0
done
exit 1
'';
in
{
config = lib.mkIf cfg.idle.enable {
programs.hyprlock = {
enable = true;
settings = {
general.hide_cursor = true;
background = [{
monitor = "";
color = rgb c.base;
}];
input-field = [{
monitor = "";
size = "300, 50";
outline_thickness = t.ui.borderSize;
dots_size = 0.25;
outer_color = rgb c.accent;
inner_color = rgb c.surface;
font_color = rgb c.text;
check_color = rgb c.warn;
fail_color = rgb c.bad;
rounding = t.ui.rounding;
placeholder_text = "<i>password</i>";
}];
label = [{
monitor = "";
text = "$TIME";
color = rgb c.text;
font_size = 64;
font_family = t.fonts.ui;
position = "0, 120";
halign = "center";
valign = "center";
}];
};
};
services.hypridle = {
enable = true;
settings = {
general = {
lock_cmd = "pidof hyprlock || hyprlock";
# No before_sleep_cmd here: locking before sleep is driven
# system-side so it can fire for suspend but skip an encrypted
# hibernate — whose LUKS resume already gates the machine, so a
# hyprlock on top is a second password (and a Wayland session-lock
# can't be safely dropped after the fact — killing the locker trips
# its "go to a tty" crash failsafe). See nomarchy-lock-before-sleep
# in modules/nixos/default.nix.
after_sleep_cmd = "hyprctl dispatch dpms on";
};
listener = [
# Lock and screen-off are the same on either power source —
# they're about privacy and the panel, not battery.
{ timeout = 300; on-timeout = "loginctl lock-session"; }
{
timeout = 600;
on-timeout = "hyprctl dispatch dpms off";
on-resume = "hyprctl dispatch dpms on";
}
# Suspend only on battery, and sooner than the old fixed 30 min
# (it now only fires unplugged). Plugged in, the machine stays
# up — long builds, media, presentations aren't killed mid-idle.
# Closing the lid still suspends on AC (logind's default): that's
# an explicit "I'm done", distinct from sitting idle.
{ timeout = 900; on-timeout = "${onAc} || systemctl suspend"; }
];
};
};
};
}