582 lines
20 KiB
Bash
Executable File
582 lines
20 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
################################################################################
|
|
#
|
|
# opensuse-personalizer.sh
|
|
# Interactive post-install setup script for OpenSUSE installations
|
|
#
|
|
################################################################################
|
|
|
|
################################################################################
|
|
#
|
|
# Constants
|
|
#
|
|
################################################################################
|
|
|
|
########################################
|
|
# OpenSUSE patterns
|
|
|
|
PATTERNS=(
|
|
# (Base system)
|
|
patterns-base-apparmor
|
|
patterns-base-base
|
|
patterns-base-enhanced_base
|
|
|
|
# (Desktop environment)
|
|
patterns-gnome-gnome_basic
|
|
)
|
|
|
|
########################################
|
|
# Zypper packages
|
|
|
|
# To remove
|
|
RM=(
|
|
libreoffice gedit
|
|
)
|
|
|
|
# To remove (and prevent reinstallation of)
|
|
AL=(
|
|
gnome-clocks gnome-packagekit gnome-software tigervnc vlc-noX xterm yast2
|
|
)
|
|
|
|
# To install
|
|
IN=(
|
|
# (Necessary packages)
|
|
git-core flatpak opi
|
|
|
|
# (Theming)
|
|
papirus-icon-theme fira-code-fonts gdouros-symbola-fonts
|
|
|
|
# (Shell utilities)
|
|
fish fzf nano zenity fortune toilet cowsay wmctrl libnotify-tools
|
|
|
|
# (Programs)
|
|
emacs inkscape gimp shotcut audacity geary nextcloud-desktop steam blender
|
|
|
|
# (GNOME utilities)
|
|
gnome-session-wayland gnome-characters gnome-disk-utility gnome-font-viewer gnome-dictionary gnome-logs gnome-screenshot gnome-text-editor gnome-weather gnome-tweaks eog dconf-editor baobab totem menulibre Fragments
|
|
|
|
# (Misc.)
|
|
distribution-logos-openSUSE distribution-logos-openSUSE-icons distribution-logos-openSUSE-Tumbleweed
|
|
)
|
|
|
|
########################################
|
|
# Flatpak packages
|
|
|
|
FLATPAK_PACKAGES=(
|
|
com.discordapp.Discord
|
|
com.spotify.Client
|
|
com.github.tchx84.Flatseal
|
|
org.nickvision.tagger
|
|
)
|
|
|
|
########################################
|
|
# GNOME extensions
|
|
|
|
GNOME_EXTENSIONS=(
|
|
AlphabeticalAppGrid@stuarthayhurst
|
|
color-picker@tuberry
|
|
places-menu@gnome-shell-extensions.gcampax.github.com
|
|
)
|
|
|
|
########################################
|
|
# URLs
|
|
|
|
FLATHUB_REMOTE_URL="https://flathub.org/repo/flathub.flatpakrepo"
|
|
|
|
PERSONALIZER_REPO_URL="https://gitlab.com/jessieh/opensuse-personalizer.git"
|
|
|
|
########################################
|
|
# Directories and files
|
|
|
|
PERSONALIZER_REPO_DIR=/tmp/opensuse-personalizer
|
|
|
|
################################################################################
|
|
#
|
|
# Pre-setup prompts
|
|
#
|
|
################################################################################
|
|
|
|
########################################
|
|
# Pre-setup
|
|
|
|
# Ensure we're not running as root
|
|
if [ "${EUID}" == 0 ]; then
|
|
echo "DO NOT RUN THIS SCRIPT AS ROOT!"
|
|
echo "Please run this script as a regular user."
|
|
exit 1
|
|
fi
|
|
|
|
# Ensure "dialog" is installed
|
|
echo "Installing dialog utility..."
|
|
sudo zypper --non-interactive in dialog
|
|
|
|
########################################
|
|
# Prompt for system chassis
|
|
|
|
system_chassis=$(hostnamectl chassis)
|
|
|
|
function string_eq ()
|
|
{
|
|
[[ "${1}" == "${2}" ]] && echo ON || echo OFF
|
|
}
|
|
|
|
function prompt_chassis_type ()
|
|
{
|
|
|
|
|
|
entry=$(dialog --title "Chassis Type" --stdout --no-cancel --erase-on-exit \
|
|
--radiolist "Confirm the chassis type for this system:" 0 0 0 \
|
|
"Desktop" "Stationary form factor" $(string_eq "${system_chassis}" "desktop") \
|
|
"Laptop" "Clamshell form factor" $(string_eq "${system_chassis}" "laptop") \
|
|
"Tablet" "Touchscreen form factor" $(string_eq "${system_chassis}" "tablet") \
|
|
"Convertible" "Hybrid form factor" $(string_eq "${system_chassis}" "convertible"))
|
|
|
|
# Ensure entry is lowercase
|
|
entry=${entry,,}
|
|
|
|
|
|
case "${entry}" in
|
|
"desktop"|"laptop"|"convertible"|"tablet")
|
|
if
|
|
dialog --title "Chassis Type" --defaultno --yesno "Use ${entry} as chassis type?" 0 0
|
|
then
|
|
system_chassis="${entry}"
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
;;
|
|
*)
|
|
dialog --title "Chassis Type" --msgbox "Please choose a chassis type for this system." 0 0
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
}
|
|
|
|
# Repeatedly show the prompt until we receive valid input
|
|
until prompt_chassis_type; do : ; done
|
|
|
|
# Set chassis type
|
|
echo "Setting chassis type to ${system_chassis}"
|
|
sudo hostnamectl chassis "${system_chassis}"
|
|
|
|
# Add "mobile" package pattern for mobile chassis types
|
|
case "${system_chassis}" in
|
|
"latop"|"convertible"|"tablet")
|
|
PATTERNS+=('patterns-desktop-mobile')
|
|
;;
|
|
esac
|
|
|
|
########################################
|
|
# Prompt for system name
|
|
|
|
system_name=$(hostnamectl hostname)
|
|
|
|
function prompt_system_name ()
|
|
{
|
|
|
|
entry=$(dialog --title "System Name" --stdout --no-cancel --erase-on-exit \
|
|
--inputbox "All lowercase letters, no spaces or symbols:" 0 0 \
|
|
"${system_name}")
|
|
|
|
# Filter all non-letter characters out of the user's entry
|
|
entry=${entry//[^[:alpha:]]/}
|
|
|
|
# Ensure entry is lowercase
|
|
entry=${entry,,}
|
|
|
|
case "${entry}" in
|
|
"")
|
|
dialog --title "Chassis Type" --msgbox "Please enter a name for this system." 0 0
|
|
return 1
|
|
;;
|
|
*)
|
|
if
|
|
dialog --title "Chassis Type" --defaultno --yesno "Use ${entry} as system name?" 0 0
|
|
then
|
|
system_name="${entry}"
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
}
|
|
|
|
# Repeatedly show the prompt until we receive valid input
|
|
until prompt_system_name; do : ; done
|
|
|
|
# Set hostname and pretty hostname
|
|
echo "Setting hostname to ${system_name}..."
|
|
sudo hostnamectl hostname "${system_name}"
|
|
echo "Setting pretty hostname to ${system_name^}"
|
|
sudo hostnamectl hostname --pretty "${system_name^}"
|
|
|
|
########################################
|
|
# Prompt for optional additions
|
|
|
|
optional_additions=""
|
|
|
|
function prompt_optional_additions ()
|
|
{
|
|
|
|
ENTRY=$(dialog --title "Optional Additions" --stdout --no-cancel --single-quoted --output-separator '|' \
|
|
--checklist "Select any additional configuration changes that you would like applied to the system:" 0 0 0 \
|
|
"Xournal++" "Install Xournal++ for taking handwritten notes" OFF \
|
|
"EasyEffects" "Install EasyEffects for applying effects (e.g. equalizers) to system audio devices" OFF \
|
|
"Media Control Key Shortcuts" "Set up media control keyboard shortcuts (for systems without dedicated media control keys)" OFF \
|
|
"Power Button Screen Lock Override" "Override the power button's default behavior with a screen lock shortcut (for tablets and some convertibles)" OFF )
|
|
|
|
case "${ENTRY}" in
|
|
"")
|
|
if
|
|
dialog --keep-window --erase-on-exit --title "Chassis Type" --defaultno --yesno "Apply only baseline system configuration?" 0 0
|
|
then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
;;
|
|
*)
|
|
if
|
|
ADDITIONS_LIST=$(echo "${ENTRY}" | sed "s/|/\\\\n * /g" | sed "s/'//g")
|
|
dialog --keep-window --erase-on-exit --title "Chassis Type" --defaultno --yesno "Confirm your selection of the following additions:\n${ADDITIONS_LIST}" 0 0
|
|
then
|
|
optional_additions="${ENTRY}"
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Repeatedly show the prompt until we receive valid input
|
|
until prompt_optional_additions; do : ; done
|
|
|
|
################################################################################
|
|
#
|
|
# Feature detection
|
|
#
|
|
################################################################################
|
|
|
|
detected_features=()
|
|
|
|
# Touchpad detection
|
|
if
|
|
cat /proc/bus/input/devices | grep -i Touchpad
|
|
then
|
|
detected_features+=('Touchpad')
|
|
fi
|
|
|
|
# Windows multi-boot detection
|
|
if
|
|
sudo grep menuentry /boot/grub2/grub.cfg | grep -Po ".*Windows.*"
|
|
then
|
|
detected_features+=('Windows')
|
|
fi
|
|
|
|
################################################################################
|
|
#
|
|
# Package setup
|
|
#
|
|
################################################################################
|
|
|
|
########################################
|
|
# Package operations
|
|
|
|
echo "Setting up packages..."
|
|
sudo zypper --non-interactive in ${PATTERNS[@]}
|
|
sudo zypper --non-interactive rm ${RM[@]} ${AL[@]}
|
|
sudo zypper --non-interactive al ${AL[@]}
|
|
sudo zypper --non-interactive in ${IN[@]}
|
|
|
|
########################################
|
|
# Flatpak operations
|
|
|
|
echo "Setting up Flatpak remotes..."
|
|
|
|
sudo flatpak remote-add --if-not-exists flathub "${FLATHUB_REMOTE}"
|
|
|
|
echo "Setting up Flatpak packages..."
|
|
sudo flatpak install --noninteractive ${FLATPAK_PACKAGES[@]}
|
|
|
|
########################################
|
|
# Codec installation
|
|
|
|
echo "Setting up codecs..."
|
|
opi codecs
|
|
|
|
########################################
|
|
# (OPTIONAL) Extra packages
|
|
|
|
if [[ "${optional_additions}" == *"Xournal++"* ]]; then
|
|
echo "Installing Xournal++..."
|
|
sudo zypper al texlive
|
|
sudo zypper in xournalpp
|
|
fi
|
|
|
|
if [[ "${optional_additions}" == *"EasyEffects"* ]]; then
|
|
echo "Installing EasyEffects..."
|
|
sudo zypper in easyeffects
|
|
fi
|
|
|
|
################################################################################
|
|
#
|
|
# System configuration
|
|
#
|
|
################################################################################
|
|
|
|
########################################
|
|
# GRUB configuration
|
|
|
|
# Silence GRUB
|
|
echo "Configuring GRUB..."
|
|
echo "# Automatically added by personal-opensuse-setup.sh
|
|
GRUB_TIMEOUT=0
|
|
GRUB_HIDDEN_TIMEOUT=0
|
|
GRUB_QUIET=true
|
|
GRUB_HIDDEN_TIMEOUT_QUIET=true" | sudo tee --append /etc/default/grub
|
|
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
|
|
|
|
########################################
|
|
# PolicyKit configuration
|
|
|
|
# Create a local policy that unlocks basic networking settings for users
|
|
echo "Configuring PolicyKit..."
|
|
sudo mkdir -p /etc/polkit/localauthority/50-local.d/
|
|
echo "[Allow users to modify system network settings]
|
|
Identity=unix-group:users
|
|
Action=org.freedesktop.NetworkManager.settings.modify.system
|
|
ResultAny=auth_admin_keep
|
|
ResultInactive=auth_admin_keep
|
|
ResultActive=yes" | sudo tee /etc/polkit/localauthority/50-local.d/10-NetworkManager.pkla
|
|
|
|
################################################################################
|
|
#
|
|
# GNOME keyboard shortcuts
|
|
#
|
|
################################################################################
|
|
|
|
echo "Configuring GNOME keyboard shortcuts..."
|
|
|
|
########################################
|
|
# Navigation
|
|
|
|
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left "['<Primary><Super>Left']"
|
|
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left "['<Primary><Super>Right']"
|
|
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-left "['<Primary><Shift><Super>Left']"
|
|
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-left "['<Primary><Shift><Super>Right']"
|
|
|
|
# Swap "switch applications" (grouped alt+tab) for "switch windows" (non-grouped alt+tab) shortcuts
|
|
gsettings set org.gnome.shell.window-switcher current-workspace-only false
|
|
gsettings set org.gnome.desktop.wm.keybindings switch-windows $(gsettings get org.gnome.desktop.wm.keybindings switch-applications)
|
|
gsettings set org.gnome.desktop.wm.keybindings switch-windows-backward $(gsettings get org.gnome.desktop.wm.keybindings switch-applications-backward)
|
|
gsettings set org.gnome.desktop.wm.keybindings switch-applications []
|
|
gsettings set org.gnome.desktop.wm.keybindings switch-applications-backward []
|
|
|
|
########################################
|
|
# (OPTIONAL) Media
|
|
|
|
if [[ "${optional_additions}" == *"Media Control Key Shortcuts"* ]]; then
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys mic-mute "['<Super>Home']"
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys next "['<Control><Super>Page_Down']"
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys previous "['<Control><Super>Page_Up']"
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys volume-down "['<Super>Page_Down']"
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys volume-mute "['<Super>End']"
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys volume-up "['<Super>Page_Up']"
|
|
fi
|
|
|
|
########################################
|
|
# Windows
|
|
|
|
gsettings set org.gnome.desktop.wm.keybindings close "['<Super>w']"
|
|
gsettings set org.gnome.desktop.wm.keybindings toggle-fullscreen "['<Super>f']"
|
|
|
|
########################################
|
|
# Custom shortcuts
|
|
|
|
# Helper function (because gsettings doesn't make this simple)
|
|
function add_custom_gnome_keybinding ()
|
|
{
|
|
EXISTING_KEYBINDINGS=$(gsettings get org.gnome.settings-daemon.plugins.media-keys custom-keybindings)
|
|
KEYBINDING_INDEX=$(expr $(echo $EXISTING_KEYBINDINGS | grep -oE '[0-9]+' | sort -n | tail -n 1) + 1)
|
|
KEYBINDING_PATH=/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom${KEYBINDING_INDEX}/
|
|
if [[ "$EXISTING_KEYBINDINGS" == "@as []" ]]; then
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings "['${KEYBINDING_PATH}']"
|
|
else
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings "$(echo ${EXISTING_KEYBINDINGS} | sed s/.$//), '${KEYBINDING_PATH}']"
|
|
fi
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:${KEYBINDING_PATH} name "${1}"
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:${KEYBINDING_PATH} command "${2}"
|
|
gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:${KEYBINDING_PATH} binding "${3}"
|
|
}
|
|
|
|
# Add custom shortcuts
|
|
add_custom_gnome_keybinding "Launch Terminal" "gnome-terminal" "<Super>Return"
|
|
add_custom_gnome_keybinding "Toggle Night Light" "gnome-toggle-night-light" "<Alt><Super>n"
|
|
|
|
# (OPTIONAL) Add custom shortcuts
|
|
if [[ "${detected_features[@]}" == *"Touchpad"* ]]; then
|
|
add_custom_gnome_keybinding "Toggle Touchpad Lock" "gnome-toggle-touchpad-lock" "<Alt><Super>t"
|
|
fi
|
|
if [[ "${optional_additions}" == *"Power Button Screen Lock Override"* ]]; then
|
|
add_custom_gnome_keybinding "Lock Screen" "gdm-lock-screen" "PowerOff"
|
|
fi
|
|
|
|
################################################################################
|
|
#
|
|
# GNOME appearance configuration
|
|
#
|
|
################################################################################
|
|
|
|
echo "Configuring GNOME appearance settings..."
|
|
|
|
gsettings set org.gnome.desktop.interface icon-theme "Papirus"
|
|
|
|
gsettings set org.gnome.desktop.interface clock-format '24h'
|
|
gsettings set org.gnome.desktop.interface clock-show-date true
|
|
gsettings set org.gnome.desktop.interface clock-show-weekday true
|
|
|
|
gsettings set org.gnome.desktop.interface font-antialiasing "rgba"
|
|
gsettings set org.gnome.desktop.interface font-name "Cantarell 10"
|
|
gsettings set org.gnome.desktop.interface document-font-name "Cantarell 10"
|
|
gsettings set org.gnome.desktop.interface monospace-font-name "Fira Code 10"
|
|
|
|
gsettings set org.gnome.settings-daemon.plugins.color night-light-enabled true
|
|
gsettings set org.gnome.settings-daemon.plugins.color night-light-temperature 3700
|
|
gsettings set org.gnome.settings-daemon.plugins.color night-light-schedule-automatic false
|
|
gsettings set org.gnome.settings-daemon.plugins.color night-light-schedule-from 22
|
|
gsettings set org.gnome.settings-daemon.plugins.color night-light-schedule-to 6
|
|
|
|
################################################################################
|
|
#
|
|
# GNOME app folder configuration
|
|
#
|
|
################################################################################
|
|
|
|
echo "Configuring GNOME app folders..."
|
|
|
|
########################################
|
|
# Favorites
|
|
|
|
gsettings set org.gnome.shell.favorite-apps "['org.gnome.Terminal.desktop', 'firefox.desktop', 'emacsclient.desktop', 'org.gnome.Geary.desktop', 'org.gnome.Nautilus.desktop']"
|
|
|
|
########################################
|
|
# Utilities folder
|
|
|
|
UTILITIES_FOLDER_PATH=/org/gnome/desktop/app-folders/folders/Utilities/
|
|
gsettings set org.gnome.desktop.app-folders folder-children "['Utilities']"
|
|
gsettings set org.gnome.desktop.app-folders.folder:${UTILITIES_FOLDER_PATH} name "X-GNOME-Utilities.directory"
|
|
gsettings set org.gnome.desktop.app-folders.folder:${UTILITIES_FOLDER_PATH} translate true
|
|
gsettings set org.gnome.desktop.app-folders.folder:${UTILITIES_FOLDER_PATH} categories "[]"
|
|
gsettings set org.gnome.desktop.app-folders.folder:${UTILITIES_FOLDER_PATH} apps "['org.gnome.FileRoller.desktop', 'org.gnome.Characters.desktop', 'ca.desrt.dconf-editor.desktop', 'org.gnome.Dictionary.desktop', 'org.gnome.baobab.desktop', 'org.gnome.DiskUtility.desktop', 'org.gnome.Evince.desktop', 'com.github.wwmm.easyeffects.desktop', 'org.gnome.Extensions.desktop', 'com.github.tchx84.Flatseal.desktop', 'org.gnome.font-viewer.desktop', 'de.haeckerfelix.Fragments.desktop', 'org.gnome.eog.desktop', 'org.gnome.Logs.desktop', 'menulibre.desktop', 'org.gnome.Screenshot.desktop', 'gnome-system-monitor.desktop', 'org.nickvision.tagger.desktop', 'org.gnome.tweaks.desktop', 'uefi-firmware-settings.desktop', 'org.gnome.Totem.desktop']"
|
|
|
|
################################################################################
|
|
#
|
|
# GNOME extension setup
|
|
#
|
|
################################################################################
|
|
|
|
echo "Setting up GNOME extensions..."
|
|
|
|
for EXTENSION in "${GNOME_EXTENSIONS[@]}"; do
|
|
busctl --user call org.gnome.Shell.Extensions /org/gnome/Shell/Extensions org.gnome.Shell.Extensions InstallRemoteExtension s ${EXTENSION}
|
|
done
|
|
|
|
################################################################################
|
|
#
|
|
# Personal configuration files and scripts
|
|
#
|
|
################################################################################
|
|
|
|
########################################
|
|
# Emacs
|
|
|
|
echo "Setting up Emacs..."
|
|
|
|
# Remove any vendor-provided Emacs configuration files
|
|
rm ${HOME}/.emacs ${HOME}/.emacs.d/init.el
|
|
|
|
# Download Emacs configuration
|
|
EMACS_CONFIG_DIR=${HOME}/.config/emacs
|
|
mkdir -p ${EMACS_CONFIG_DIR}
|
|
wget https://jessieh.net/emacs -O ${EMACS_CONFIG_DIR}/init.el
|
|
|
|
# Enable and start Emacs daemon
|
|
systemctl --user enable emacs.service
|
|
systemctl --user start emacs.service
|
|
|
|
########################################
|
|
# Fish
|
|
|
|
echo "Setting up Fish..."
|
|
|
|
# Download Fish configuration
|
|
FISH_CONFIG_DIR=${HOME}/.config/fish
|
|
mkdir -p ${FISH_CONFIG_DIR}
|
|
wget https://jessieh.net/fish -O ${EMACS_CONFIG_DIR}/config.fish
|
|
|
|
# Set Fish as default shell
|
|
sudo chsh ${USER} -s $(which fish)
|
|
|
|
########################################
|
|
# Utility scripts
|
|
|
|
echo "Installing scripts..."
|
|
|
|
# Clone personalizer repo containing scripts, desktop entries, etc. to temporary folder
|
|
git clone "${PERSONALIZER_REPO_URL}" "${PERSONALIZER_REPO_DIR}"
|
|
|
|
if [[ "${detected_features[@]}" != *'Touchpad'* ]]; then
|
|
rm ${PERSONALIZER_REPO_DIR}/scripts/gnome-toggle-touchpad-lock
|
|
fi
|
|
|
|
if [[ "${detected_features[@]}" != *'Windows'* ]]; then
|
|
rm ${PERSONALIZER_REPO_DIR}/scripts/reboot-windows
|
|
fi
|
|
|
|
chmod +x ${PERSONALIZER_REPO_DIR}/scripts/*
|
|
sudo cp ${PERSONALIZER_REPO_DIR}/scripts/* /usr/bin
|
|
|
|
########################################
|
|
# Desktop entries
|
|
|
|
echo "Installing desktop entries..."
|
|
|
|
if [[ "${detected_features[@]}" != *'Windows'* ]]; then
|
|
rm ${PERSONALIZER_REPO_DIR}/desktop_entries/windows.desktop
|
|
fi
|
|
|
|
mkdir -p ${HOME}/.local/share/applications/
|
|
cp ${PERSONALIZER_REPO_DIR}/desktop-entries/* ${HOME}/.local/share/applications/
|
|
|
|
################################################################################
|
|
#
|
|
# Post-setup suggestions
|
|
#
|
|
################################################################################
|
|
|
|
echo "
|
|
Personalization complete!
|
|
|
|
Recommended next steps:
|
|
|
|
• Reboot
|
|
|
|
• Log in to Firefox Sync
|
|
|
|
• Configure Nextcloud client
|
|
$(if [[ "${optional_additions}" == *"EasyEffects"* ]]; then echo " • Install an audio device profile from\n https://autoeq.app\n"; fi)
|
|
• Install a Wireguard VPN profile from
|
|
https://mullvad.net/en/account/#/wireguard-config/?platform=linux
|
|
|
|
• Configure display settings and run 'gdm-update-display-settings'
|
|
|
|
• Run 'themer' to install/update unofficial libadwaita themes
|
|
|
|
(A copy of these recommendations has been saved to ${HOME}/next-steps)" | tee ${HOME}/next-steps
|