# Shared display recovery helpers (#127). Used by hyprland.nix (PATH + # undock dump) and idle.nix (hypridle on-resume / after_sleep absolute paths). # # dump — evidence to ~/nomarchy-display-dump-*.txt without SSH # wake — dpms on + zero-output undock rescue + dump if still dark # Pass displayTransition so wake pins the same binary hyprland ships. # Call once with only pkgs to get dump (transition not ready yet), then # again with displayTransition for wake. { pkgs, displayTransition ? null }: let dump = pkgs.writeShellScriptBin "nomarchy-display-dump" '' set -u reason="''${1:-manual}" stamp=$(date +%Y%m%d-%H%M%S) out="''${HOME:-/tmp}/nomarchy-display-dump-''${stamp}.txt" { echo "=== nomarchy-display-dump reason=$reason ===" echo "date: $(date -Is 2>/dev/null || date)" echo "user: $(id -un 2>/dev/null || echo ?)" echo "HYPRLAND_INSTANCE_SIGNATURE=''${HYPRLAND_INSTANCE_SIGNATURE:-}" echo echo "=== hyprctl monitors (enabled) ===" hyprctl monitors -j 2>&1 || true echo echo "=== hyprctl monitors all ===" hyprctl monitors all -j 2>&1 || true echo echo "=== hyprctl workspaces ===" hyprctl workspaces -j 2>&1 || true echo echo "=== hyprctl devices (keyboards) ===" hyprctl devices -j 2>/dev/null | ${pkgs.jq}/bin/jq '.keyboards // .' 2>&1 || true echo echo "=== systemd-inhibit --list ===" ${pkgs.systemd}/bin/systemd-inhibit --list 2>&1 || true echo echo "=== DRM connector status ===" for s in /sys/class/drm/*/status; do [ -r "$s" ] || continue echo "$s: $(cat "$s" 2>/dev/null)" done echo echo "=== journal user display/idle (last 100) ===" journalctl --user -t nomarchy-display-watch -t nomarchy-display-transition \ -t nomarchy-display-wake -t hypridle -t hyprlock -n 100 --no-pager 2>&1 || true echo echo "=== journal -b suspend/sleep/dpms (last 80 matching) ===" journalctl -b --no-pager 2>/dev/null \ | ${pkgs.gnugrep}/bin/grep -iE 'Suspending|PM: suspend|PM: hibernate|dpms|sleep\.target|systemd-sleep' \ | ${pkgs.coreutils}/bin/tail -n 80 || true } >"$out" 2>&1 ${pkgs.util-linux}/bin/logger -t nomarchy-display-dump -- "reason=$reason wrote $out" command -v notify-send >/dev/null 2>&1 \ && notify-send "Display dump" "$out" 2>/dev/null || true printf '%s\n' "$out" ''; wake = if displayTransition == null then null else pkgs.writeShellScriptBin "nomarchy-display-wake" '' set -u LOGGER=${pkgs.util-linux}/bin/logger log() { "$LOGGER" -t nomarchy-display-wake -- "$*"; } TRANSITION=${displayTransition}/bin/nomarchy-display-transition DUMP=${dump}/bin/nomarchy-display-dump hyprctl dispatch dpms on >/dev/null 2>&1 || true enabled=$(hyprctl monitors -j 2>/dev/null | ${pkgs.jq}/bin/jq 'length' 2>/dev/null || echo 0) case "$enabled" in *[!0-9]*|"") enabled=0 ;; esac if [ "$enabled" -eq 0 ]; then log "zero-enabled-outputs: attempting internal enable" internal=$(hyprctl monitors all -j 2>/dev/null \ | ${pkgs.jq}/bin/jq -r '.[] | select(.name | test("^(eDP|LVDS|DSI)")) | .name' 2>/dev/null \ | ${pkgs.coreutils}/bin/head -n1) if [ -n "$internal" ]; then if "$TRANSITION" undock "$internal" 2>/dev/null; then log "rescued via undock internal=$internal" elif "$TRANSITION" enable "$internal" 2>/dev/null; then log "rescued via enable internal=$internal" else log "rescue failed internal=$internal" fi else log "no internal output in monitors all" fi hyprctl dispatch dpms on >/dev/null 2>&1 || true enabled=$(hyprctl monitors -j 2>/dev/null | ${pkgs.jq}/bin/jq 'length' 2>/dev/null || echo 0) case "$enabled" in *[!0-9]*|"") enabled=0 ;; esac if [ "$enabled" -eq 0 ]; then log "still zero-enabled: dumping" "$DUMP" auto-zero-after-wake >/dev/null 2>&1 || true fi fi first=$(hyprctl monitors -j 2>/dev/null \ | ${pkgs.jq}/bin/jq -r '.[0].name // empty' 2>/dev/null || true) [ -n "$first" ] && hyprctl dispatch focusmonitor "$first" >/dev/null 2>&1 || true log "done enabled=$enabled first=''${first:-none}" ''; in { displayDumpTool = dump; displayWakeTool = wake; }