diff --git a/home/niri/default.nix b/home/niri/default.nix index 30df3ec..7524576 100644 --- a/home/niri/default.nix +++ b/home/niri/default.nix @@ -3,12 +3,21 @@ scale ? null, ... }: let - terminal = "${pkgs.foot}/bin/footclient"; nautilus = "${pkgs.nautilus}/bin/nautilus"; playerctl = "${pkgs.playerctl}/bin/playerctl"; wpctl = "${pkgs.wireplumber}/bin/wpctl"; brightnessctl = "${pkgs.brightnessctl}/bin/brightnessctl"; - terminal-name = "foot"; + # Spawn a foot terminal that the "duplicate window" keybind can later trace back to + # its shell. foot's --server mode makes every window report the *server's* PID to the + # compositor, so niri can't distinguish windows by PID. Instead we give each window a + # unique app-id ("footclient-") and export the same value as FOOT_APPID into its + # shell; -E hands footclient's environment (incl. FOOT_APPID) to the server-spawned + # shell. launch_terminal then finds the focused window's shell by matching FOOT_APPID. + spawn_terminal = pkgs.writeShellScriptBin "spawn_terminal" '' + ID="footclient-$$" + export FOOT_APPID="$ID" + exec ${pkgs.foot}/bin/footclient -E --app-id="$ID" "$@" + ''; launch_terminal = pkgs.writeShellScriptBin "launch_terminal" '' function find_leaf_pid(){ local PID @@ -29,28 +38,46 @@ fi } - LEAF_PID=$(find_leaf_pid "$1") + # foot runs in --server mode, so niri reports the shared server PID for every foot + # window and cannot tell them apart. Resolve the focused window to its own shell by + # matching the FOOT_APPID marker that spawn_terminal exports into each window: scan + # the server's direct children for the one whose environment carries our app-id. + FOCUSED=$(niri msg --json focused-window) + SERVER_PID=$(echo "$FOCUSED" | ${pkgs.jq}/bin/jq -r '.pid // empty') + APP_ID=$(echo "$FOCUSED" | ${pkgs.jq}/bin/jq -r '.app_id // empty') + + ROOT_PID="" + if [ -n "$APP_ID" ] && [ -n "$SERVER_PID" ]; then + for CHILD in $(pgrep -P "$SERVER_PID"); do + if grep -qzF "FOOT_APPID=$APP_ID" "/proc/$CHILD/environ" 2>/dev/null; then + ROOT_PID="$CHILD" + break + fi + done + fi + + # Focused window isn't one of our tagged foot terminals: just open a plain terminal. + if [ -z "$ROOT_PID" ]; then + exec ${spawn_terminal}/bin/spawn_terminal + fi + + LEAF_PID=$(find_leaf_pid "$ROOT_PID") if [ "$(ps -p "$LEAF_PID" -o comm=)" == "ssh" ]; then SSH_COMMAND=$(ps -p "$LEAF_PID" -o args --no-headers) if [[ "$SSH_COMMAND" == *"waypipe"* ]]; then CLIENT=$(echo "$SSH_COMMAND" | awk '{ print $5 }') PREVIOUS_SESSION_ID=$(grep -z "SSH_SESSION_ID" "/proc/$LEAF_PID/environ" | xargs -0 -n 1 | grep -oP "[0-9]*") SSH_SESSION_ID=$RANDOM - ${terminal} -e zsh -c "SSH_SESSION_ID=$SSH_SESSION_ID waypipe ssh -t \"$CLIENT\" env SSH_SESSION_ID=\"$SSH_SESSION_ID\" PREVIOUS_SESSION_ID=\"$PREVIOUS_SESSION_ID\" \"zsh --login\"" + ${spawn_terminal}/bin/spawn_terminal zsh -c "SSH_SESSION_ID=$SSH_SESSION_ID waypipe ssh -t \"$CLIENT\" env SSH_SESSION_ID=\"$SSH_SESSION_ID\" PREVIOUS_SESSION_ID=\"$PREVIOUS_SESSION_ID\" \"zsh --login\"" else - ${terminal} -e zsh -c "ssh -t \"$(echo "$SSH_COMMAND" | awk '{ print $2 }')\"" + ${spawn_terminal}/bin/spawn_terminal zsh -c "ssh -t \"$(echo "$SSH_COMMAND" | awk '{ print $2 }')\"" fi - - else # Not an ssh session - if [ "$(ps -p "$1" -o comm=)" == "${terminal-name}" ]; then - CWD=$(readlink -e /proc/"$LEAF_PID"/cwd) - if [ "$CWD" != "" ]; then - ${terminal} --working-directory "$CWD" - else - ${terminal} - fi + else # Not an ssh session: open a local terminal in the same directory. + CWD=$(readlink -e /proc/"$LEAF_PID"/cwd) + if [ "$CWD" != "" ]; then + ${spawn_terminal}/bin/spawn_terminal --working-directory "$CWD" else - ${terminal} + ${spawn_terminal}/bin/spawn_terminal fi fi ''; @@ -156,8 +183,8 @@ in { binds { // General Binds - Mod+Return { spawn "sh" "-c" "${launch_terminal}/bin/launch_terminal $(niri msg --json focused-window | ${pkgs.jq}/bin/jq .pid)"; } - Mod+Shift+Return { spawn "${terminal}"; } + Mod+Return { spawn "${launch_terminal}/bin/launch_terminal"; } + Mod+Shift+Return { spawn "${spawn_terminal}/bin/spawn_terminal"; } Mod+Q { close-window; } Mod+A { spawn "${nautilus}"; } Mod+B { spawn "Helium"; }