# Generic viewers. mpv for video/audio, imv for images, zathura for PDFs/docs — # all minimal, keyboard-driven, Wayland-native. No personal config here. # # imv key binds run external actions on the current file (yank path, rotate/flip, # delete, open in editor, info). Wallpaper uses awww (daemon + CLI): `setbg` # symlinks the chosen file to ~/.local/share/bg and pushes it live. The # awww-daemon and the boot-time restore from that symlink run as Hyprland # `exec-once` (see home.nix). { pkgs, config, ... }: let # setbg: persist the choice as an XDG-data symlink, then set it live. Startup # restore just re-runs `awww img` against the same symlink. setbg = pkgs.writeShellScriptBin "setbg" '' bgloc="''${XDG_DATA_HOME:-$HOME/.local/share}/bg" [ -n "$1" ] && ln -sf "$(readlink -f "$1")" "$bgloc" ${pkgs.awww}/bin/awww img "$bgloc" ''; # 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 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 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>>"*) 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 ''; in { programs.mpv = { enable = true; # gallery/thumbnail grid for playlists. Ships the scripts; key bindings to # open it can be added later via programs.mpv.bindings (input.conf). scripts = [ pkgs.mpvScripts.mpv-gallery-view ]; }; programs.imv = { enable = true; settings.binds = { "w" = ''exec setbg "$imv_current_file"''; "y" = ''exec printf %s "$imv_current_file" | wl-copy''; "" = ''exec readlink -f "$imv_current_file" | wl-copy''; "" = ''exec rm "$imv_current_file"''; # no confirm "r" = ''exec magick "$imv_current_file" -rotate 90 "$imv_current_file"''; "" = ''exec magick "$imv_current_file" -rotate -90 "$imv_current_file"''; "f" = ''exec magick "$imv_current_file" -flop "$imv_current_file"''; "e" = ''exec gimp "$imv_current_file"''; # edit; `g` reserved by imv's gg chord "i" = ''exec notify-send "File info" "$(mediainfo "$imv_current_file")"''; }; }; # PDF/document viewer. pkgs.zathura bundles the mupdf backend, so enabling is # enough. Route yanks to the wayland clipboard. programs.zathura = { enable = true; options.selection-clipboard = "clipboard"; }; home.packages = with pkgs; [ setbg monitorHotplug # re-push wallpaper + reload waybar on monitor add/remove (see comment above) awww # wayland wallpaper daemon (setbg backend) wl-clipboard # wl-copy, for the yank binds imagemagick # `magick`: rotate/flip binds mediainfo # `i` info bind libnotify # notify-send client (daemon = mako, in home.nix) gimp # `e` open-in-editor bind ]; }