diff --git a/modules/home.nix b/modules/home.nix index 8928ff4..53cb972 100644 --- a/modules/home.nix +++ b/modules/home.nix @@ -661,7 +661,7 @@ in # the ~/.local/share/bg symlink if it exists. "awww-daemon" "sh -c '[ -e \"$HOME/.local/share/bg\" ] && awww img \"$HOME/.local/share/bg\"'" - # re-push wallpaper + reload waybar on monitor add/remove (media.nix) + # re-push wallpaper + relaunch waybar on monitor add/remove (media.nix) "monitor-hotplug" ]; }; diff --git a/modules/media.nix b/modules/media.nix index ded2412..f2e8870 100644 --- a/modules/media.nix +++ b/modules/media.nix @@ -7,7 +7,7 @@ # awww-daemon and the boot-time restore from that symlink run as Hyprland # `exec-once` (see home.nix). -{ pkgs, ... }: +{ pkgs, config, ... }: let # setbg: persist the choice as an XDG-data symlink, then set it live. Startup @@ -21,20 +21,30 @@ let # awww-daemon paints only the outputs present when `awww img` last ran and does # not repaint a monitor hotplugged afterwards — it comes up on the fill color # (black), and a transparent foot on it then shows that black, not the - # wallpaper. Symmetric problem on unplug: removing an output makes Hyprland - # drop and not recreate the layer-shell surfaces on the surviving monitor, so + # wallpaper. Symmetric problem on real DP/HDMI unplug: Hyprland drops the + # layer-shell surfaces on the surviving monitor and does not recreate them, so # its waybar and wallpaper vanish. Watch Hyprland's event socket and, on either # add or remove, re-push the wallpaper (setbg with no arg → all current - # outputs) and reload waybar (SIGUSR2 rebuilds its per-output bars). Hyprland - # emits both `monitoradded` and `monitoraddedv2`; match only the non-v2 forms - # so each side fires once. Runs as a Hyprland exec-once (see home.nix). + # outputs) and fully relaunch waybar. A SIGUSR2 reload is not enough — it + # rereads config but does not recreate a bar Hyprland already tore down — so + # kill and restart, which enumerates the current outputs and draws a bar on + # each. The event flaps (several add/remove lines per plug); the loop is + # sequential so each pass converges to one waybar. Hyprland emits both + # `monitoradded` and `monitoraddedv2`; match only the non-v2 forms so each side + # fires once. Runs as a Hyprland exec-once (see home.nix). + hyprctl = "${config.wayland.windowManager.hyprland.finalPackage}/bin/hyprctl"; monitorHotplug = pkgs.writeShellScriptBin "monitor-hotplug" '' sock="''${XDG_RUNTIME_DIR}/hypr/''${HYPRLAND_INSTANCE_SIGNATURE}/.socket2.sock" ${pkgs.socat}/bin/socat -u UNIX-CONNECT:"$sock" - | while IFS= read -r line; do case "$line" in "monitoradded>>"* | "monitorremoved>>"*) - setbg - ${pkgs.procps}/bin/pkill -USR2 -x .waybar-wrapped || true + sleep 1 # let Hyprland settle the new geometry + setbg # re-push wallpaper to all current outputs + ${pkgs.procps}/bin/pkill -x waybar || true # relaunch waybar fresh (see comment) + i=0 + while [ $i -lt 6 ] && ${pkgs.procps}/bin/pgrep -x waybar >/dev/null; do sleep 0.3; i=$((i+1)); done + ${pkgs.procps}/bin/pkill -9 -x waybar || true + ${hyprctl} dispatch exec waybar ;; esac done