From 97a9fce54f5df007afe7b8637ddc09314f38ad00 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 28 Sep 2026 14:04:31 +0200 Subject: [PATCH] Hand browser and web app launches to the running browser directly (#13530) * Hand browser and web app launches to the running browser directly With a Chromium-based browser already running, each launch started a second browser process only to pass its command line over the profile's singleton socket and exit, ~165ms before the running browser even heard of it. omarchy-cmd-browser-handoff sends that message itself with socat and waits for the ACK, so a web app opens in ~210ms instead of ~430ms. It hands off only what it can do exactly as the browser would: the packaged browser binary rather than a wrapper, a flags file holding nothing beyond the process flags Omarchy ships, no other data directory, and a socket we own. Anything else, or no answer, launches the browser as before. Co-Authored-By: Claude Opus 5.5 * Hand Brave Origin launches to the running browser too /usr/bin/brave-origin is the package's own launcher, reading brave-origin-flags.conf, with the profile in BraveSoftware/Brave-Origin. A web app now opens in ~158ms instead of ~345ms. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- bin/omarchy-cmd-browser-handoff | 48 ++++++++++++++++ bin/omarchy-launch-browser | 8 ++- bin/omarchy-launch-webapp | 6 +- test/shell.d/browser-handoff-test.sh | 85 ++++++++++++++++++++++++++++ test/shell.d/launch-browser-test.sh | 16 ++++++ 5 files changed, 159 insertions(+), 4 deletions(-) create mode 100755 bin/omarchy-cmd-browser-handoff create mode 100644 test/shell.d/browser-handoff-test.sh diff --git a/bin/omarchy-cmd-browser-handoff b/bin/omarchy-cmd-browser-handoff new file mode 100755 index 00000000..7dd14b23 --- /dev/null +++ b/bin/omarchy-cmd-browser-handoff @@ -0,0 +1,48 @@ +#!/bin/bash + +# omarchy:summary=Hand a command line to the running Chromium-based browser +# omarchy:args= [browser-args...] +# omarchy:hidden=true + +# A second browser process spends ~165ms starting up only to pass its command +# line to the running one over the profile's singleton socket, then exits. Send +# it there directly, and fail when no browser acknowledges it so the caller can +# launch one instead. +config="${XDG_CONFIG_HOME:-$HOME/.config}" + +# Only the browsers themselves: a wrapper in their place may pick a profile or +# add flags of its own, which only running it can honour. +case $(type -P "$1") in +/usr/bin/chromium) profile=chromium flags=chromium-flags.conf ;; +/usr/bin/google-chrome-stable) profile=google-chrome flags=chrome-flags.conf ;; +/usr/bin/brave) profile=BraveSoftware/Brave-Browser flags=brave-flags.conf ;; +/usr/bin/brave-origin) profile=BraveSoftware/Brave-Origin flags=brave-origin-flags.conf ;; +/usr/bin/microsoft-edge-stable) profile=microsoft-edge flags=microsoft-edge-stable-flags.conf ;; +*) exit 1 ;; +esac +shift + +# The running browser already has the process flags Omarchy ships in the flags +# file. Any other flag there may be meant for each launch, and a data directory +# from the environment is another browser, so leave those to the launcher. +if [[ -n ${CHROME_USER_DATA_DIR:-}${CHROME_CONFIG_HOME:-} ]] || + cat "/etc/$flags" "$config/$flags" 2>/dev/null | sed 's/#.*//' | tr -s '[:space:]' '\n' | + grep -vE '^(--(ozone-platform|ozone-platform-hint|password-store|enable-features|load-extension)=.*)?$' | grep -q .; then + exit 1 +fi + +for arg in "$@"; do + [[ $arg == --user-data-dir* ]] && exit 1 +done + +# The socket lives in a /tmp dir, which another user could recreate once a +# crashed browser's is cleaned away, so only a socket of our own gets the URL. +socket="$config/$profile/SingletonSocket" +[[ -S $socket && -O $socket ]] || exit 1 + +reply=$({ + printf 'START\0%s\0browser' "$PWD" + printf '\0%s' "$@" +} | socat -t2 - "UNIX-CONNECT:$socket" 2>/dev/null) + +[[ $reply == "ACK" ]] diff --git a/bin/omarchy-launch-browser b/bin/omarchy-launch-browser index 5bc69b72..d858a3a4 100755 --- a/bin/omarchy-launch-browser +++ b/bin/omarchy-launch-browser @@ -14,9 +14,11 @@ else private_flag="--incognito" fi -systemd-run --user --quiet --collect --unit="omarchy-browser-$(date +%s%N)" \ - --property=StandardOutput=null --property=StandardError=null \ - uwsm-app -- "$browser_exec" "${@/--private/$private_flag}" +if ! omarchy-cmd-browser-handoff "$browser_exec" "${@/--private/$private_flag}"; then + systemd-run --user --quiet --collect --unit="omarchy-browser-$(date +%s%N)" \ + --property=StandardOutput=null --property=StandardError=null \ + uwsm-app -- "$browser_exec" "${@/--private/$private_flag}" +fi url="" for argument in "$@"; do diff --git a/bin/omarchy-launch-webapp b/bin/omarchy-launch-webapp index 5c250683..392882e5 100755 --- a/bin/omarchy-launch-webapp +++ b/bin/omarchy-launch-webapp @@ -10,4 +10,8 @@ google-chrome* | brave* | microsoft-edge* | opera* | vivaldi* | helium*) ;; *) browser="chromium.desktop" ;; esac -exec setsid uwsm-app -- $(sed -n 's/^Exec=\([^ ]*\).*/\1/p' {~/.local,~/.nix-profile,/usr}/share/applications/$browser 2>/dev/null | head -1) --app="$1" "${@:2}" +browser_exec=$(sed -n 's/^Exec=\([^ ]*\).*/\1/p' {~/.local,~/.nix-profile,/usr}/share/applications/$browser 2>/dev/null | head -1) + +if ! omarchy-cmd-browser-handoff "$browser_exec" --app="$1" "${@:2}"; then + exec setsid uwsm-app -- $browser_exec --app="$1" "${@:2}" +fi diff --git a/test/shell.d/browser-handoff-test.sh b/test/shell.d/browser-handoff-test.sh new file mode 100644 index 00000000..c188399d --- /dev/null +++ b/test/shell.d/browser-handoff-test.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +require_command python3 +require_command socat + +# The handoff only stands in for the packaged browser itself. +if [[ $(type -P chromium) != "/usr/bin/chromium" ]]; then + skip "browser handoff needs /usr/bin/chromium" + exit 0 +fi + +test_tmp=$(mktemp -d) +trap 'rm -rf "$test_tmp"' EXIT + +export XDG_CONFIG_HOME="$test_tmp/config" +socket="$XDG_CONFIG_HOME/chromium/SingletonSocket" +received="$test_tmp/received" +mkdir -p "${socket%/*}" +flags_file="$XDG_CONFIG_HOME/chromium-flags.conf" +cp "$ROOT/config/chromium-flags.conf" "$flags_file" +echo "# A comment of the user's" >>"$flags_file" + +# A running browser's side of the singleton socket: take each command line and +# acknowledge it, as Chromium does. +python3 - "$socket" "$received" <<'PY' & +import socket, sys +server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +server.bind(sys.argv[1]) +server.listen(1) +while True: + connection, _ = server.accept() + message = b"" + while chunk := connection.recv(4096): + message += chunk + open(sys.argv[2], "wb").write(message) + connection.sendall(b"ACK") + connection.close() +PY +server=$! +trap 'kill "$server" 2>/dev/null || true; rm -rf "$test_tmp"' EXIT + +for _ in $(seq 100); do + [[ -S $socket ]] && break + sleep 0.02 +done + +(cd "$test_tmp" && "$ROOT/bin/omarchy-cmd-browser-handoff" chromium --app="https://example.test/a b") || + fail "the running browser acknowledges a handed off command line" + +expected=$(printf 'START\0%s\0browser\0--app=https://example.test/a b' "$test_tmp" | od -c) +[[ $(od -c <"$received") == "$expected" ]] || + fail "the handoff sends the working directory and arguments as Chromium's singleton expects" "$(od -c <"$received")" +pass "a command line is handed to the running browser over its singleton socket" + +! "$ROOT/bin/omarchy-cmd-browser-handoff" chromium --user-data-dir=/elsewhere https://example.test || + fail "another data directory is left to a browser of its own" +mkdir -p "$test_tmp/wrapper" +printf '#!/bin/bash\nexec /usr/bin/chromium --profile-directory=Work "$@"\n' >"$test_tmp/wrapper/chromium" +chmod +x "$test_tmp/wrapper/chromium" +! PATH="$test_tmp/wrapper:$PATH" "$ROOT/bin/omarchy-cmd-browser-handoff" chromium https://example.test || + fail "a wrapper standing in for the browser is left to run" +! CHROME_USER_DATA_DIR=/elsewhere "$ROOT/bin/omarchy-cmd-browser-handoff" chromium https://example.test || + fail "a data directory from the environment is left to a browser of its own" + +# The handoff forwards no flags file, so any flag beyond Omarchy's own, which +# may be meant for each launch, needs the launcher. +for flag in '--new-window' '--enable-features=A --profile-directory="Profile 1"'; do + cp "$ROOT/config/chromium-flags.conf" "$flags_file" + echo "$flag" >>"$flags_file" + ! "$ROOT/bin/omarchy-cmd-browser-handoff" chromium https://example.test || + fail "a flags file with $flag is left to the launcher" +done + +# The browser is gone but its socket file is left, as after a crash. +kill "$server" +wait "$server" 2>/dev/null || true +! "$ROOT/bin/omarchy-cmd-browser-handoff" chromium --app=https://example.test || + fail "a socket no browser answers on fails the handoff" +! "$ROOT/bin/omarchy-cmd-browser-handoff" firefox https://example.test || + fail "a browser without a singleton socket fails the handoff" +pass "the handoff fails when no Chromium-based browser answers, so the caller launches one" diff --git a/test/shell.d/launch-browser-test.sh b/test/shell.d/launch-browser-test.sh index 161ff9ee..561174d4 100644 --- a/test/shell.d/launch-browser-test.sh +++ b/test/shell.d/launch-browser-test.sh @@ -10,6 +10,9 @@ trap 'rm -rf "$test_tmp"' EXIT mock_bin="$test_tmp/bin" test_home="$test_tmp/home" mkdir -p "$mock_bin" "$test_home/.local/share/applications" +# Keep the launcher away from the running browser's singleton socket, which it +# would otherwise hand these test URLs to. +export XDG_CONFIG_HOME="$test_home/.config" XDG_DATA_HOME="$test_home/.local/share" cat >"$test_home/.local/share/applications/chromium.desktop" <<'EOF' [Desktop Entry] @@ -79,3 +82,16 @@ grep -Fx '^chromium.*$' "$focus_log" >/dev/null || fail "browser launcher focuses the browser resolved from the HTTPS handler" pass "browser launcher follows opened links to the browser workspace" + +rm -f "$launch_log" +cat >"$mock_bin/omarchy-cmd-browser-handoff" <<'SH' +#!/bin/bash +[[ $1 == "chromium" && $2 == "https://example.test/running" ]] +SH +chmod +x "$mock_bin/omarchy-cmd-browser-handoff" + +HOME="$test_home" PATH="$mock_bin:$PATH" OMARCHY_TEST_BROWSER_LAUNCH="$launch_log" \ + OMARCHY_TEST_BROWSER_FOCUS="$focus_log" bash "$ROOT/bin/omarchy-launch-browser" "https://example.test/running" + +[[ ! -e $launch_log ]] || fail "browser launcher starts no browser when the running one takes the URL" +pass "browser launcher hands a URL to the running browser"