feat(power): clamshell — ignore lid suspend when docked (#86)
Some checks failed
Check / eval (push) Has been cancelled

Explicit HandleLidSwitchDocked=ignore under services.logind so closing
the lid with an external display connected does not suspend. Undocked
lid path left to upstream defaults. checks.clamshell-logind asserts the
baked logind.conf and active logind; real multi-monitor lid V3 queued.

Verified: V2 — flake check --no-build; checks.clamshell-logind green.
V3 pending: HARDWARE-QUEUE #86 lid+external on a laptop.
This commit is contained in:
Bernardo Magri
2026-07-11 10:32:18 +01:00
parent ce05eed754
commit 27f18e4ccc
9 changed files with 73 additions and 13 deletions

View File

@@ -85,8 +85,9 @@ in
# 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.
# Lid close is logind's job (not hypridle): undocked lid still
# suspends (HandleLidSwitch); docked/clamshell lid is ignore
# (HandleLidSwitchDocked — modules/nixos/power.nix, #86).
{ timeout = 900; on-timeout = "${onAc} || systemctl suspend"; }
];
};

View File

@@ -31,6 +31,20 @@ in
services.power-profiles-daemon.enable = lib.mkDefault ppd;
services.tlp.enable = lib.mkDefault tlp;
# Clamshell / dock (BACKLOG #86): when the machine is "docked" in
# logind's sense (≥1 external display connected), closing the lid
# must NOT suspend — the external panel is the session. systemd's
# built-in default is already ignore; we set it explicitly so a
# downstream override or lock-bump drift is visible, and so
# checks.clamshell-logind can assert the contract.
# Lid alone (undocked) keeps the normal suspend path
# (HandleLidSwitch / ExternalPower left to upstream defaults).
# Display-profile "docked" layouts (eDP off) are orthogonal and
# already handled by nomarchy.displayProfiles.
services.logind.settings.Login = {
HandleLidSwitchDocked = lib.mkDefault "ignore";
};
# thermald is Intel-only, so off unless asked (the installer enables
# it on a GenuineIntel CPU). Sits happily next to either backend.
services.thermald.enable = lib.mkDefault cfg.thermal.enable;