Reported symptom: Electron applications and a Chromium-based browser, all set to follow the system, went light when the desktop went light and never came back. Nothing reported an error, and the portal was serving the correct value the whole time. Cause: ColorScheme set gtk-theme to "Adwaita-dark" for dark and "Adwaita" for light. Neither is installed on Fedora 44 -- only adw-gtk3 and adw-gtk3-dark are. GTK responds to an unknown theme name by falling back to its built-in default, which is LIGHT. So asking for light worked by accident, asking for dark silently produced light, and anything that takes its cue from the GTK theme rather than the portal stayed light no matter what org.freedesktop.appearance said. Verified: the portal emits correctly in both directions, so this was never the portal's fault. Second cause, the mirror of the first: gtk-3.0/settings.ini and gtk-4.0/settings.ini were pinned to adw-gtk3-dark and prefer-dark=1 and never regenerated. Under GNOME that file is ignored because gnome-settings-daemon publishes over XSETTINGS; under Hyprland nothing does, so for GTK3 it is authoritative -- and it contradicted the scheme in light mode. They are now generated from a template on every switch, gitignored as machine state, and seeded by link-dotfiles, the same shape kitty's current-theme.conf already uses. These directories are symlinked into the repository, so writing the live file directly would dirty the working tree on every theme switch. The failure was silent by construction, so it gets a test rather than a comment: gtk-theme-contract asserts every theme name Panama sets is actually installed, and that the generated GTK config agrees with the scheme in both directions. Verified it catches both original bugs. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
93 lines
3.8 KiB
Bash
Executable File
93 lines
3.8 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
|
|
|
|
# ── 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
|
|
|
|
printf '{"scheme":"%s","kitty":"%s"}\n' "$scheme" "$status_kitty"
|