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
|
#!/bin/bash
# Install 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.
set -euo pipefail
repo="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
target="$HOME/.config/rofi/udt"
mkdir -p "$target" "$HOME/bin" "$HOME/.cache/wal"
# Generate every themed config from the selected scheme first: the rofi palette
# symlinked below is one of its outputs, so this has to run before anything is
# linked. It fails loudly if a role names a colour the scheme does not define,
# which is the whole point of keeping the colours in one place.
selector="$HOME/.config/udt/roles.conf"
if [ ! -f "$selector" ]; then
install -Dm644 "$repo/palette/roles.conf.default" "$selector"
echo "seeded $selector"
fi
"$repo/bin/udt-palette"
# Theme files are symlinked individually; accent.rasi is NOT, it points at the
# generated file in the wal cache instead.
for f in palette.rasi common.rasi menu.rasi list.rasi grid.rasi powermenu.rasi confirm.rasi; do
ln -sfn "$repo/rofi/udt/$f" "$target/$f"
done
# launcher.rasi is generated rather than symlinked: its wallpaper path comes
# from the wal cache and cannot be committed. Regenerating it is why re-running
# this script after moving the repo is safe.
rm -f "$target/launcher.rasi"
sed "s|@WPAPER@|$HOME/.cache/wal/wpaper|" \
"$repo/rofi/udt/launcher.rasi" > "$target/launcher.rasi"
# Seed the generated accent if it does not exist yet, so themes parse on a
# fresh install before any wallpaper has been set.
if [ ! -f "$HOME/.cache/wal/udt-accent.rasi" ]; then
cp "$repo/rofi/udt/accent.rasi" "$HOME/.cache/wal/udt-accent.rasi"
fi
ln -sfn "$HOME/.cache/wal/udt-accent.rasi" "$target/accent.rasi"
ln -sfn "$repo/bin/udt-accent" "$HOME/bin/udt-accent"
ln -sfn "$repo/bin/udt-palette" "$HOME/bin/udt-palette"
# The generated configs for everything that is not rofi. These are copied
# rather than symlinked: each app owns its config file and mixes theme keys
# with settings that are none of this repo's business.
scheme="$(sed -n 's/^scheme *= *//p' "$selector")"
# waybar reads whichever themes/<name>.css style.css imports, so write the file
# under the scheme's own name and repoint the import. The older per-flavour
# files in themes/ are left alone; they are simply no longer imported.
install -Dm644 "$repo/templates/waybar/theme.css" \
"$HOME/.config/waybar/themes/$scheme.css"
if [ -f "$HOME/.config/waybar/style.css" ]; then
sed -i "s|@import \"themes/.*\.css\";|@import \"themes/$scheme.css\";|" \
"$HOME/.config/waybar/style.css"
fi
install -Dm644 "$repo/templates/terminal/kitty-theme.conf" \
"$HOME/.config/kitty/current-theme.conf"
# Kvantum wants a directory per theme, named after itself, and qt5ct/qt6ct
# reach Qt apps through it. The theme is installed under one fixed name rather
# than one per scheme: Kvantum caches by name, so reusing it means a switch
# needs no change to kvantum.kvconfig and no second theme left behind.
kv="$HOME/.config/Kvantum/udt"
install -Dm644 "$repo/templates/kvantum/theme.kvconfig" "$kv/udt.kvconfig"
install -Dm644 "$repo/templates/kvantum/theme.svg" "$kv/udt.svg"
printf '[General]\ntheme=udt\n' > "$HOME/.config/Kvantum/kvantum.kvconfig"
# Obsidian and Typora need more than a copy: the Obsidian snippet has to be
# enabled in each vault's appearance.json without disturbing the snippets
# already listed there. Skipped silently when neither app is installed.
"$repo/bin/udt-appthemes" || true
# Stage the homepage stylesheet on the dashboard host. Staged, not installed:
# /opt/homepage/config is root-owned and this script does not hold root there.
# Never fatal, and never slow: a laptop away from that network must still be
# able to install the local theme, so the connect timeout is short and any
# failure is a warning.
if command -v scp >/dev/null 2>&1; then
if scp -q -o ConnectTimeout=5 -o BatchMode=yes \
"$repo/templates/homepage/custom.css" \
homepage:hp-stage/custom.css 2>/dev/null; then
echo "homepage: staged custom.css ($scheme)"
echo " finish with: ssh homepage 'sudo cp ~/hp-stage/custom.css /opt/homepage/config/custom.css'"
else
echo "homepage: unreachable, skipped" >&2
fi
fi
# Reload what is running. Writing the configs is not enough: waybar, kitty and
# Hyprland reread on a signal, dunst and conky only on a restart, and rofi
# reads its theme per launch so it needs nothing. Each is guarded, because none
# of them is necessarily running, and a missing one is not an error.
reloaded=""
pgrep -x waybar >/dev/null 2>&1 && killall -SIGUSR2 waybar 2>/dev/null && reloaded="$reloaded waybar"
pgrep -x kitty >/dev/null 2>&1 && pkill -USR1 -x kitty 2>/dev/null && reloaded="$reloaded kitty"
command -v hyprctl >/dev/null 2>&1 && hyprctl reload >/dev/null 2>&1 && reloaded="$reloaded hyprland"
# udt-accent regenerates the accent and restarts dunst itself. It needs a
# wallpaper to read; without one the accent keeps its current value.
if command -v udt-accent >/dev/null 2>&1 && [ -e "$HOME/.cache/wal/wpaper" ]; then
udt-accent "$HOME/.cache/wal/wpaper" >/dev/null 2>&1 && reloaded="$reloaded accent+dunst"
fi
# conky has no hot-reload and nothing respawns it, so it is restarted only if
# it was already running.
if pgrep -x conky >/dev/null 2>&1; then
pkill -x conky 2>/dev/null
sleep 0.5
(conky -d >/dev/null 2>&1 &)
reloaded="$reloaded conky"
fi
[ -n "$reloaded" ] && echo "reloaded:$reloaded"
echo "installed:"
ls -l "$target" "$HOME/bin/udt-accent"
|