Files, Papers, Loupe and every other libadwaita application read their accent from the Settings portal, so they rendered in GNOME blue no matter which accent this desktop was set to -- correct on our own surfaces, wrong on half the screen. xdg-desktop-portal-gtk cannot serve org.freedesktop.appearance accent-color at all; the string does not appear in the 1.15.3 binary. The gnome backend serves it, so Settings now routes to gnome with gtk still listed behind it -- the frontend merges Settings backends in order, so color-scheme keeps resolving if the gnome backend is ever unavailable. GNOME's accent-color is a fixed enum of nine names rather than a color, so each of our eight accents carries its nearest member. Nearest by hue rather than by name: rose maps to red, because it is the red role in this palette. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
116 lines
5.4 KiB
Bash
Executable File
116 lines
5.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Choosing an accent must recolor libadwaita applications too.
|
|
#
|
|
# Files, Papers and Loupe read their accent from the Settings portal, so an
|
|
# accent that never reaches GNOME's accent-color key leaves half the desktop in
|
|
# GNOME blue while the other half wears the chosen color. That is invisible from
|
|
# inside Panama's own surfaces, which look correct either way.
|
|
#
|
|
# Three things have to line up, and none of them share a source:
|
|
# - config/Theme.qml carries the accent table with its `gnome` member
|
|
# - scripts/panama-theme-apps maps the same names in shell
|
|
# - the portal routes Settings to a backend that can serve accent-color
|
|
#
|
|
# Read-only apart from a gsettings *read*; it never sets an accent.
|
|
|
|
set -uo pipefail
|
|
|
|
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
theme="$repo_dir/config/dot/quickshell/config/Theme.qml"
|
|
script="$repo_dir/config/dot/quickshell/scripts/panama-theme-apps"
|
|
portals="$repo_dir/config/dot/xdg-desktop-portal/hyprland-portals.conf"
|
|
|
|
fail() {
|
|
printf 'adwaita accent contract: %s\n' "$1" >&2
|
|
exit 1
|
|
}
|
|
|
|
for path in "$theme" "$script" "$portals"; do
|
|
[[ -r "$path" ]] || fail "missing $path"
|
|
done
|
|
|
|
# ── The accent table ─────────────────────────────────────────────────────────
|
|
mapping="$(python3 - "$theme" <<'PYTHON'
|
|
import re, sys
|
|
source = open(sys.argv[1]).read()
|
|
table = re.search(r"readonly property var accents: \(\{(.*?)\n \}\)", source, re.S)
|
|
if not table:
|
|
raise SystemExit("accents table not found")
|
|
for line in table.group(1).splitlines():
|
|
name = re.search(r'"([a-z]+)":', line)
|
|
if not name:
|
|
continue
|
|
member = re.search(r'gnome: "([a-z]+)"', line)
|
|
print(name.group(1) + "\t" + (member.group(1) if member else ""))
|
|
PYTHON
|
|
)" || fail 'could not read the accent table from Theme.qml'
|
|
|
|
[[ -n "$mapping" ]] || fail 'the accent table is empty'
|
|
|
|
while IFS=$'\t' read -r name member; do
|
|
[[ -n "$name" ]] || continue
|
|
[[ -n "$member" ]] \
|
|
|| fail "the \"$name\" accent has no gnome member, so libadwaita applications keep the previous accent when it is chosen"
|
|
done <<<"$mapping"
|
|
|
|
# ── Every member must exist in GNOME's enum ──────────────────────────────────
|
|
# The enum is read from the system rather than hardcoded here: a hardcoded copy
|
|
# would still pass on a machine whose GNOME dropped or renamed a member, which
|
|
# is the case where gsettings silently refuses the write.
|
|
if command -v gsettings >/dev/null 2>&1; then
|
|
enum="$(gsettings range org.gnome.desktop.interface accent-color 2>/dev/null | tail -n +2 | tr -d "'")"
|
|
if [[ -n "$enum" ]]; then
|
|
while IFS=$'\t' read -r name member; do
|
|
[[ -n "$member" ]] || continue
|
|
grep -qx "$member" <<<"$enum" \
|
|
|| fail "the \"$name\" accent maps to \"$member\", which GNOME's accent-color enum does not publish"
|
|
done <<<"$mapping"
|
|
fi
|
|
fi
|
|
|
|
# ── The shell helper must agree with the table ───────────────────────────────
|
|
# panama-theme-apps carries its own copy of this mapping because a shell script
|
|
# cannot read a QML object. A copy that drifts is exactly how an accent ends up
|
|
# correct in Panama's own surfaces and wrong everywhere else.
|
|
shell_member() {
|
|
local name="$1" body
|
|
body="$(sed -n '/^gnome_accent() {/,/^}/p' "$script")"
|
|
[[ -n "$body" ]] || fail 'gnome_accent() is missing from panama-theme-apps'
|
|
local line
|
|
line="$(grep -E "^\s+${name}\)" <<<"$body" | head -1)"
|
|
if [[ -z "$line" ]]; then
|
|
# Not listed means it falls through to the default branch.
|
|
line="$(grep -E '^\s+\*\)' <<<"$body" | head -1)"
|
|
fi
|
|
sed -E "s/.*printf '([a-z]+)'.*/\1/" <<<"$line"
|
|
}
|
|
|
|
while IFS=$'\t' read -r name member; do
|
|
[[ -n "$name" ]] || continue
|
|
actual="$(shell_member "$name")"
|
|
[[ "$actual" == "$member" ]] \
|
|
|| fail "Theme.qml maps \"$name\" to \"$member\" but panama-theme-apps maps it to \"$actual\""
|
|
done <<<"$mapping"
|
|
|
|
# The helper also validates the accent name it is handed; an accent the table
|
|
# knows but the helper rejects silently degrades to blue.
|
|
accepted="$(grep -oE '^\s+blue\|[a-z|]+\)' "$script" | head -1 | tr -d ' )' )"
|
|
while IFS=$'\t' read -r name member; do
|
|
[[ -n "$name" ]] || continue
|
|
grep -qE "(^|\|)$name(\||$)" <<<"$accepted" \
|
|
|| fail "panama-theme-apps does not accept the \"$name\" accent, so choosing it falls back to blue"
|
|
done <<<"$mapping"
|
|
|
|
# ── The portal has to be able to serve it ────────────────────────────────────
|
|
# xdg-desktop-portal-gtk cannot serve accent-color, so routing Settings to gtk
|
|
# alone makes every mapping above inert -- correct on paper, invisible in use.
|
|
settings_line="$(grep -E '^org\.freedesktop\.impl\.portal\.Settings=' "$portals")" \
|
|
|| fail 'the portal config does not route Settings at all, so accent-color has no backend'
|
|
[[ "$settings_line" == *gnome* ]] \
|
|
|| fail "Settings is routed to \"${settings_line#*=}\", and only the gnome backend serves accent-color"
|
|
[[ "${settings_line#*=}" == gnome* ]] \
|
|
|| fail "the gnome backend must come first in \"${settings_line#*=}\" or gtk answers Settings and accent-color is never published"
|
|
|
|
printf 'adwaita accent contract: PASS (%d accents mapped)\n' "$(grep -c . <<<"$mapping")"
|