1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
#!/bin/bash
# Install waybar-theme-udt by symlink, so the repo stays canonical.
# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
# Licensed under the GNU General Public License v2 only.
#
# Installs to ~/.config/waybar-udt/, which is a separate config directory from
# the stock ~/.config/waybar/: that one is left on disk untouched, so its
# modules and scripts stay available to go back to.
#
# Nothing is started here. Hyprland launches the bar on login from
# ~/.config/hypr/sections/autostart.lua; the command is printed at the end for
# starting it by hand.
set -euo pipefail
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
target="$HOME/.config/waybar-udt"
udt="$(cd "$repo/../unified-desktop-theme" 2>/dev/null && pwd || true)"
icons="$HOME/.local/share/icons/Material-Black-Plum-Suru"
mkdir -p "$target/modules/hyprland" "$target/modules/custom" \
"$target/modules/extras" "$target/modules/image" \
"$target/styles" "$HOME/bin"
# ---------------------------------------------------------------- colours --
# The palette is udt's, not this repo's. Generating it needs the sibling
# checkout, so a missing one is a clear failure rather than a bar with no
# colours: every stylesheet below names @main-bg and friends.
if [ -z "$udt" ]; then
echo "error: unified-desktop-theme not found next to this repo" >&2
echo " expected at $repo/../unified-desktop-theme" >&2
exit 1
fi
"$udt/bin/udt-palette"
install -Dm644 "$udt/templates/waybar/theme.css" "$target/styles/theme.css"
# The dot scripts are bash, not CSS, so they cannot read @define-color. Write
# the handful of colours they need as a shell fragment they source.
#
# The values are read back out of the stylesheet udt-palette just generated,
# because that is the only place they exist in a form this script can see:
# udt-palette renders files, it does not answer queries about single roles.
#
# Pango wants a colour it can parse, and the generated file mixes #rrggbb with
# rgb()/rgba() spellings, so each is normalised to hex on the way out.
scheme="$(sed -n 's/^scheme *= *//p' "$HOME/.config/udt/roles.conf")"
css_color() {
# Last definition wins, matching how GTK resolves a redefined colour.
sed -n "s/^@define-color $1 *\(.*\);\$/\1/p" "$target/styles/theme.css" | tail -1
}
to_hex() {
python3 -c '
import re, sys
v = sys.argv[1].strip()
m = re.match(r"rgba?\(([^)]*)\)", v)
if m:
p = [x.strip() for x in m.group(1).split(",")]
print("#%02x%02x%02x" % tuple(int(float(c)) for c in p[:3]))
else:
print(v)
' "$2"
}
{
echo "# Generated by waybar-theme-udt/install.sh from the $scheme scheme."
echo "# Sourced by vms_dots.sh and privacy_dots.sh. Do not edit."
# The generated stylesheet carries no success/info roles, so the dots use
# the palette names it does define. green/teal/mauve are role-resolved by
# udt-palette, so they still follow the scheme.
for pair in "SUCCESS:green" "WARNING:warning" "CRITICAL:critical" \
"INFO:teal" "ACCENT:mauve" "FAINT:overlay0"; do
var="${pair%%:*}"
raw="$(css_color "${pair##*:}")"
[ -n "$raw" ] && printf 'DOT_%s="%s"\n' "$var" "$(to_hex "$var" "$raw")"
done
} > "$target/dots.colors"
# ------------------------------------------------------------------ files --
# Config and modules are symlinked: this repo owns them outright, so linking
# means the installed bar cannot drift from what is committed.
#
# Links whose source has gone are pruned first. Linking alone never removes
# anything, so a module renamed or dropped in the repo would otherwise leave a
# dangling link behind for every later install to step over.
find "$target" -xtype l -delete 2>/dev/null || true
ln -sfn "$repo/config.jsonc" "$target/config.jsonc"
for f in modules/clock.jsonc \
modules/hyprland/workspaces.jsonc \
modules/custom/vmdot.jsonc modules/custom/privacy_dots.jsonc \
modules/custom/presentation.jsonc modules/custom/mail.jsonc \
modules/extras/taskbar.jsonc modules/extras/tray.jsonc \
modules/image/volume.jsonc modules/image/language.jsonc; do
ln -sfn "$repo/$f" "$target/$f"
done
for f in style.css fonts.css global.css pills.css; do
ln -sfn "$repo/styles/$f" "$target/styles/$f"
done
# modules.css is generated rather than linked: it carries the icon theme's
# absolute path, which cannot be committed, and the accent-tinted launcher.
sed -e "s|@ICONS@|$icons|g" -e "s|@CONFIG@|$target|g" \
"$repo/styles/modules.css" > "$target/styles/modules.css"
# The launcher module is generated for the same reason. A module's `path` is
# NOT shell-expanded the way `exec` is, so it needs the absolute path written
# in: with "$HOME/..." waybar finds no file and the module draws nothing, with
# no error to say why.
#
# The target is removed first. An earlier install symlinked this file, and a
# redirect onto a surviving link writes THROUGH it: the shell truncates the
# link's target, which is the repo's own copy, before sed reads it. That
# emptied the source file once already.
rm -f "$target/modules/image/launcher.jsonc"
sed "s|@CONFIG@|$target|g" \
"$repo/modules/image/launcher.jsonc" > "$target/modules/image/launcher.jsonc"
# The flags ship as they are; the Slackware mark is monochrome, so it is
# tinted here. It sits ON the accent pill, so it takes the bar's background
# colour rather than the accent: filled with the accent it would be invisible
# against its own pill, which is exactly what the first version did.
mark="$(sed -n 's/^@define-color main-bg *\(.*\);$/\1/p' "$target/styles/theme.css" | head -1)"
mark="${mark:-#24273a}"
sed "s|@ACCENT@|$mark|" "$repo/icons/slackware.svg" > "$target/slackware.svg"
install -Dm644 "$repo/icons/flag-it.svg" "$target/flag-it.svg"
install -Dm644 "$repo/icons/flag-gb.svg" "$target/flag-gb.svg"
# ---------------------------------------------------------------- scripts --
# The two dot scripts used to live only in ~/bin, in no repository at all.
# They are this repo's now, and ~/bin gets links. Any real file found there is
# kept: it is the only copy of whatever was running before.
for s in vms_dots.sh privacy_dots.sh; do
if [ -f "$HOME/bin/$s" ] && [ ! -L "$HOME/bin/$s" ]; then
mv "$HOME/bin/$s" "$HOME/bin/$s.pre-udt"
echo "kept your $s as ~/bin/$s.pre-udt"
fi
ln -sfn "$repo/bin/$s" "$HOME/bin/$s"
done
ln -sfn "$repo/bin/wb-icon" "$HOME/bin/wb-icon"
ln -sfn "$repo/bin/wb-lang" "$HOME/bin/wb-lang"
# ----------------------------------------------------------------- checks --
# A missing icon renders as an empty pill and nothing says why, so the names
# are checked here, while someone is watching.
"$repo/bin/wb-icon" --selftest
echo
echo "installed to $target"
echo "run it with: waybar -c $target/config.jsonc -s $target/styles/style.css"
echo "hyprland starts it on login; see ~/.config/hypr/sections/autostart.lua"
|