Give the desktop real themes, video wallpapers, and honest titlebars

Appearance now opens on Themes: light and dark side by side, each
remembering its own choice, over galleries of ten shipped themes —
Tokyo Moon and Day joined by Moon Rose, Catppuccin, Nord, Gruvbox and
Everforest in both modes. A theme is a complete palette: the catalog
lives in themes.json, Theme.qml reads every color token from the
active record, and one render pipeline carries it to kitty, tmux,
btop, GTK, Vicinae, Firefox's chrome, and the lock screen. The Theme
editor builds new ones from four wells — wheel, hex, or eyedropper —
with derived surfaces, a saturation slider, debounced fine-tune, and
effects that save with the theme. Custom edits finally keep GNOME's
accent, kitty's border, and hyprlock in sync.

Wallpapers can be video: mpvpaper per output, hardware-decoded, muted
and looped, supervised and respawned. Panama owns the pausing — games,
battery, and a bar pill for right now — because the compositor
rebuilds full-screen blur for every frame a video wallpaper draws.
The lock screen gets a still frame.

Titlebars stop lying. GNOME apps get close-only on your chosen side,
the maximize and double-click settings are gone, the Settings window
obeys the same rules, and its titlebar can be turned off entirely.
Typography becomes five labeled dropdowns instead of a wall of
samples.

