Revert WhatsApp theme bridge

The native messaging host, extension shim, and lifecycle machinery are too complicated for the value this integration provides.
This commit is contained in:
David Heinemeier Hansson
2026-08-01 12:44:40 -07:00
parent 237405215d
commit 66427571bc
15 changed files with 1 additions and 964 deletions
-224
View File
@@ -1,224 +0,0 @@
#!/bin/bash
# omarchy:summary=Native messaging host: push the active Omarchy theme to Chromium web apps
# omarchy:hidden=true
# Native messaging host for the Omarchy theme bridge.
#
# Reads the active Omarchy theme and reports background / foreground / accent /
# selection / browser-chrome colors to a web-app extension as length-prefixed
# JSON on stdout. It's a shared bridge keyed by name (com.omarchy.theme): any
# bundled web-app extension that wants to follow the theme connects to it and
# lists its ID in the host manifest's allowed_origins.
#
# This host is PUSH-ONLY: it never parses inbound messages. That's deliberate.
# Reading Chromium's length-prefixed framing in bash means blocking in
# `head -c4`, which a trap cannot interrupt — so a signal-driven wakeup would
# need a background reader plus a FIFO. Instead we let omarchy's theme-set hook
# signal us with SIGUSR1 (see bin/omarchy-theme-set) and drop inbound
# stdio entirely. The extension gets a push on connect and a push on every
# theme change, which is all it ever needs.
#
# This differs from Omarchy's other bundled hosts (omarchy-chromium-copy-url-host,
# -ytdlp-host): those are one-shot — read a frame, act, exit. Theme-following is
# the inverse direction (system -> extension), so we stay alive to push; only
# their framing idioms carry over, not their structure.
#
# Because it ships in-tree, `omarchy-theme-set` runs the refresh command on every
# switch, so no polling fallback is needed (the standalone AUR build of this host
# carries one for old Omarchy).
set -uo pipefail
# Omarchy 4+ keeps the active theme state here; theme/ is a directory Omarchy
# replaces wholesale on every switch (same layout `omarchy-theme-set` writes).
CURRENT="$HOME/.local/state/omarchy/current"
# Pidfiles live here so the theme-set.d hook can SIGUSR1 every running host.
RUNDIR="$XDG_RUNTIME_DIR/omarchy-theme"
PIDFILE="$RUNDIR/$$.pid"
WATCHDOG_PID=""
# ---------------------------------------------------------------- lifecycle --
cleanup() {
rm -f "$PIDFILE"
[[ -n $WATCHDOG_PID ]] && kill "$WATCHDOG_PID" 2>/dev/null
return 0
}
# ------------------------------------------------------------------ parsing --
trim() {
local s="$1"
s="${s#"${s%%[![:space:]]*}"}"
s="${s%"${s##*[![:space:]]}"}"
printf '%s' "$s"
}
read_text() {
[[ -f $1 ]] || return 0
local text
text=$(<"$1") || return 0
trim "$text"
}
# The terminal background lives under [colors.primary] in the theme's
# alacritty.toml. Only that section counts — other sections define their own
# `background` keys that would otherwise match.
parse_alacritty_bg() {
local file="$1" line s in_primary=0
[[ -f $file ]] || return 0
while IFS= read -r line || [[ -n $line ]]; do
s=$(trim "$line")
if [[ $s == \[* ]]; then
if [[ $s == "[colors.primary]" ]]; then in_primary=1; else in_primary=0; fi
continue
fi
if ((in_primary)) && [[ $s =~ ^background[[:space:]]*=[[:space:]]*\"(#[0-9a-fA-F]{6,8})\" ]]; then
printf '%s' "${BASH_REMATCH[1]}"
return 0
fi
done <"$file"
}
# colors.toml is a flat list of `name = "#rrggbb"` pairs. Populates COLORS.
declare -A COLORS=()
parse_colors_toml() {
local file="$1" line s
COLORS=()
[[ -f $file ]] || return 0
while IFS= read -r line || [[ -n $line ]]; do
s=$(trim "$line")
if [[ $s =~ ^([A-Za-z0-9_]+)[[:space:]]*=[[:space:]]*\"(#[0-9a-fA-F]{6,8})\" ]]; then
COLORS["${BASH_REMATCH[1]}"]="${BASH_REMATCH[2]}"
fi
done <"$file"
}
# omarchy ships the browser chrome color as 'r,g,b' decimal CSV in chromium.theme.
# Most stock themes omit the file — omarchy-theme-set-browser then falls back to
# #1c2027, but we return empty and let the extension pick its own fallback so it
# can be theme-aware about the choice.
parse_chromium_theme() {
local file="$1" text r g b extra c
[[ -f $file ]] || return 0
text=$(<"$file") || return 0
text=$(trim "$text")
IFS=, read -r r g b extra <<<"$text"
[[ -n ${extra:-} ]] && return 0
r=$(trim "${r:-}") g=$(trim "${g:-}") b=$(trim "${b:-}")
for c in "$r" "$g" "$b"; do
[[ $c =~ ^[0-9]+$ ]] || return 0
((c >= 0 && c <= 255)) || return 0
done
printf '#%02x%02x%02x' "$r" "$g" "$b"
}
# --------------------------------------------------------------------- JSON --
json_escape() {
local s="$1"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//$'\n'/\\n}"
s="${s//$'\r'/\\r}"
s="${s//$'\t'/\\t}"
printf '%s' "$s"
}
# Emit a JSON string, or bare null when empty, so the extension can tell "theme
# didn't define this color" from "empty string".
json_value() {
if [[ -z ${1:-} ]]; then
printf 'null'
else
printf '"%s"' "$(json_escape "$1")"
fi
}
build_state() {
local name bg fg accent selection chrome
name=$(read_text "$CURRENT/theme.name")
bg=$(parse_alacritty_bg "$CURRENT/theme/alacritty.toml")
parse_colors_toml "$CURRENT/theme/colors.toml"
chrome=$(parse_chromium_theme "$CURRENT/theme/chromium.theme")
[[ -z $bg ]] && bg="${COLORS[background]:-}"
[[ -z $bg ]] && bg="#1e1e2e" # last-resort fallback
fg="${COLORS[foreground]:-}"
accent="${COLORS[accent]:-}"
selection="${COLORS[selection_background]:-}"
# No day/night flag by design — the extension decides dark vs. light purely
# from the WCAG relative luminance of bg.
printf '{"theme_name":%s,"bg":%s,"fg":%s,"accent":%s,"selection_bg":%s,"chrome":%s}' \
"$(json_value "$name")" \
"$(json_value "$bg")" \
"$(json_value "$fg")" \
"$(json_value "$accent")" \
"$(json_value "$selection")" \
"$(json_value "$chrome")"
}
# ------------------------------------------------------------------ framing --
# Chromium expects each message prefixed with its byte length as a native-endian
# (little, on every platform we target) uint32.
emit() {
local json="$1" len
len=$(LC_ALL=C printf '%s' "$json" | wc -c)
printf '%b%s' \
"\\x$(printf '%02x' $((len & 0xff)))\\x$(printf '%02x' $((len >> 8 & 0xff)))\\x$(printf '%02x' $((len >> 16 & 0xff)))\\x$(printf '%02x' $((len >> 24 & 0xff)))" \
"$json" || exit 0 # stdout closed: the browser is gone
}
emit_theme() {
local state
state=$(build_state) || return 0
emit "$state"
}
# --------------------------------------------------------------------- main --
main() {
local starttime
trap cleanup EXIT
# Arm signal handlers before publishing the pidfile so refresh cannot signal
# the host during a window where USR1 still has its default fatal disposition.
trap 'exit 0' TERM INT
trap 'emit_theme' USR1
mkdir -p "$RUNDIR"
starttime=$(awk '{print $22}' "/proc/$$/stat")
[[ -n $starttime ]] || exit 1
printf '%s %s\n' "$$" "$starttime" >"$PIDFILE"
# Push the current theme immediately on connect, before arming the watchdog —
# if stdin is already at EOF the watchdog fires at once, and we'd otherwise be
# killed before saying anything.
emit_theme
# The browser talks to us by closing the pipe, not by sending anything we care
# about. Drain stdin so its writes never block, and exit when it hangs up.
#
# The `<&3` is load-bearing. Bash gives every background job /dev/null as stdin
# unless it's redirected explicitly, so a bare read loop here would see EOF
# instantly and kill us right after the first push — leaving the extension in a
# reconnect loop. Duplicating the real stdin onto fd 3 overrides the default.
exec 3<&0
(while IFS= read -r; do :; done <&3; kill -TERM "$$" 2>/dev/null) &
WATCHDOG_PID=$!
# Stay alive until the browser closes the pipe. A SIGUSR1 interrupts `wait`,
# runs the USR1 trap to push, and we resume waiting; when the watchdog exits
# (browser gone) `wait` succeeds and we fall through to the EXIT trap.
while ! wait "$WATCHDOG_PID"; do :; done
}
if [[ ${BASH_SOURCE[0]} == "$0" ]]; then
main "$@"
fi
-34
View File
@@ -1,34 +0,0 @@
#!/bin/bash
# omarchy:summary=Signal running theme-bridge hosts to push the current theme
# omarchy:hidden=true
# Nudge every running Omarchy theme-bridge host to re-read and push the current
# theme, so web-app extensions repaint live on a theme switch instead of waiting
# for the next reload. Called by omarchy-theme-set.
#
# The hosts (omarchy-chromium-theme-host, spoken to over com.omarchy.theme) are
# push-only and can't watch the filesystem, so each drops a pidfile in RUNDIR on
# connect and waits for SIGUSR1. We signal them here. Dead/garbage pidfiles are
# pruned. A no-op when no browser is connected — nothing to signal.
set -uo pipefail
RUNDIR="$XDG_RUNTIME_DIR/omarchy-theme"
[[ -d $RUNDIR ]] || exit 0
shopt -s nullglob
for pidfile in "$RUNDIR"/*.pid; do
pid=""
starttime=""
extra=""
read -r pid starttime extra <"$pidfile" || true
current_starttime=""
[[ $pid =~ ^[0-9]+$ && $starttime =~ ^[0-9]+$ && -z ${extra:-} ]] &&
current_starttime=$(awk '{print $22}' "/proc/$pid/stat" 2>/dev/null) || true
if [[ -n $current_starttime && $current_starttime == "$starttime" ]] &&
kill -USR1 "$pid" 2>/dev/null; then
continue
fi
# Host is gone (or the pidfile is garbage) — prune it.
rm -f "$pidfile"
done
-1
View File
@@ -19,7 +19,6 @@ copy_chromium_flags() {
cp -f "$OMARCHY_PATH/config/chromium-flags.conf" "$1"
omarchy-install-chromium-copy-url
omarchy-install-chromium-ytdlp
omarchy-install-chromium-theme
}
setup_firefox_preferences() {
-28
View File
@@ -1,28 +0,0 @@
#!/bin/bash
# omarchy:summary=Install the native messaging host for the Omarchy theme bridge
set -euo pipefail
HOST_NAME="com.omarchy.theme"
HOST_PATH="$OMARCHY_PATH/bin/omarchy-chromium-theme-host"
TEMPLATE="$OMARCHY_PATH/default/chromium/native-messaging-hosts/$HOST_NAME.json"
browser_dirs=(
"$HOME/.config/chromium"
"$HOME/.config/google-chrome"
"$HOME/.config/google-chrome-beta"
"$HOME/.config/google-chrome-unstable"
"$HOME/.config/BraveSoftware/Brave-Browser"
"$HOME/.config/BraveSoftware/Brave-Browser-Beta"
"$HOME/.config/BraveSoftware/Brave-Browser-Nightly"
"$HOME/.config/microsoft-edge"
"$HOME/.config/microsoft-edge-dev"
)
manifest=$(sed "s|__HOST_PATH__|$HOST_PATH|g" "$TEMPLATE")
for dir in "${browser_dirs[@]}"; do
mkdir -p "$dir/NativeMessagingHosts"
printf '%s\n' "$manifest" >"$dir/NativeMessagingHosts/$HOST_NAME.json"
done
-1
View File
@@ -18,7 +18,6 @@ omarchy-refresh-config chromium-flags.conf
# Install/refresh the native messaging hosts used by the bundled extensions
omarchy-install-chromium-copy-url
omarchy-install-chromium-ytdlp
omarchy-install-chromium-theme
# Re-install Google accounts if previously configured
if [[ $INSTALL_GOOGLE_ACCOUNTS == "true" ]]; then
-1
View File
@@ -199,7 +199,6 @@ post_theme_commands=(
omarchy-theme-set-pi
omarchy-theme-set-claude
omarchy-theme-set-browser
omarchy-chromium-theme-refresh
omarchy-theme-set-vscode
omarchy-theme-set-obsidian
omarchy-theme-set-keyboard