fix(idle): skip DPMS-off when docked (#127 mitigation)
All checks were successful
Check / eval (push) Successful in 5m24s
All checks were successful
Check / eval (push) Successful in 5m24s
Blanking the only live output in dock mode led to a brick where wake and even VT switch failed. Skip hypridle's 10m dpms off when any laptop internal (eDP/LVDS/DSI) is present but not enabled; lock at 5m remains. Undocked still blanks. Document LATER revisit for intentional DPMS-when-docked once wake is proven. V1: nix flake check --no-build. V3: docked idle stays lit under lock.
This commit is contained in:
@@ -20,24 +20,10 @@ let
|
||||
exit 1
|
||||
'';
|
||||
|
||||
# Same transition binary hyprland.nix puts on PATH — re-derived here so
|
||||
# hypridle can pin absolute store paths (thin PATH in the user unit).
|
||||
# Must stay in lockstep with modules/home/hyprland.nix's transition.
|
||||
# We only need undock/enable + dpms; call via PATH-installed name is
|
||||
# fragile, so wake embeds the transition from a minimal import chain:
|
||||
# dump+wake live in display-tools.nix; transition is the public name
|
||||
# on PATH after HM activation — wake script uses absolute path from
|
||||
# a local reimplementation of just the enable/dpms rescue when the
|
||||
# full transition package isn't injectable without circular imports.
|
||||
#
|
||||
# Practical approach: invoke `nomarchy-display-wake` from PATH after
|
||||
# activation; for the unit Exec lines use a wrapper that prefers the
|
||||
# store path of a wake script built with transition = null fallback
|
||||
# (hyprctl keyword + reload + dpms) matching undock's public contract.
|
||||
# Absolute store paths for hypridle (thin PATH). Wake reuses the shared
|
||||
# helper; a mini transition avoids a circular import on hyprland.nix.
|
||||
displayWake =
|
||||
let
|
||||
# Minimal undock-equivalent for idle's store path (no circular dep on
|
||||
# hyprland.nix). Prefer the real transition when on PATH at runtime.
|
||||
miniTransition = pkgs.writeShellScriptBin "nomarchy-display-transition" ''
|
||||
set -u
|
||||
case "''${1:-}" in
|
||||
@@ -65,6 +51,31 @@ let
|
||||
inherit pkgs;
|
||||
displayTransition = miniTransition;
|
||||
}).displayWakeTool;
|
||||
|
||||
# #127 mitigation (2026-07-15): blanking the *only* live output while
|
||||
# docked (eDP disabled) left a black seat that sometimes would not
|
||||
# recover (and even VT switch looked dead). Skip DPMS-off when any
|
||||
# laptop internal is present but not enabled. Lock still runs at 5 min.
|
||||
# Revisit: intentional DPMS-on-dock once wake is trustworthy — see
|
||||
# BACKLOG #127 and LATER "DPMS when docked".
|
||||
dpmsOff = pkgs.writeShellScript "nomarchy-dpms-off" ''
|
||||
set -euo pipefail
|
||||
jq=${pkgs.jq}/bin/jq
|
||||
internals=$(hyprctl monitors all -j 2>/dev/null \
|
||||
| $jq -r '.[] | select(.name | test("^(eDP|LVDS|DSI)")) | .name' \
|
||||
2>/dev/null || true)
|
||||
if [ -n "$internals" ]; then
|
||||
for m in $internals; do
|
||||
if ! hyprctl monitors -j 2>/dev/null \
|
||||
| $jq -e --arg m "$m" 'any(.[]; .name == $m)' >/dev/null 2>&1; then
|
||||
${pkgs.util-linux}/bin/logger -t nomarchy-idle -- \
|
||||
"dpms-off skipped: docked (internal $m not enabled)"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
hyprctl dispatch dpms off
|
||||
'';
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.idle.enable {
|
||||
@@ -168,8 +179,8 @@ in
|
||||
{ timeout = 300; on-timeout = "loginctl lock-session"; }
|
||||
{
|
||||
timeout = 600;
|
||||
on-timeout = "hyprctl dispatch dpms off";
|
||||
# Same rescue path as after_sleep (#127).
|
||||
# Docked: skip blanking sole output (#127). Undocked: DPMS off.
|
||||
on-timeout = "${dpmsOff}";
|
||||
on-resume = "${lib.getExe displayWake}";
|
||||
}
|
||||
# Suspend only on battery, and sooner than the old fixed 30 min
|
||||
|
||||
Reference in New Issue
Block a user