diff --git a/dotfiles/.config/hypr/conf/autostart.lua b/dotfiles/.config/hypr/conf/autostart.lua index b35b3bbcf..a9ef35183 100644 --- a/dotfiles/.config/hypr/conf/autostart.lua +++ b/dotfiles/.config/hypr/conf/autostart.lua @@ -28,8 +28,13 @@ hl.on("hyprland.start", function () -- Start waybar hl.exec_cmd(HOME .. "/.config/waybar/launch.sh") - -- Start polkit daemon - hl.exec_cmd("/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1") + -- Start polkit agent: prefer hyprpolkitagent.service (Ubuntu, via + -- packages-ubuntu -- its unit is WantedBy=graphical-session.target, + -- which Hyprland never activates, so start it explicitly), falling + -- back to polkit-gnome-authentication-agent-1 where that unit + -- doesn't exist. Only one should run -- starting both means + -- duplicate polkit auth dialogs. + hl.exec_cmd("systemctl --user start hyprpolkitagent.service 2>/dev/null || /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 || true") -- Restore wallpaper (skip for quickshell — handled inside ml4w-autostart) if wallpaper_app ~= "quickshell" then @@ -42,8 +47,10 @@ hl.on("hyprland.start", function () -- Load GTK settings hl.exec_cmd("~/.config/hypr/scripts/gtk.sh") - -- Start swaync - hl.exec_cmd("swaync") + -- Start swaync -- skipped where D-Bus activation is already set up + -- (marker written by post-ubuntu.sh), since an explicit exec-once + -- there raced with it and lost with "already running!". + hl.exec_cmd("[ -f ~/.config/ml4w/.swaync-dbus-activated ] || swaync") -- Start hypridle hl.exec_cmd("hypridle") diff --git a/dotfiles/.config/hypr/scripts/launcher.sh b/dotfiles/.config/hypr/scripts/launcher.sh index c813c9136..dfd4b4624 100755 --- a/dotfiles/.config/hypr/scripts/launcher.sh +++ b/dotfiles/.config/hypr/scripts/launcher.sh @@ -7,7 +7,7 @@ launcher=$(cat $HOME/.config/ml4w/settings/launcher) # Use Walker _launch_walker() { - $HOME/.config/walker/launch.sh --height 500 + walker -t ml4w --height 500 } # Use Rofi diff --git a/dotfiles/.config/matugen/config.toml b/dotfiles/.config/matugen/config.toml index 5b4d57fea..aa395b264 100644 --- a/dotfiles/.config/matugen/config.toml +++ b/dotfiles/.config/matugen/config.toml @@ -23,6 +23,10 @@ input_path = '~/.config/matugen/templates/hyprland-colors.lua' output_path = '~/.config/hypr/colors.lua' post_hook = 'hyprctl reload' +[templates.hyprtoolkit] +input_path = '~/.config/matugen/templates/hyprtoolkit-colors.conf' +output_path = '~/.config/hypr/hyprtoolkit.conf' + [templates.waybar] input_path = '~/.config/matugen/templates/colors.css' output_path = '~/.config/waybar/colors.css' @@ -48,6 +52,10 @@ output_path = '~/.cache/wal/colors.json' input_path = '~/.config/matugen/templates/colors.css' output_path = '~/.config/swaync/colors.css' +[templates.walker] +input_path = '~/.config/matugen/templates/colors.css' +output_path = '~/.config/walker/colors.css' + [templates.sequences] input_path = '~/.config/matugen/templates/sequences' output_path = '~/.cache/wal/sequences' diff --git a/dotfiles/.config/matugen/templates/hyprtoolkit-colors.conf b/dotfiles/.config/matugen/templates/hyprtoolkit-colors.conf new file mode 100644 index 000000000..baed3b035 --- /dev/null +++ b/dotfiles/.config/matugen/templates/hyprtoolkit-colors.conf @@ -0,0 +1,15 @@ +background = 0xff{{colors.surface_dim.default.hex_stripped}} +base = 0xff{{colors.surface_container.default.hex_stripped}} +text = 0xff{{colors.on_surface.default.hex_stripped}} +alternate_base = 0xff{{colors.surface_container_high.default.hex_stripped}} +bright_text = 0xff{{colors.inverse_on_surface.default.hex_stripped}} +link_text = 0xff{{colors.tertiary.default.hex_stripped}} +accent = 0xff{{colors.primary.default.hex_stripped}} +accent_secondary = 0xff{{colors.secondary.default.hex_stripped}} + +# Static (not wallpaper-derived) -- libadwaita's own corner-radius +# convention: 12px for windows/cards, 9px for controls like buttons. +rounding_large = 12 +rounding_small = 9 +font_family = Ubuntu Sans + diff --git a/dotfiles/.config/ml4w/scripts/ml4w-autostart b/dotfiles/.config/ml4w/scripts/ml4w-autostart index 96c18dba3..9c3680c0d 100755 --- a/dotfiles/.config/ml4w/scripts/ml4w-autostart +++ b/dotfiles/.config/ml4w/scripts/ml4w-autostart @@ -97,6 +97,12 @@ info "Starting ML4W Power Menu" ml4w-powermenu start & info "ML4W Power Menu started" +# Start ML4W Walker (starts elephant first, then walker -- see +# ml4w-walker's own start command) +info "Starting ML4W Walker" +ml4w-walker start & +info "ML4W Walker started" + # Start ML4W Welcome App info "Starting ML4W Welcome App" if [ ! -f $HOME/.cache/ml4w-welcome-autostart ]; then diff --git a/dotfiles/.config/walker/themes/ml4w/style.css b/dotfiles/.config/walker/themes/ml4w/style.css new file mode 100644 index 000000000..070a16d0e --- /dev/null +++ b/dotfiles/.config/walker/themes/ml4w/style.css @@ -0,0 +1,182 @@ +@define-color window_bg_color #1f1f28; +@define-color accent_bg_color #54546d; +@define-color theme_fg_color #f2ecbc; +@define-color error_bg_color #C34043; +@define-color error_fg_color #DCD7BA; + +@import "../../colors.css"; + +* { + all: unset; +} + +.normal-icons { + -gtk-icon-size: 16px; +} + +.large-icons { + -gtk-icon-size: 32px; +} + +scrollbar { + opacity: 0; +} + +.box-wrapper { + box-shadow: + 0 19px 38px rgba(0, 0, 0, 0.3), + 0 15px 12px rgba(0, 0, 0, 0.22); + background: @surface; + padding: 20px; + border-radius: 20px; + border: 2px solid @primary; +} + +.preview-box, +.elephant-hint, +.placeholder { + color: @theme_fg_color; +} + +.box { +} + +.search-container { + border-radius: 10px; + border: 2px solid @primary; +} + +.input placeholder { + opacity: 0.5; +} + +.input { + background: transparent; + padding: 10px; + color: @on_surface; +} + +.input:focus, +.input:active { +} + +.content-container { +} + +.placeholder { +} + +.scroll { +} + +.list { + color: @theme_fg_color; +} + +child { +} + +.item-box { + border-radius: 10px; + padding: 10px; + color:@on_surface; +} + +.item-quick-activation { + margin-left: 10px; + background: alpha(@accent_bg_color, 0.25); + border-radius: 5px; + padding: 10px; +} + +child:hover .item-box, +child:selected .item-box { + background: @primary; + color:@on_primary; +} + +.item-text-box { +} + +.item-text { +} + +.item-subtext { + font-size: 12px; + opacity: 0.5; +} + +.item-image, +.item-image-text { + margin-right: 10px; +} + +.item-image-text { + font-size: 28px; +} + +.preview { + border: 1px solid alpha(@accent_bg_color, 0.25); + padding: 10px; + border-radius: 10px; + color: @theme_fg_color; +} + +.calc .item-text { + font-size: 24px; +} + +.calc .item-subtext { +} + +.symbols .item-image { + font-size: 24px; +} + +.todo.done .item-text-box { + opacity: 0.25; +} + +.todo.urgent { + font-size: 24px; +} + +.todo.active { + font-weight: bold; +} + +.bluetooth.disconnected { + opacity: 0.5; +} + +.preview .large-icons { + -gtk-icon-size: 64px; +} + +.keybinds-wrapper { + border-top: 0px solid lighter(@primary); + font-size: 12px; + opacity: 0.5; + color: @on_surface; +} + +.keybinds { +} + +.keybind { +} + +.keybind-bind { + color: @on_surface; + font-weight: bold; +} + +.keybind-label { + color: @on_surface; +} + +.error { + padding: 10px; + background: @error_bg_color; + color: @error_fg_color; +} \ No newline at end of file diff --git a/setup/dependencies/packages-ubuntu b/setup/dependencies/packages-ubuntu new file mode 100644 index 000000000..d07f04253 --- /dev/null +++ b/setup/dependencies/packages-ubuntu @@ -0,0 +1,28 @@ +hyprland +hyprland-guiutils +hyprpolkitagent +hyprsunset +sway-notification-center +fonts-font-awesome +tesseract-ocr +tesseract-ocr-eng +libsecret-1-0 +libnotify-bin +network-manager-gnome +nm-connection-editor +power-profiles-daemon +gnome-themes-extra +gnome-themes-extra-data +gnome-themes-ubuntu +gvfs-backends +qml6-module-qt5compat-graphicaleffects +qml6-module-qt-labs-folderlistmodel +qml6-module-qtquick-effects +qml6-module-qtquick-shapes +qml6-module-qtquick-controls +qml6-module-qtquick-layouts +libgirepository-2.0-dev +libcairo2-dev +lua5.4 +imagemagick +pipx \ No newline at end of file diff --git a/setup/post-ubuntu.sh b/setup/post-ubuntu.sh new file mode 100755 index 000000000..e16e3671d --- /dev/null +++ b/setup/post-ubuntu.sh @@ -0,0 +1,311 @@ +#!/usr/bin/env bash + +# -------------------------------------------------------------- +# Mask systemd --user units that duplicate autostart.lua's exec-once +# daemons. hyprpolkitagent.service and swaync.service stay unmasked -- +# hyprpolkitagent is started explicitly below, swaync needs D-Bus +# activation to restart itself if it dies. +# -------------------------------------------------------------- + +for _svc in waybar.service hypridle.service hyprsunset.service; do + if systemctl --user list-unit-files "$_svc" &>/dev/null; then + systemctl --user mask "$_svc" 2>/dev/null || true + fi +done + +systemctl --user unmask swaync.service 2>/dev/null || true +# Marker for autostart.lua: skip the direct swaync launch there and +# rely on D-Bus activation instead (avoids a race between the two). +mkdir -p "$HOME/.config/ml4w" +touch "$HOME/.config/ml4w/.swaync-dbus-activated" + +# hyprpolkitagent.service is WantedBy=graphical-session.target, which a +# real GNOME session also activates -- it then collides with GNOME's +# own polkit agent and crashes. Gate it to Hyprland via +# ConditionEnvironment instead of masking, so the explicit start below +# still works. +mkdir -p "$HOME/.config/systemd/user/hyprpolkitagent.service.d" +cat > "$HOME/.config/systemd/user/hyprpolkitagent.service.d/hyprland-only.conf" <<-EOF +[Unit] +ConditionEnvironment=XDG_CURRENT_DESKTOP=Hyprland +EOF +systemctl --user daemon-reload 2>/dev/null || true + +# -------------------------------------------------------------- +# snapd-desktop-integration: fails under every non-GNOME session on +# GDM installs, spamming Failed Units. Gate via ConditionEnvironment +# rather than masking, so it still runs under real GNOME sessions. +# -------------------------------------------------------------- + +if command -v snap &> /dev/null && snap list snapd-desktop-integration &> /dev/null; then + sudo snap refresh snapd-desktop-integration --channel=candidate >> "$LOG_FILE" 2>&1 || true + + _snap_svc="snap.snapd-desktop-integration.snapd-desktop-integration.service" + mkdir -p "$HOME/.config/systemd/user/${_snap_svc}.d" + cat > "$HOME/.config/systemd/user/${_snap_svc}.d/gnome-only.conf" <<-EOF +[Unit] +ConditionEnvironment=XDG_CURRENT_DESKTOP=ubuntu:GNOME +EOF + + systemctl --user daemon-reload 2>/dev/null || true +fi + +# -------------------------------------------------------------- +# mate-polkit fights hyprpolkitagent for the polkit-agent race. Not a +# systemd unit, so hide it via the standard XDG autostart override. +# -------------------------------------------------------------- + +if [ -f /etc/xdg/autostart/polkit-mate-authentication-agent-1.desktop ]; then + mkdir -p "$HOME/.config/autostart" + cat > "$HOME/.config/autostart/polkit-mate-authentication-agent-1.desktop" <<-'EOF' + [Desktop Entry] + Hidden=true + EOF +fi + +# -------------------------------------------------------------- +# Cargo -- matugen +# -------------------------------------------------------------- + +TARGET_VERSION="4.0.0" + +force_install_matugen() { + run_quiet "Installing matugen" cargo install matugen --force + info "matugen installed." +} + +if ! command -v matugen &> /dev/null; then + info "'matugen' is not currently installed." + force_install_matugen +else + CURRENT_VERSION=$(matugen --version | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1) + LOWEST_VERSION=$(printf "%s\n%s" "$TARGET_VERSION" "$CURRENT_VERSION" | sort -V | head -n1) + if [ "$LOWEST_VERSION" = "$CURRENT_VERSION" ] && [ "$CURRENT_VERSION" != "$TARGET_VERSION" ]; then + info "Current version ($CURRENT_VERSION) is lower than $TARGET_VERSION. Updating..." + force_install_matugen + else + info "matugen is already up to date! (Current version: $CURRENT_VERSION)" + fi +fi + +# -------------------------------------------------------------- +# awww (Wayland wallpaper daemon -- replaces swww; no apt/PPA source) +# -------------------------------------------------------------- + +if [ ! -x /usr/local/bin/awww ] || [ ! -x /usr/local/bin/awww-daemon ]; then + # Check the install target, not `command -v awww` -- a prior run + # where only awww-daemon failed to build would otherwise skip this + # block forever. + run_quiet "Building awww from source" bash -c ' + set -e + sudo apt-get install -y liblz4-dev pkg-config libwayland-dev + cargo install --git https://codeberg.org/LGFae/awww --tag v0.12.1 awww awww-daemon --locked + sudo cp "$HOME/.cargo/bin/awww" /usr/local/bin/awww + sudo cp "$HOME/.cargo/bin/awww-daemon" /usr/local/bin/awww-daemon + ' + info "awww installed to /usr/local/bin" +fi + +if dpkg -l 2>/dev/null | grep -q "^ii hyprpaper "; then + sudo apt-get remove -y hyprpaper >> "$LOG_FILE" 2>&1 +fi + +# -------------------------------------------------------------- +# Shared scaffold for the from-source builds below. +# -------------------------------------------------------------- + +build_from_source() { + local label=$1 tmp_prefix=$2 script=$3 + local src_dir status + src_dir=$(mktemp -d -t "${tmp_prefix}-XXXXXX") + if run_quiet "Building $label from source" bash -c "$script" _ "$src_dir"; then + status=0 + else + status=$? + fi + rm -rf "$src_dir" + return $status +} + +# -------------------------------------------------------------- +# Quickshell -- built from source, pinned to a commit already +# validated against this repo's QML config. +# -------------------------------------------------------------- + +if ! command -v qs &> /dev/null; then + build_from_source "quickshell" quickshell-src ' + set -e + sudo apt-get install -y \ + cmake ninja-build pkg-config \ + qt6-base-dev qt6-base-private-dev \ + qt6-declarative-dev qt6-declarative-private-dev \ + qt6-svg-dev qt6-shadertools-dev \ + libcli11-dev \ + libxcb1-dev \ + libdrm-dev libgbm-dev libegl1-mesa-dev \ + libcpptrace-dev libunwind-dev libzstd-dev \ + libwayland-bin libwayland-dev wayland-protocols \ + libglib2.0-dev \ + libpipewire-0.3-dev \ + libjemalloc-dev \ + libvulkan-dev \ + libpolkit-agent-1-dev libpolkit-gobject-1-dev \ + libpam0g-dev \ + spirv-tools + git clone https://github.com/quickshell-mirror/quickshell "$1" + (cd "$1" && git checkout -q 4df562dfb2475a9057f0f33a8db75808efad8670) + cmake -S "$1" -B "$1/build" -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DDISTRIBUTOR="ML4W Ubuntu Support (source build)" + cmake --build "$1/build" + sudo cmake --install "$1/build" + ' + info "quickshell installed." +fi + +# -------------------------------------------------------------- +# Quickshell Overview + ML4W Dock (placed after quickshell since +# ml4w-dock wants qs on PATH). +# -------------------------------------------------------------- + +# matugen's [templates.quickshell_overview] writes into this same +# path; clear it only when its output file is present and there's no +# .git, so unrelated content is never touched. +QSO_DIR="$HOME/.local/share/quickshell-overview" +if [ -f "$QSO_DIR/common/Appearance.colors.qml" ] && [ ! -d "$QSO_DIR/.git" ]; then + rm -rf "$QSO_DIR" +fi +run_quiet "Installing Quickshell Overview" bash -c ' + set -euo pipefail + curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors https://raw.githubusercontent.com/mylinuxforwork/ml4w-quickshell-overview/main/install.sh | bash +' + +run_quiet "Installing ML4W Dock" bash -c ' + set -euo pipefail + curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors https://raw.githubusercontent.com/mylinuxforwork/ml4w-dock/main/install.sh | bash +' + +# -------------------------------------------------------------- +# ML4W Dotfiles Settings App -- its setup.sh only detects pacman/dnf/ +# zypper and exits 1 on Ubuntu; post.sh runs it later and tolerates +# that failure, which otherwise leaves ml4w-autostart's +# ~/.local/share/ml4w-dotfiles-settings/quickshell unwritten and the +# `ml4w-settings` alias permanently reporting no running instance. +# Install it ourselves the same way setup.sh does: clone + make install. +# -------------------------------------------------------------- + +build_from_source "ML4W Dotfiles Settings" ml4w-dotfiles-settings ' + set -e + git clone --depth=1 https://github.com/mylinuxforwork/ml4w-dotfiles-settings.git "$1" + make -C "$1" install +' +info "ML4W Dotfiles Settings installed to ~/.local/bin/" + +# -------------------------------------------------------------- +# nwg-displays -- built from source, not the apt package, for Wayland +# compatibility (matches Fedora/openSUSE). +# -------------------------------------------------------------- + +if dpkg -l 2>/dev/null | grep -q "^ii nwg-displays "; then + sudo apt-get remove -y nwg-displays >> "$LOG_FILE" 2>&1 +fi +# gir1.2-gtklayershell-0.1 is required for nwg-displays to run as an +# overlay via GtkLayerShell; without it, it falls back to a plain +# floating window that Hyprland doesn't position as an overlay. +build_from_source "nwg-displays" nwg-displays ' + set -e + sudo apt-get install -y python3-pip gir1.2-gtklayershell-0.1 + git clone https://github.com/nwg-piotr/nwg-displays.git "$1" + python3 -m pip install --user --break-system-packages "$1" +' +info "nwg-displays installed to ~/.local/bin/" + +# -------------------------------------------------------------- +# Grimblast +# -------------------------------------------------------------- + +run_quiet "Installing grimblast" bash -c ' + set -e + sudo apt-get install -y scdoc + bash "$1" +' _ "$repo_path/setup/clean-install-grimblast.sh" + +# -------------------------------------------------------------- +# grim -- built from source because Ubuntu's package is compiled +# without JPEG support, which breaks the default .jpg screenshot +# filename. Installs to /usr/local/bin, ahead of the apt grim on PATH. +# -------------------------------------------------------------- + +if ! ldd /usr/local/bin/grim 2>/dev/null | grep -q libjpeg; then + build_from_source "grim" grim-src ' + set -e + sudo apt-get install -y \ + meson ninja-build pkg-config scdoc \ + libpng-dev libjpeg-dev libpixman-1-dev \ + libwayland-bin libwayland-dev wayland-protocols + git clone --depth=1 --branch v1.5.0 https://gitlab.freedesktop.org/emersion/grim.git "$1" + meson setup "$1/build" "$1" --buildtype=release -Djpeg=enabled + ninja -C "$1/build" + sudo ninja -C "$1/build" install + ' + info "grim installed to /usr/local/bin" +fi + +# -------------------------------------------------------------- +# Pip +# -------------------------------------------------------------- + +run_quiet "Installing pywalfox" bash -c ' + set -e + sudo apt-get install -y python3-pip pipx + pipx install pywalfox || pipx upgrade pywalfox + pipx ensurepath +' + +# -------------------------------------------------------------- +# Fonts +# -------------------------------------------------------------- + +# Only creates $dest once files are confirmed extracted, so a failed +# download can't permanently block retry. +install_font_zip() { + local label=$1 url=$2 glob=$3 dest=$4 + local tmp + tmp=$(mktemp -d) + if run_quiet "Installing $label" bash -c ' + set -e + curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors -o "$1/font.zip" "$2" + (cd "$1" && unzip -q font.zip -d extracted) + shopt -s nullglob + files=("$1"/extracted/$4) + [ ${#files[@]} -gt 0 ] + sudo mkdir -p "$3" + sudo cp "${files[@]}" "$3/" + ' _ "$tmp" "$url" "$dest" "$glob"; then + rm -rf "$tmp" + return 0 + fi + rm -rf "$tmp" + return 1 +} + +# JetBrains Mono Nerd Font -- no Ubuntu package. +JBM_DEST="/usr/share/fonts/JetBrainsMonoNerd" +if [ ! -d "$JBM_DEST" ]; then + install_font_zip "JetBrains Mono Nerd Font" \ + "https://github.com/ryanoasis/nerd-fonts/releases/latest/download/JetBrainsMono.zip" \ + "*.ttf" "$JBM_DEST" || + warn "Failed to download JetBrains Mono Nerd Font; kitty font_family will fall back." +fi + +# Font Awesome 7 -- apt's fonts-font-awesome is 4.7 rebadged and +# doesn't register the "Font Awesome 7" family waybar's CSS wants. +FA_DEST="/usr/share/fonts/font-awesome-7" +if [ ! -d "$FA_DEST" ]; then + install_font_zip "Font Awesome 7" \ + "https://github.com/FortAwesome/Font-Awesome/releases/download/7.3.0/fontawesome-free-7.3.0-desktop.zip" \ + "*/otfs/*.otf" "$FA_DEST" || + warn "Failed to install Font Awesome 7; waybar icons may not render." +fi + +sudo fc-cache -f >> "$LOG_FILE" 2>&1 diff --git a/setup/post.sh b/setup/post.sh index c61a39d69..13a67f2ea 100644 --- a/setup/post.sh +++ b/setup/post.sh @@ -30,6 +30,12 @@ bash <(curl -s https://raw.githubusercontent.com/mylinuxforwork/ml4w-dock/main/i bash <(curl -s https://raw.githubusercontent.com/mylinuxforwork/ml4w-powermenu/main/install.sh) +# -------------------------------------------------------------- +# ML4W Walker (app launcher + its provider daemon, elephant) +# -------------------------------------------------------------- + +bash <(curl -s https://raw.githubusercontent.com/mylinuxforwork/ml4w-walker/main/install.sh) + # -------------------------------------------------------------- # Cursors # -------------------------------------------------------------- diff --git a/setup/preflight-ubuntu.sh b/setup/preflight-ubuntu.sh new file mode 100755 index 000000000..fd2dc259a --- /dev/null +++ b/setup/preflight-ubuntu.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +mkdir -p "$HOME/.local/bin" + +# -------------------------------------------------------------- +# Repositories +# -------------------------------------------------------------- + +sudo apt-get install -y software-properties-common >> "$LOG_FILE" 2>&1 +sudo add-apt-repository -y universe >> "$LOG_FILE" 2>&1 +sudo add-apt-repository -y restricted >> "$LOG_FILE" 2>&1 + +# Hyprland core +if ! grep -Rq "cppiber.*hyprland" /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null; then + info "Adding PPA: ppa:cppiber/hyprland" + sudo add-apt-repository -y ppa:cppiber/hyprland >> "$LOG_FILE" 2>&1 +else + info "Hyprland PPA already present" +fi + +# cliphist (quickshell itself is built from source in post-ubuntu.sh) +if ! grep -Rq "avengemedia.*danklinux" /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null; then + info "Adding PPA: ppa:avengemedia/danklinux" + sudo add-apt-repository -y ppa:avengemedia/danklinux >> "$LOG_FILE" 2>&1 +else + info "danklinux PPA already present" +fi + +# gum (not in Ubuntu main/universe). -s, not -f: a failed curl leaves a +# 0-byte keyring that -f would treat as present. +if [ ! -s /etc/apt/keyrings/charm.gpg ]; then + info "Adding Charm apt repo for gum" + sudo mkdir -p /etc/apt/keyrings + curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg + echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list > /dev/null +else + info "Charm apt repo already present" +fi + +# Firefox: apt-get install firefox on 22.04+ installs a snap wrapper, +# not a .deb. Pin the Mozilla Team PPA so packages' `firefox` resolves +# to a real .deb. +if ! grep -Rq "mozillateam.*ppa" /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null; then + info "Adding PPA: ppa:mozillateam/ppa (native Firefox .deb, not the snap)" + sudo add-apt-repository -y ppa:mozillateam/ppa >> "$LOG_FILE" 2>&1 +fi +sudo tee /etc/apt/preferences.d/mozilla-firefox > /dev/null <<-'EOF' + Package: * + Pin: release o=LP-PPA-mozillateam + Pin-Priority: 1001 + EOF +sudo tee /etc/apt/apt.conf.d/51unattended-upgrades-firefox > /dev/null <<-'EOF' + Unattended-Upgrade::Allowed-Origins:: "LP-PPA-mozillateam:${distro_codename}"; + EOF + +sudo apt-get update >> "$LOG_FILE" 2>&1 + +if ! command -v gum &> /dev/null; then + sudo apt-get install -y gum >> "$LOG_FILE" 2>&1 +fi + +# -------------------------------------------------------------- +# Uninstall swww if exists. To be replaced with awww in the next steps +# -------------------------------------------------------------- + +if dpkg -l 2>/dev/null | grep -q "^ii swww "; then + sudo apt-get remove -y swww >> "$LOG_FILE" 2>&1 +fi