Contracts updated and written throughout (165 now); per the redesign
workflow none were executed — the full sweep runs once at the end.

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-23 23:39:04 -04:00
parent 7578348db1
commit cb7c09d208
68 changed files with 6115 additions and 1138 deletions
+70 -11
View File
@@ -110,11 +110,18 @@ expected = {
"fontHinting": ("enum", '"slight"', "typography"),
"fontAntialiasing": ("enum", '"rgba"', "typography"),
"titlebarButtonSide": ("enum", '"right"', "titlebar"),
"titlebarMaximizeButton": ("bool", "false", "titlebar"),
"titlebarDoubleClick": ("enum", '"toggle-maximize"', "titlebar"),
"panamaTitlebar": ("bool", "true", "titlebar"),
"middleClickPaste": ("bool", "true", "pointer"),
}
# Deleted on purpose. Hyprland has no minimize and maximize is noise in a
# tiler, so neither button is offered -- and neither is a setting for it. A
# schema entry that comes back is a control that writes a preference nothing
# reads, which is worse than no control at all.
for gone in ("titlebarMaximizeButton", "titlebarDoubleClick"):
if re.search(r'key:\s*"' + gone + r'"', text):
raise SystemExit(f"{gone} is back in the schema; it was removed on purpose")
def block_for(key: str) -> str:
match = re.search(r"\{\s*\n\s*key:\s*\"" + re.escape(key) + r"\".*?\n\s{8}\}", text, re.S)
if not match:
@@ -134,7 +141,6 @@ enum_values = {
"fontHinting": ["none", "slight", "medium", "full"],
"fontAntialiasing": ["none", "grayscale", "rgba"],
"titlebarButtonSide": ["left", "right"],
"titlebarDoubleClick": ["toggle-maximize", "none"],
}
for key, values in enum_values.items():
block = block_for(key)
@@ -169,13 +175,39 @@ for needle in \
'Fonts.interfaceFonts' \
'Fonts.monospaceFonts' \
'gtk-enable-primary-paste' \
'button-layout' \
'action-double-click-titlebar'; do
'button-layout'; do
rg -Fq "$needle" "$service" || fail "DesktopStyle is missing $needle"
done
! rg -q 'sh -c|bash -c' "$service" \
|| fail 'DesktopStyle routes gsettings through a shell'
# ── The button layout is close-only, on either side ─────────────────────────
# A minimize button on Hyprland is a button that does nothing, and maximize is
# noise in a tiler. Neither token may reappear in the layout DesktopStyle
# pushes, and the double-click action is left at GNOME's default rather than
# being driven from a preference that no longer exists.
python3 - "$service" <<'PY' || fail 'the titlebar button layout is no longer close-only'
import re
import sys
text = open(sys.argv[1], encoding="utf-8").read()
block = re.search(r'function buttonLayout\(\).*?\n \}', text, re.S)
if not block:
raise SystemExit("DesktopStyle no longer builds a button layout")
body = block.group(0)
if '"close:appmenu"' not in body or '"appmenu:close"' not in body:
raise SystemExit("the layout is not close-only on both sides")
for token in ("minimize", "maximize"):
if token in body:
raise SystemExit(f"the button layout offers {token}, which Hyprland cannot honour")
if 'DesktopPreferences.get("titlebarButtonSide")' not in body:
raise SystemExit("the button side is no longer read from the schema")
for gone in ("titlebarMaximizeButton", "titlebarDoubleClick", "action-double-click-titlebar"):
if gone in text:
raise SystemExit(f"DesktopStyle still reads or writes {gone}")
PY
for group in typography themes titlebar; do
rg -q "\"$group\": \"appearance\"" "$search" \
|| fail "settings search does not route $group to Appearance"
@@ -183,8 +215,15 @@ done
rg -q '"pointer": "mouse"' "$search" \
|| fail 'settings search no longer routes pointer controls to Mouse'
# Typography is one Fonts card of five dropdowns plus Sizes and Rendering.
# The old split into "Shell typography" and "Application typography" is gone:
# it never said which font was the shell's and which was the applications',
# which was the one question the page existed to answer.
for needle in \
'title: "Application typography"' \
'title: "Fonts"' \
'title: "Sizes"' \
'title: "Rendering"' \
'setting: "interfaceFontSize"' \
'setting: "applicationFontSize"' \
'setting: "documentFontSize"' \
'setting: "monospaceFontSize"' \
@@ -193,14 +232,34 @@ for needle in \
'title: "Icons & pointer"' \
'DesktopStyle.cursorThemes' \
'DesktopStyle.iconThemes' \
'DesktopStyle.setApplicationFont(' \
'DesktopStyle.setDocumentFont(' \
'DesktopStyle.setMonospaceFont(' \
'title: "Titlebars"' \
'setting: "titlebarButtonSide"' \
'setting: "titlebarMaximizeButton"' \
'setting: "titlebarDoubleClick"'; do
'setting: "panamaTitlebar"' \
'setting: "titlebarButtonSide"'; do
rg -Fq "$needle" "$appearance" || fail "Appearance is missing $needle"
done
! rg -q 'setting: "titlebarMinimize|GTK theme|Shell theme' "$appearance" \
|| fail 'Appearance exposes an inert or separately-owned theme control'
# Five font rows, each naming what it controls, each a closed dropdown.
[[ "$(rg -c 'FontPicker \{' "$appearance")" == "5" ]] \
|| fail 'Appearance no longer offers exactly one FontPicker per font role'
for role in 'label: "Interface"' 'label: "Icons"' 'label: "Application"' \
'label: "Document"' 'label: "Monospace"'; do
rg -Fq "$role" "$appearance" || fail "the Fonts card is missing $role"
done
# The titlebar card must say why there is no minimize or maximize toggle,
# rather than leaving the absence looking like an oversight.
rg -Fq 'no minimize or maximize toggle' "$appearance" \
|| fail 'the Titlebars card does not explain why it offers only close'
for gone in 'setting: "titlebarMaximizeButton"' 'setting: "titlebarDoubleClick"' \
'setting: "titlebarMinimize' 'GTK theme' 'Shell theme' \
'title: "Shell typography"' 'title: "Application typography"'; do
if rg -Fq "$gone" "$appearance"; then
fail "Appearance exposes a retired, inert, or separately-owned control: $gone"
fi
done
rg -q 'setting: "middleClickPaste"' "$mouse" \
|| fail 'Mouse does not expose middle-click paste'