aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-16 09:30:19 +0200
committerDanilo M. <danix@danix.xyz>2026-09-16 09:30:19 +0200
commita366de437867f29ffd58673f6d1b6359135e1cad (patch)
tree316857551e81803cd7cb138ffbdf1cb5315ca877
parent82dfcae2225e4313f400e87e97b1e5f42a0e7b3f (diff)
downloadunified-desktop-theme-a366de437867f29ffd58673f6d1b6359135e1cad.tar.gz
unified-desktop-theme-a366de437867f29ffd58673f6d1b6359135e1cad.zip
fix(gtk): derive the twelve computed tints from the palette too
Twelve hexes were shades upstream computed from a palette colour rather than taking one. They were left literal on the same reasoning as the neutral greys, which was wrong: a grey is shading, but each of these paints one widget surface in a colour that is supposed to be the theme's. Under any scheme but Macchiato they stayed Macchiato, including the window close, minimise and maximise hover fills. They are substituted as @ROLE_PCT@ now, the percentage being that shade's brightness relative to its base. shade() scales each channel and clamps, so it keeps the relationship rather than the exact upstream value; closest on the accent family, crudest on the reds, where upstream darkened toward saturation. GTK4 carries ten of the twelve: the selected progress bar and the selection-mode titlebar backdrop are GTK3-only widgets upstream. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
-rwxr-xr-xbin/udt-palette37
-rw-r--r--templates/gtk/gtk3.css.in24
-rw-r--r--templates/gtk/gtk4.css.in20
3 files changed, 59 insertions, 22 deletions
diff --git a/bin/udt-palette b/bin/udt-palette
index a9aa005..95b9092 100755
--- a/bin/udt-palette
+++ b/bin/udt-palette
@@ -368,6 +368,38 @@ def gen_kvantum(res, scheme, palette, template):
return out
+# Shades upstream computed from a palette colour rather than taking one. Each
+# paints exactly one widget surface, so leaving them literal (the rule that is
+# right for the neutral greys) left twelve lavender and Macchiato-tinted spots
+# on every other scheme: the window close/min/max hover fills among them.
+#
+# The percentage is that shade's brightness relative to its base, measured off
+# the Macchiato theme these were derived from. Reproducing the exact upstream
+# value is not the goal; keeping the relationship is.
+GTK_TINTS = [
+ ("@ACCENT_93@", "accent", 93),
+ ("@ACCENT_103@", "accent", 103),
+ ("@ACCENT_109@", "accent", 109),
+ ("@ACCENT_118@", "accent", 118),
+ ("@CRITICAL_110@", "critical", 110),
+ ("@CRITICAL_92@", "critical", 92),
+ ("@CRITICAL_79@", "critical", 79),
+ ("@WARNING_105@", "warning", 105),
+ ("@WARNING_94@", "warning", 94),
+ ("@WARNING_86@", "warning", 86),
+ ("@SUCCESS_109@", "success", 109),
+ ("@SUCCESS_81@", "success", 81),
+]
+
+
+def shade(c, pct):
+ """Scale a colour's channels by pct, clamped to 0-255."""
+ r, g, b, a = c
+ return (min(255, round(r * pct / 100)),
+ min(255, round(g * pct / 100)),
+ min(255, round(b * pct / 100)), a)
+
+
def gen_gtk(res, scheme, palette, template):
"""GTK3/GTK4: substitute the palette into the upstream stylesheet.
@@ -380,6 +412,10 @@ def gen_gtk(res, scheme, palette, template):
exactly as drawn, the same rule the Kvantum SVG follows.
"""
out = template
+ # Tints first: @ACCENT_93@ starts with @ACCENT, so the plain role loop
+ # below would otherwise replace that prefix and leave a stray "_93@".
+ for placeholder, role, pct in GTK_TINTS:
+ out = out.replace(placeholder, hex6(shade(res[role], pct)))
for role in GTK_ROLES:
# _RGB@ first: @FG@ is a prefix of @FG_RGB@, so the bare form would
# otherwise eat the start of the triple placeholder and leave "_RGB@".
@@ -732,6 +768,7 @@ def selftest():
gtk_dir = REPO / "templates" / "gtk"
known = {f"@{r.upper()}@" for r in GTK_ROLES}
known |= {f"@{r.upper()}_RGB@" for r in GTK_ROLES}
+ known |= {placeholder for placeholder, _, _ in GTK_TINTS}
known.add("@MAUVE@")
for tpl in sorted(gtk_dir.glob("*.in")) + sorted((gtk_dir / "assets").glob("*.in")):
used = set(re.findall(r"@[A-Z][A-Z_]*@", tpl.read_text()))
diff --git a/templates/gtk/gtk3.css.in b/templates/gtk/gtk3.css.in
index 5ef6d70..10b9b53 100644
--- a/templates/gtk/gtk3.css.in
+++ b/templates/gtk/gtk3.css.in
@@ -1510,7 +1510,7 @@ searchbar > revealer > box {
.titlebar.selection-mode:backdrop {
color: rgba(@BG_DEEP_RGB@, 0.6);
- background-color: #d3d7fb;
+ background-color: @ACCENT_109@;
}
.titlebar.selection-mode .subtitle:link {
@@ -1816,7 +1816,7 @@ treeview.view.progressbar {
treeview.view.progressbar:selected, treeview.view.progressbar:selected:hover, treeview.view.progressbar:selected:focus {
box-shadow: none;
- background-color: #bfc5f8;
+ background-color: @ACCENT_103@;
color: rgba(@BG_DEEP_RGB@, 0.87);
}
@@ -2614,7 +2614,7 @@ check:checked:hover, check:indeterminate:hover,
radio:checked:hover,
radio:indeterminate:hover {
box-shadow: 0 0 0 6px rgba(@ACCENT_RGB@, 0.15);
- background-color: #e5e8fd;
+ background-color: @ACCENT_118@;
}
check:checked:active, check:indeterminate:active,
@@ -3872,7 +3872,7 @@ infobar.action > revealer > box button, infobar.action > revealer > box button:h
}
infobar.action:hover > revealer > box, infobar.question:hover > revealer > box {
- background-color: #a0a8f6;
+ background-color: @ACCENT_93@;
}
infobar.warning > revealer > box, infobar.warning:backdrop > revealer > box {
@@ -3888,7 +3888,7 @@ infobar.warning > revealer > box button, infobar.warning > revealer > box button
}
infobar.warning:hover > revealer > box {
- background-color: #eaca89;
+ background-color: @WARNING_94@;
}
infobar.error > revealer > box, infobar.error:backdrop > revealer > box {
@@ -3905,7 +3905,7 @@ infobar.error > revealer > box button, infobar.error > revealer > box button:hov
}
infobar.error:hover > revealer > box {
- background-color: #ea7183;
+ background-color: @CRITICAL_92@;
}
/************
@@ -4170,7 +4170,7 @@ button.minimize.titlebutton:not(.suggested-action):not(.destructive-action) {
}
button.minimize.titlebutton:active:not(.suggested-action):not(.destructive-action) {
- background-color: #eedbb5;
+ background-color: @WARNING_105@;
}
button.maximize.titlebutton:not(.suggested-action):not(.destructive-action) {
@@ -4178,7 +4178,7 @@ button.maximize.titlebutton:not(.suggested-action):not(.destructive-action) {
}
button.maximize.titlebutton:active:not(.suggested-action):not(.destructive-action) {
- background-color: #b8e0ad;
+ background-color: @SUCCESS_109@;
}
button.close.titlebutton:not(.suggested-action):not(.destructive-action) {
@@ -4186,7 +4186,7 @@ button.close.titlebutton:not(.suggested-action):not(.destructive-action) {
}
button.close.titlebutton:active:not(.suggested-action):not(.destructive-action) {
- background-color: #eea2ae;
+ background-color: @CRITICAL_110@;
}
#MozillaGtkWidget.background headerbar.titlebar.default-decoration button.minimize.titlebutton, .background.csd headerbar.titlebar.default-decoration button.minimize.titlebutton:not(.suggested-action):not(.destructive-action), #MozillaGtkWidget.background headerbar.titlebar.default-decoration button.maximize.titlebutton, .background.csd headerbar.titlebar.default-decoration button.maximize.titlebutton:not(.suggested-action):not(.destructive-action), #MozillaGtkWidget.background headerbar.titlebar.default-decoration button.close.titlebutton, .background.csd headerbar.titlebar.default-decoration button.close.titlebutton:not(.suggested-action):not(.destructive-action) {
@@ -8472,11 +8472,11 @@ read if you used those and something break with a version upgrade you're on your
@define-color wm_unfocused_bg @BG@;
@define-color wm_button_icon white;
@define-color wm_button_close_hover_bg @CRITICAL@;
-@define-color wm_button_close_active_bg #e55267;
+@define-color wm_button_close_active_bg @CRITICAL_79@;
@define-color wm_button_max_hover_bg @SUCCESS@;
-@define-color wm_button_max_active_bg #80ca68;
+@define-color wm_button_max_active_bg @SUCCESS_81@;
@define-color wm_button_min_hover_bg @WARNING@;
-@define-color wm_button_min_active_bg #e5bd6b;
+@define-color wm_button_min_active_bg @WARNING_86@;
/*
FIXME this is really an API */
@define-color content_view_bg @BG@;
diff --git a/templates/gtk/gtk4.css.in b/templates/gtk/gtk4.css.in
index 63d845d..d528b20 100644
--- a/templates/gtk/gtk4.css.in
+++ b/templates/gtk/gtk4.css.in
@@ -3520,7 +3520,7 @@ check:checked:hover, check:indeterminate:hover,
radio:checked:hover,
radio:indeterminate:hover {
box-shadow: 0 0 0 6px rgba(@ACCENT_RGB@, 0.15);
- background-color: #e5e8fd;
+ background-color: @ACCENT_118@;
}
check:checked:active, check:indeterminate:active,
@@ -5398,7 +5398,7 @@ infobar.action > revealer > box *:link, infobar.action:backdrop > revealer > box
}
infobar.action:hover > revealer > box, infobar.question:hover > revealer > box {
- background-color: #a0a8f6;
+ background-color: @ACCENT_93@;
}
infobar.warning > revealer > box, infobar.warning:backdrop > revealer > box {
@@ -5415,7 +5415,7 @@ infobar.warning > revealer > box *:link, infobar.warning:backdrop > revealer > b
}
infobar.warning:hover > revealer > box {
- background-color: #eaca89;
+ background-color: @WARNING_94@;
}
infobar.error > revealer > box, infobar.error:backdrop > revealer > box {
@@ -5432,7 +5432,7 @@ infobar.error > revealer > box *:link, infobar.error:backdrop > revealer > box *
}
infobar.error:hover > revealer > box {
- background-color: #ea7183;
+ background-color: @CRITICAL_92@;
}
/************
@@ -5657,7 +5657,7 @@ windowcontrols > button.minimize:not(.suggested-action):not(.destructive-action)
}
windowcontrols > button.minimize:active:not(.suggested-action):not(.destructive-action) > image {
- background-color: #eedbb5;
+ background-color: @WARNING_105@;
}
windowcontrols > button.maximize:not(.suggested-action):not(.destructive-action) > image {
@@ -5665,7 +5665,7 @@ windowcontrols > button.maximize:not(.suggested-action):not(.destructive-action)
}
windowcontrols > button.maximize:active:not(.suggested-action):not(.destructive-action) > image {
- background-color: #b8e0ad;
+ background-color: @SUCCESS_109@;
}
windowcontrols > button.close:not(.suggested-action):not(.destructive-action) > image {
@@ -5673,7 +5673,7 @@ windowcontrols > button.close:not(.suggested-action):not(.destructive-action) >
}
windowcontrols > button.close:active:not(.suggested-action):not(.destructive-action) > image {
- background-color: #eea2ae;
+ background-color: @CRITICAL_110@;
}
windowcontrols {
@@ -8354,11 +8354,11 @@ read if you used those and something break with a version upgrade you're on your
@define-color wm_unfocused_bg @BG@;
@define-color wm_button_icon white;
@define-color wm_button_close_hover_bg @CRITICAL@;
-@define-color wm_button_close_active_bg #e55267;
+@define-color wm_button_close_active_bg @CRITICAL_79@;
@define-color wm_button_max_hover_bg @SUCCESS@;
-@define-color wm_button_max_active_bg #80ca68;
+@define-color wm_button_max_active_bg @SUCCESS_81@;
@define-color wm_button_min_hover_bg @WARNING@;
-@define-color wm_button_min_active_bg #e5bd6b;
+@define-color wm_button_min_active_bg @WARNING_86@;
/*
FIXME this is really an API */
@define-color content_view_bg @BG@;