{pkgs, ...}: let hyprctl = "${pkgs.hyprland}/bin/hyprctl"; jq = "${pkgs.jq}/bin/jq"; socat = "${pkgs.socat}/bin/socat"; hypr-window-rules = pkgs.writeShellScriptBin "hypr-window-rules" '' LOG=/tmp/hypr-window-rules.log log() { echo "[$(date +%T)] $*" >> "$LOG"; } handle() { local event="$1" case "$event" in windowtitlev2*) local data="''${event#windowtitlev2>>}" local addr="0x''${data%%,*}" local title="''${data#*,}" if echo "$title" | grep -qi "bitwarden"; then log "bitwarden title detected: addr=$addr title=$title" local info info=$(${hyprctl} clients -j | ${jq} -r --arg addr "$addr" \ '.[] | select(.address == $addr) | "\(.class)|\(.floating)"') local class="''${info%|*}" local floating="''${info#*|}" log " -> class=$class floating=$floating" if [[ "$class" == "firefox" && "$floating" == "false" ]]; then ${hyprctl} dispatch togglefloating "address:$addr" local target_w=600 local target_h=800 local mon_id mon_id=$(${hyprctl} clients -j | ${jq} -r --arg addr "$addr" \ '.[] | select(.address == $addr) | .monitor') local center center=$(${hyprctl} monitors -j | ${jq} -r \ --argjson id "$mon_id" --argjson tw "$target_w" --argjson th "$target_h" \ '.[] | select(.id == $id) | "\(.x + ((.width / .scale) - $tw) / 2 | floor)|\(.y + ((.height / .scale) - $th) / 2 | floor)"') local cx="''${center%%|*}" local cy="''${center#*|}" ${hyprctl} dispatch resizewindowpixel "exact $target_w $target_h, address:$addr" ${hyprctl} dispatch movewindowpixel "exact $cx $cy, address:$addr" log " -> floated, resized to $target_w x $target_h, moved to $cx,$cy" else log " -> skipped (class or floating mismatch)" fi fi ;; esac } log "started (HYPRLAND_INSTANCE_SIGNATURE=$HYPRLAND_INSTANCE_SIGNATURE)" ${socat} -u \ "UNIX-CONNECT:$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" \ - \ | while IFS= read -r line; do handle "$line"; done log "socat exited" ''; in { home.packages = [hypr-window-rules]; wayland.windowManager.hyprland.settings.exec-once = [ "hypr-window-rules" ]; }