#!/bin/bash # Install waybar-theme-udt by symlink, so the repo stays canonical. # Copyright (C) 2026 Danilo M. # 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's install.sh calls this script, and it has already run udt-palette by # then. Running it again would be harmless but pointless, so it says so. if [ "${UDT_PALETTE_DONE:-}" != "1" ]; then "$udt/bin/udt-palette" fi 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/custom/launcher.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 carries no generated path any more: its mark is a CSS # background, so modules.css owns the paths and the module file is a plain # symlink like every other. # The flags ship as they are; the Slackware mark is monochrome, so it is # tinted here, twice. The pill inverts on hover, so the mark has to invert # with it: dark on the accent pill at rest, light on the dark pill hovered. # One mark and one pill colour would always collide in one of the two states, # which is exactly what shipped twice before this. mark_dark="$(sed -n 's/^@define-color main-bg *\(.*\);$/\1/p' "$target/styles/theme.css" | head -1)" mark_light="$(sed -n 's/^@define-color main-fg *\(.*\);$/\1/p' "$target/styles/theme.css" | head -1)" mark_dark="${mark_dark:-#24273a}" mark_light="${mark_light:-#cad3f5}" sed "s|@ACCENT@|$mark_dark|" "$repo/icons/slackware.svg" > "$target/slackware.svg" sed "s|@MARK_LIGHT@|$mark_light|" "$repo/icons/slackware-light.svg" > "$target/slackware-light.svg" install -Dm644 "$repo/icons/flag-it.svg" "$target/flag-it.svg" install -Dm644 "$repo/icons/burger.svg" "$target/burger.svg" # Files an earlier install generated that nothing references any more. The # prune above only clears dangling SYMLINKS, and these were written as real # files, so nothing else removes them: the UK flag the hamburger replaced, and # the launcher from when it was an image module. rm -f "$target/flag-gb.svg" "$target/modules/image/launcher.jsonc" # ---------------------------------------------------------------- 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"