Two more applications that keep their own palette and so never followed the desktop. btop was on "Default" and had never been themed at all; tmux had Tokyo Night Moon hardcoded across seventeen lines, which meant a dark status bar sitting under a light terminal in light mode. Both themes are authored rather than borrowed. btop ships a "tokyo-night" theme, but it is the Night variant (#1a1b26) where the rest of this desktop is Moon (#222436), and two Tokyo Nights side by side read as a mistake; it ships no Tokyo Night light theme at all. Colours come from kitty's theme files so a terminal and what runs inside it cannot disagree. tmux follows kitty's shape: the colours move to themes/, tmux.conf sources a generated current-theme.conf, and running servers are re-sourced so an open session changes immediately rather than at next launch. btop is different -- it OWNS btop.conf and rewrites it on exit, so only the color_theme line is edited in place and the file is not symlinked into the repository. btop reads its theme once at startup, so a running instance keeps the old colours; forcing a restart would kill a process the user is watching. The tmux light theme took two passes. Mapping the palette role-for-role put the standard Day accents on a mid-grey panel at 2.74:1 and 2.94:1 -- under the 3:1 floor, on a bar you read at a glance. It now uses Day's darker accent variants on a lighter panel: 4.42:1 and 4.17:1, and 5.01:1 / 4.73:1 for the light text inside the inverted blocks. The helper also now reports every target rather than only kitty. Saying "kitty: applied" while silently skipping three other applications is how a half-applied theme goes unnoticed. Not changed: bat is configured with --theme ansi, which follows the terminal's own palette, so it already tracks kitty with nothing to do. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
150 lines
6.6 KiB
Bash
Executable File
150 lines
6.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Propagates the colour scheme to applications that do not read the desktop
|
|
# portal.
|
|
#
|
|
# Most modern applications DO follow org.freedesktop.portal.Settings and need
|
|
# nothing from us: GTK4/libadwaita, Qt6, Chromium and Electron all read
|
|
# org.freedesktop.appearance color-scheme, which xdg-desktop-portal-gtk serves
|
|
# from gsettings. Panama sets that, so those follow automatically.
|
|
#
|
|
# Terminals are the notable exception -- they predate the standard and carry
|
|
# their own palettes. kitty is handled here.
|
|
#
|
|
# GTK3 is the other one. Under GNOME, gnome-settings-daemon publishes the theme
|
|
# over XSETTINGS; under Hyprland nothing does, so ~/.config/gtk-3.0/settings.ini
|
|
# is authoritative for GTK3 applications. Pinned to dark, it contradicted the
|
|
# scheme in light mode, so it is generated from a template here instead.
|
|
#
|
|
# panama-theme-apps dark|light
|
|
#
|
|
# kitty gets it twice: the generated include file so terminals opened later
|
|
# start correct, and a live `set-colors` over its control socket so terminals
|
|
# already open change now. Without the second, a scheme change appears to do
|
|
# nothing until you open a new window.
|
|
|
|
set -euo pipefail
|
|
|
|
scheme="${1:-dark}"
|
|
case "$scheme" in
|
|
dark|light) ;;
|
|
*) printf 'usage: panama-theme-apps [dark|light]\n' >&2; exit 2 ;;
|
|
esac
|
|
|
|
# ── tmux ─────────────────────────────────────────────────────────────────────
|
|
# Generated like kitty's: tmux.conf sources current-theme.conf, and that file is
|
|
# machine state rather than configuration. Running servers are re-sourced so an
|
|
# open session changes now instead of at next launch -- tmux applies a
|
|
# source-file to every attached client immediately.
|
|
tmux_dir="${XDG_CONFIG_HOME:-$HOME/.config}/tmux"
|
|
tmux_theme="$tmux_dir/themes/tokyonight-moon.conf"
|
|
[[ "$scheme" == "light" ]] && tmux_theme="$tmux_dir/themes/tokyonight-day.conf"
|
|
|
|
status_tmux="skipped"
|
|
if [[ -r "$tmux_theme" ]]; then
|
|
if cp "$tmux_theme" "$tmux_dir/current-theme.conf.tmp" 2>/dev/null \
|
|
&& mv "$tmux_dir/current-theme.conf.tmp" "$tmux_dir/current-theme.conf" 2>/dev/null; then
|
|
status_tmux="written"
|
|
# Only if a server is actually running; `tmux source-file` would
|
|
# otherwise start one just to theme it.
|
|
if command -v tmux >/dev/null 2>&1 && tmux has-session 2>/dev/null; then
|
|
tmux source-file "$tmux_dir/current-theme.conf" 2>/dev/null \
|
|
&& status_tmux="applied to running sessions"
|
|
fi
|
|
else
|
|
rm -f "$tmux_dir/current-theme.conf.tmp"
|
|
status_tmux="failed"
|
|
fi
|
|
fi
|
|
|
|
# ── btop ─────────────────────────────────────────────────────────────────────
|
|
# Only the color_theme line is rewritten, in place. btop OWNS btop.conf -- it
|
|
# rewrites the whole file on exit -- so the config is not symlinked into Panama
|
|
# and not replaced wholesale here; just this one value is edited, and btop keeps
|
|
# it on the next write.
|
|
#
|
|
# btop reads its theme once at startup, so a running instance keeps the old
|
|
# colours until it is restarted. That is acceptable for a monitor you open when
|
|
# you want it, and forcing a restart would kill a process the user is watching.
|
|
btop_conf="${XDG_CONFIG_HOME:-$HOME/.config}/btop/btop.conf"
|
|
btop_theme="tokyonight-moon"
|
|
[[ "$scheme" == "light" ]] && btop_theme="tokyonight-day"
|
|
|
|
status_btop="skipped"
|
|
if [[ -w "$btop_conf" ]]; then
|
|
if sed -i "s|^color_theme *=.*|color_theme = \"$btop_theme\"|" "$btop_conf" 2>/dev/null; then
|
|
status_btop="written"
|
|
else
|
|
status_btop="failed"
|
|
fi
|
|
fi
|
|
|
|
# ── GTK ──────────────────────────────────────────────────────────────────────
|
|
# adw-gtk3, not Adwaita: no Adwaita GTK theme is installed on Fedora 44, and
|
|
# naming a theme that does not exist makes GTK fall back to its light default --
|
|
# which made dark mode silently produce light windows.
|
|
if [[ "$scheme" == "light" ]]; then
|
|
gtk_theme="adw-gtk3"
|
|
prefer_dark=0
|
|
else
|
|
gtk_theme="adw-gtk3-dark"
|
|
prefer_dark=1
|
|
fi
|
|
|
|
status_gtk="skipped"
|
|
for gtk_version in 3.0 4.0; do
|
|
gtk_dir="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-$gtk_version"
|
|
template="$gtk_dir/settings.ini.template"
|
|
[[ -r "$template" ]] || continue
|
|
|
|
# Written atomically: a GTK application starting mid-write would otherwise
|
|
# read a truncated file and fall back to defaults.
|
|
if sed -e "s/@GTK_THEME@/$gtk_theme/" -e "s/@PREFER_DARK@/$prefer_dark/" "$template" \
|
|
>"$gtk_dir/settings.ini.tmp" 2>/dev/null \
|
|
&& mv "$gtk_dir/settings.ini.tmp" "$gtk_dir/settings.ini" 2>/dev/null; then
|
|
status_gtk="written"
|
|
else
|
|
rm -f "$gtk_dir/settings.ini.tmp"
|
|
status_gtk="failed"
|
|
fi
|
|
done
|
|
|
|
kitty_dir="${XDG_CONFIG_HOME:-$HOME/.config}/kitty"
|
|
theme_file="$kitty_dir/themes/tokyonight-moon.conf"
|
|
[[ "$scheme" == "light" ]] && theme_file="$kitty_dir/themes/tokyonight-day.conf"
|
|
|
|
status_kitty="skipped"
|
|
if [[ -r "$theme_file" ]]; then
|
|
# Written atomically: kitty may read this while a new window is starting.
|
|
if cp "$theme_file" "$kitty_dir/current-theme.conf.tmp" 2>/dev/null \
|
|
&& mv "$kitty_dir/current-theme.conf.tmp" "$kitty_dir/current-theme.conf" 2>/dev/null; then
|
|
status_kitty="written"
|
|
fi
|
|
|
|
# Live-apply to running terminals. kitty appends its PID to the socket name
|
|
# from listen_on, so there is one socket per instance -- "unix:@mykitty"
|
|
# alone reaches nothing, which is exactly how this looked like remote
|
|
# control being disabled when it was not.
|
|
if command -v kitty >/dev/null 2>&1 && command -v ss >/dev/null 2>&1; then
|
|
applied=0
|
|
while read -r socket; do
|
|
[[ -n "$socket" ]] || continue
|
|
if kitty @ --to "unix:@${socket#@}" set-colors --all --configured "$theme_file" >/dev/null 2>&1; then
|
|
applied=$((applied + 1))
|
|
fi
|
|
done < <(ss -xl 2>/dev/null | grep -oE '@mykitty[^[:space:]]*' | sort -u)
|
|
(( applied > 0 )) && status_kitty="applied to $applied"
|
|
fi
|
|
fi
|
|
|
|
# Every target reports what actually happened. A helper that says only
|
|
# "kitty: applied" while silently skipping three other applications is how a
|
|
# half-applied theme goes unnoticed.
|
|
jq -cn \
|
|
--arg scheme "$scheme" \
|
|
--arg kitty "$status_kitty" \
|
|
--arg gtk "$status_gtk" \
|
|
--arg btop "$status_btop" \
|
|
--arg tmux "$status_tmux" \
|
|
'{scheme: $scheme, kitty: $kitty, gtk: $gtk, btop: $btop, tmux: $tmux}'
|