202 lines
8.4 KiB
Bash
202 lines
8.4 KiB
Bash
#!/bin/bash
|
||
# plymouth.sh — Plymouth boot splash installer
|
||
#
|
||
# Installs the M-Archy Plymouth theme: skull logo centred on a dark background
|
||
# with a magenta spinning-dot animation below it.
|
||
#
|
||
# SVG NOTE: Plymouth's image loader (ply-image) is PNG-only — it links against
|
||
# libpng and has no SVG or gdk-pixbuf dependency. The ply-image.h header is
|
||
# even commented "png file loader". bg-skull.svg must be converted to PNG with
|
||
# rsvg-convert (higher fidelity than ImageMagick for SVG) before deployment.
|
||
#
|
||
# Logo resolution order:
|
||
# 1. $PLYMOUTH_LOGO_SRC env var — caller-supplied custom image (PNG or SVG)
|
||
# 2. $DOTFILES_DIR/resources/bg-skull.svg — repo copy, always present
|
||
# 3. /root/installer/resources/bg-skull.svg — archiso embedded copy
|
||
#
|
||
# PNG inputs are used directly; SVG inputs are converted via rsvg-convert.
|
||
#
|
||
# Steps:
|
||
# 1. Install plymouth (extra repo)
|
||
# 2. Install librsvg (rsvg-convert) if logo is SVG; imagemagick for dot
|
||
# 3. Produce logo.png (300 px wide) from the resolved source
|
||
# 4. Generate a 10×10 magenta dot.png for the spinner
|
||
# 5. Write the m-archy theme (.plymouth descriptor + .script animation)
|
||
# 6. Register with plymouth-set-default-theme
|
||
# 7. Inject plymouth / sd-plymouth hook into /etc/mkinitcpio.conf
|
||
# 8. Add 'quiet splash' to GRUB_CMDLINE_LINUX_DEFAULT
|
||
# 9. Regenerate GRUB config and initramfs
|
||
|
||
set -euo pipefail
|
||
source "$(dirname "${BASH_SOURCE[0]}")/../lib/logging.sh"
|
||
|
||
THEME_DIR="/usr/share/plymouth/themes/m-archy"
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
DOTFILES_DIR="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||
|
||
# Resolve logo source — env var takes priority, then bundled SVG
|
||
LOGO_SRC="${PLYMOUTH_LOGO_SRC:-}"
|
||
if [[ -z "$LOGO_SRC" ]]; then
|
||
for _candidate in \
|
||
"$DOTFILES_DIR/resources/bg-skull.svg" \
|
||
"/root/installer/resources/bg-skull.svg"
|
||
do
|
||
if [[ -f "$_candidate" ]]; then
|
||
LOGO_SRC="$_candidate"
|
||
break
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# ── Install Plymouth ──────────────────────────────────────────────────────────
|
||
log "Installing Plymouth..."
|
||
sudo pacman -S --noconfirm --needed plymouth
|
||
|
||
# ── Ensure conversion tools ───────────────────────────────────────────────────
|
||
# imagemagick is always needed for the spinner dot.
|
||
# librsvg (rsvg-convert) is only needed when the logo source is an SVG.
|
||
if ! command -v convert &>/dev/null; then
|
||
log "Installing imagemagick (dot generation)..."
|
||
sudo pacman -S --noconfirm --needed imagemagick
|
||
fi
|
||
|
||
# ── Produce logo.png ──────────────────────────────────────────────────────────
|
||
TMP_LOGO="$(mktemp /tmp/plymouth-logo.XXXXXX.png)"
|
||
TMP_DOT="/tmp/plymouth-dot.png"
|
||
trap 'rm -f "$TMP_LOGO" "$TMP_DOT"' EXIT
|
||
|
||
if [[ -z "$LOGO_SRC" ]]; then
|
||
warn "No logo source found — using transparent placeholder."
|
||
convert -size 300x300 xc:transparent "$TMP_LOGO"
|
||
elif [[ "${LOGO_SRC,,}" == *.png ]]; then
|
||
log "Using PNG directly: $LOGO_SRC"
|
||
cp "$LOGO_SRC" "$TMP_LOGO"
|
||
else
|
||
# SVG (or unknown) — convert via rsvg-convert for best fidelity
|
||
if ! command -v rsvg-convert &>/dev/null; then
|
||
log "Installing librsvg (rsvg-convert) for SVG→PNG conversion..."
|
||
sudo pacman -S --noconfirm --needed librsvg
|
||
fi
|
||
log "Converting $LOGO_SRC → PNG (300 px wide)..."
|
||
rsvg-convert -w 300 "$LOGO_SRC" -o "$TMP_LOGO"
|
||
fi
|
||
|
||
# ── Generate spinner dot ──────────────────────────────────────────────────────
|
||
# 10×10 magenta circle — centred at (5,5), radius 4 px
|
||
convert -size 10x10 xc:transparent \
|
||
-fill '#E40046' \
|
||
-draw 'circle 5,5 5,1' \
|
||
"$TMP_DOT"
|
||
|
||
# ── Install theme files ───────────────────────────────────────────────────────
|
||
log "Installing M-Archy Plymouth theme..."
|
||
sudo mkdir -p "$THEME_DIR"
|
||
sudo cp "$TMP_LOGO" "$THEME_DIR/logo.png"
|
||
sudo cp "$TMP_DOT" "$THEME_DIR/dot.png"
|
||
|
||
sudo tee "$THEME_DIR/m-archy.plymouth" > /dev/null <<'EOF'
|
||
[Plymouth Theme]
|
||
Name=M-Archy
|
||
Description=M-Archy boot splash — skull logo with spinning dots
|
||
ModuleName=script
|
||
|
||
[script]
|
||
ImageDir=/usr/share/plymouth/themes/m-archy
|
||
ScriptFile=/usr/share/plymouth/themes/m-archy/m-archy.script
|
||
EOF
|
||
|
||
sudo tee "$THEME_DIR/m-archy.script" > /dev/null <<'EOF'
|
||
# M-Archy Plymouth splash — skull logo + magenta spinner
|
||
|
||
Window.SetBackgroundTopColor (0.10, 0.10, 0.10);
|
||
Window.SetBackgroundBottomColor (0.07, 0.07, 0.07);
|
||
|
||
screen_width = Window.GetWidth ();
|
||
screen_height = Window.GetHeight ();
|
||
|
||
# Centred skull logo
|
||
logo.image = Image ("logo.png");
|
||
logo.sprite = Sprite (logo.image);
|
||
logo.sprite.SetX (Math.Int (screen_width / 2 - logo.image.GetWidth () / 2));
|
||
logo.sprite.SetY (Math.Int (screen_height / 2 - logo.image.GetHeight () / 2));
|
||
logo.sprite.SetZ (10);
|
||
|
||
# 12-dot spinner below the logo
|
||
num_dots = 12;
|
||
dot_r = 5;
|
||
orbit = 35;
|
||
cx = screen_width / 2;
|
||
cy = screen_height / 2 + logo.image.GetHeight () / 2 + 55;
|
||
dot.image = Image ("dot.png");
|
||
|
||
for (i = 0; i < num_dots; i++) {
|
||
dot[i].sprite = Sprite (dot.image);
|
||
dot[i].sprite.SetZ (20);
|
||
}
|
||
|
||
frame = 0;
|
||
|
||
fun refresh_callback () {
|
||
frame++;
|
||
step = 2 * Math.Pi / num_dots;
|
||
for (i = 0; i < num_dots; i++) {
|
||
angle = step * i + frame * 0.15;
|
||
dot[i].sprite.SetX (Math.Int (cx + Math.Cos (angle) * orbit - dot_r));
|
||
dot[i].sprite.SetY (Math.Int (cy + Math.Sin (angle) * orbit - dot_r));
|
||
t = (i + Math.Int (frame / 4) % num_dots) % num_dots;
|
||
f = t / num_dots;
|
||
dot[i].sprite.SetOpacity (0.15 + 0.85 * f * f);
|
||
}
|
||
}
|
||
|
||
Plymouth.SetRefreshFunction (refresh_callback);
|
||
EOF
|
||
|
||
# ── Register theme ────────────────────────────────────────────────────────────
|
||
log "Registering m-archy as default Plymouth theme..."
|
||
sudo plymouth-set-default-theme m-archy
|
||
|
||
# ── mkinitcpio: inject Plymouth hook ─────────────────────────────────────────
|
||
log "Adding Plymouth hook to /etc/mkinitcpio.conf..."
|
||
if grep -q '\bplymouth\b\|sd-plymouth' /etc/mkinitcpio.conf; then
|
||
skip "Plymouth hook already present in mkinitcpio.conf"
|
||
else
|
||
# systemd hook → sd-plymouth goes after systemd
|
||
# traditional udev hook → plymouth goes after udev
|
||
if grep -qE 'HOOKS=\([^)]*\bsystemd\b' /etc/mkinitcpio.conf; then
|
||
sudo sed -Ei 's/(\bsystemd\b)( |\))/\1 sd-plymouth\2/' /etc/mkinitcpio.conf
|
||
log "Injected sd-plymouth hook after systemd"
|
||
else
|
||
sudo sed -Ei 's/(\budev\b)( |\))/\1 plymouth\2/' /etc/mkinitcpio.conf
|
||
log "Injected plymouth hook after udev"
|
||
fi
|
||
|
||
if ! grep -q '\bplymouth\b\|sd-plymouth' /etc/mkinitcpio.conf; then
|
||
warn "Could not auto-inject Plymouth hook."
|
||
warn "Manually add 'plymouth' after 'udev' in /etc/mkinitcpio.conf."
|
||
fi
|
||
fi
|
||
|
||
# ── GRUB: add quiet splash ────────────────────────────────────────────────────
|
||
GRUB_CONF="/etc/default/grub"
|
||
if [[ -f "$GRUB_CONF" ]]; then
|
||
if grep -q '\bsplash\b' "$GRUB_CONF"; then
|
||
skip "'splash' already present in $GRUB_CONF"
|
||
else
|
||
log "Adding 'quiet splash' to GRUB_CMDLINE_LINUX_DEFAULT..."
|
||
sudo sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/GRUB_CMDLINE_LINUX_DEFAULT="\1 quiet splash"/' "$GRUB_CONF"
|
||
sudo sed -i 's/quiet quiet/quiet/g' "$GRUB_CONF"
|
||
fi
|
||
log "Regenerating GRUB config..."
|
||
sudo grub-mkconfig -o /boot/grub/grub.cfg
|
||
else
|
||
warn "/etc/default/grub not found."
|
||
warn "If using systemd-boot, add 'quiet splash' to your loader entry manually."
|
||
fi
|
||
|
||
# ── Rebuild initramfs ─────────────────────────────────────────────────────────
|
||
log "Rebuilding initramfs (this bakes the theme into the initrd)..."
|
||
sudo mkinitcpio -P
|
||
|
||
log "Plymouth m-archy theme installed. Reboot to see the splash screen."
|