diff --git a/dotfiles/lib/bin/codex_desktop_scratchpad b/dotfiles/lib/bin/codex_desktop_scratchpad index e17262f2..8deea42f 100755 --- a/dotfiles/lib/bin/codex_desktop_scratchpad +++ b/dotfiles/lib/bin/codex_desktop_scratchpad @@ -101,6 +101,45 @@ activate_status_notifier_item() { return 1 } +focus_hyprland_window() { + local pid="$1" + local address + local output + + command -v hyprctl >/dev/null 2>&1 || return 1 + address="$( + HYPR_FOCUS_PID="$pid" python3 - <<'PY' +import json +import os +import subprocess +import sys + +target_pid = int(os.environ["HYPR_FOCUS_PID"]) +try: + clients = json.loads(subprocess.check_output(["hyprctl", "clients", "-j"], text=True, stderr=subprocess.DEVNULL)) +except Exception: + raise SystemExit(1) + +for client in clients: + if client.get("pid") == target_pid and client.get("address") and client.get("mapped", True) and not client.get("hidden", False): + print(client["address"]) + break +else: + raise SystemExit(1) +PY + )" || return 1 + [ -n "$address" ] || return 1 + + output="$(hyprctl dispatch "hl.dsp.focus({ window = \"address:$address\" })" 2>&1)" || return 1 + [ "$output" = "ok" ] || return 1 +} + +start_second_instance_handoff() { + ( + exec codex-desktop "$@" + ) >/dev/null 2>&1 & +} + running_app_is_alive() { local pid @@ -146,7 +185,9 @@ if running_app="$(find_running_app)"; then printf '%s\n' "$running_pid" > "$pid_file" send_launch_action "$@" && exit 0 activate_status_notifier_item "$running_pid" && exit 0 - notify-send "Codex is already running" "No warm-start socket or tray activation path was available." >/dev/null 2>&1 || true + focus_hyprland_window "$running_pid" && exit 0 + start_second_instance_handoff "$@" && exit 0 + notify-send "Codex is already running" "No warm-start socket, tray activation, or second-instance restore path was available." >/dev/null 2>&1 || true exit 0 fi diff --git a/nixos/code.nix b/nixos/code.nix index f694a4f5..4f6dc452 100644 --- a/nixos/code.nix +++ b/nixos/code.nix @@ -7,7 +7,11 @@ ... }: let - codexDesktopLinuxSource = inputs.codex-desktop-linux; + codexDesktopLinuxSource = pkgs.applyPatches { + name = "codex-desktop-linux-patched"; + src = inputs.codex-desktop-linux; + patches = [ ./patches/codex-desktop-linux-gsettings-schemas.patch ]; + }; codexDesktopLinux = let flake = import "${codexDesktopLinuxSource}/flake.nix"; @@ -75,6 +79,8 @@ makeEnable config "myModules.code" true { nix nodejs openssh + ripgrep + zsh ]; listen = "unix://"; }; diff --git a/nixos/patches/codex-desktop-linux-gsettings-schemas.patch b/nixos/patches/codex-desktop-linux-gsettings-schemas.patch new file mode 100644 index 00000000..f60e050a --- /dev/null +++ b/nixos/patches/codex-desktop-linux-gsettings-schemas.patch @@ -0,0 +1,25 @@ +diff --git a/flake.nix b/flake.nix +index 6c225c2..fce1fac 100644 +--- a/flake.nix ++++ b/flake.nix +@@ -275,6 +275,12 @@ + stdenv.cc.cc.lib + zlib + ]); ++ gsettingsSchemaDataDirs = pkgs.lib.concatMapStringsSep ":" (pkg: ++ pkgs.lib.removeSuffix "/glib-2.0/schemas" (pkgs.glib.getSchemaPath pkg) ++ ) (with pkgs; [ ++ gsettings-desktop-schemas ++ gtk3 ++ ]); + launcherPath = pkgs.lib.makeBinPath (with pkgs; [ + bash + coreutils +@@ -547,6 +553,7 @@ + makeWrapper "$out/opt/codex-desktop/start.sh" "$out/bin/codex-desktop" \ + --prefix PATH : "${launcherPath}" \ + --prefix LD_LIBRARY_PATH : "${electronLibPath}" \ + --prefix LD_LIBRARY_PATH : "${runtimeLibPath}" \ ++ --prefix XDG_DATA_DIRS : "${gsettingsSchemaDataDirs}" \ + --prefix PATH : "/run/current-system/sw/bin" \ + --prefix PATH : "/etc/profiles/per-user/$(whoami)/bin"