#!/bin/bash ################################################################################ # # opensuse-personalizer.sh # Interactive post-install setup script for OpenSUSE installations # ################################################################################ ################################################################################ # # Constants # ################################################################################ ######################################## # 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) \ wget nano git-core flatpak opi \ \ # (Theming) \ papirus-icon-theme fira-code-fonts \ \ # (Shell utilities) \ fish fzf fortune toilet cowsay \ \ # (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 # To install 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 ######################################## # Directories SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) TMP_WORKDIR="/tmp/opensuse-setup-script-workdir/" ################################################################################ # # 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 zenity is installed echo "Ensuring zenity is installed..." sudo zypper --non-interactive in zenity ######################################## # Prompt for system chassis system_chassis=$(hostnamectl chassis) function string_eq () { [[ "${1}" == "${2}" ]] && echo TRUE || echo FALSE } function prompt_chassis_type () { entry=$(zenity --title="Chassis Type" --list --radiolist --width=200 --height=400 \ --text="Confirm the chassis type for this system:\n" \ --column="Selected" --column="Chassis Type" \ $(string_eq "${system_chassis}" "desktop") "Desktop" \ $(string_eq "${system_chassis}" "laptop") "Laptop" \ $(string_eq "${system_chassis}" "tablet") "Tablet" \ $(string_eq "${system_chassis}" "convertible") "Convertible") # Ensure entry is lowercase entry=${entry,,} case "${entry}" in "desktop"|"laptop"|"convertible"|"tablet") if zenity --question --title="Chassis Type" --text="Use ${entry} as chassis type?" --default-cancel --no-wrap then system_chassis="${entry}" return 0 else return 1 fi ;; *) zenity --warning --title="Chassis Type" --text="Please choose a chassis type for this system." --no-wrap 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}" ######################################## # Prompt for system name system_name="mycomputer" function prompt_system_name () { entry=$(zenity --entry --title="System Name" --text="All lowercase letters, no spaces or symbols:" --entry-text="${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 "mycomputer") zenity --warning --title="System Name" --text="Please enter a name for this system." --no-wrap return 1 ;; "") zenity --warning --title="System Name" --text="Please enter a name for this system." --no-wrap return 1 ;; *) if zenity --question --title="System Name" --text="Use ${entry} as system name?" --default-cancel --no-wrap 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=$(zenity --title="Optional Additions" --list --checklist --width=600 --height=440 \ --text="Select any additional configuration changes that you would like applied to the system:\n" \ --column="Apply" --column="Title" --column="Description" \ FALSE "Xournal++" "Install Xournal++ for taking handwritten notes" \ FALSE "EasyEffects" "Install EasyEffects for applying effects (e.g. equalizers) to system audio devices" \ FALSE "Media Control Key Shortcuts" "Set up media control keyboard shortcuts (for keyboards without dedicated media control keys)" \ FALSE "Touchpad Lock Toggle Shortcut" "Set up a touchpad lock toggle keyboard shortcut (for systems with touchpads)" \ FALSE "Power Button Screen Lock Override" "Override the power button's default behavior with a screen lock shortcut (for tablets or convertibles)" \ FALSE '"Reboot to Windows" Launcher' "Install a desktop entry that reboots the system to Microsoft Windows (for systems that multi-boot with Windows)") case "${ENTRY}" in "") if zenity --question --title="Optional Additions" --text="Apply only baseline system configuration?" --default-cancel --no-wrap then return 0 else return 1 fi ;; *) if ADDITIONS_LIST=$(echo " • ${ENTRY}" | sed "s/|/\n • /g") zenity --question --title="Optional Additions" --text="Confirm your selection of the following additions:\n${ADDITIONS_LIST}" --default-cancel --no-wrap 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 ################################################################################ # # Package setup # ################################################################################ ######################################## # Package operations echo "Setting up packages..." 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..." FLATHUB_REMOTE=https://flathub.org/repo/flathub.flatpakrepo 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 "['Left']" gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left "['Right']" gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-left "['Left']" gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-left "['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 "['Home']" gsettings set org.gnome.settings-daemon.plugins.media-keys next "['Page_Down']" gsettings set org.gnome.settings-daemon.plugins.media-keys previous "['Page_Up']" gsettings set org.gnome.settings-daemon.plugins.media-keys volume-down "['Page_Down']" gsettings set org.gnome.settings-daemon.plugins.media-keys volume-mute "['End']" gsettings set org.gnome.settings-daemon.plugins.media-keys volume-up "['Page_Up']" fi ######################################## # Windows gsettings set org.gnome.desktop.wm.keybindings close "['w']" gsettings set org.gnome.desktop.wm.keybindings toggle-fullscreen "['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}/ gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings "$(echo ${EXISTING_KEYBINDINGS} | sed s/.$//), '${KEYBINDING_PATH}']" 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" "Return" add_custom_gnome_keybinding "Toggle Night Light" "gnome-toggle-night-light" "n" # (OPTIONAL) Add custom shortcuts if [[ "${optional_additions}" == *"Touchpad Lock Toggle Shortcut"* ]]; then add_custom_gnome_keybinding "Toggle Touchpad Lock" "gnome-toggle-touchpad-lock" "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 false gsettings set org.gnome.desktop.interface clock-show-weekday false 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" ################################################################################ # # GNOME app folder configuration # ################################################################################ echo "Configuring GNOME app folders..." ######################################## # 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} 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 "Downloading Emacs configuration..." wget https://jessieh.net/emacs -O ${HOME}/.config/emacs/init.el ######################################## # Fish echo "Downloading Fish configuration..." wget https://jessieh.net/fish -O ${HOME}/.config/fish/config.fish echo "Setting default shell to Fish..." chsh -s $(which fish) ######################################## # Utility scripts echo "Installing scripts..." if [[ "${optional_additions}" != *'"Reboot to Windows" Launcher'* ]]; then rm ${SCRIPT_DIR}/scripts/reboot-windows fi chmod +x ${SCRIPT_DIR}/scripts/* sudo cp ${SCRIPT_DIR}/scripts/* /usr/bin ######################################## # Desktop entries echo "Installing desktop entries..." if [[ "${optional_additions}" != *'"Reboot to Windows" Launcher'* ]]; then rm ${SCRIPT_DIR}/desktop_entries/windows.desktop fi mkdir -p ${HOME}/.local/share/applications/ cp ${SCRIPT_DIR}/desktop-entries/* ${HOME}/.local/share/applications/ ################################################################################ # # Post-setup suggestions # ################################################################################ echo echo "Personalization complete!" echo echo "Recommended next steps:" echo " • Log in to Firefox Sync" echo " • Configure Nextcloud client" if [[ "${optional_additions}" == *"EasyEffects"* ]]; then echo " • Install an audio device profile from" echo " https://autoeq.app" fi echo " • Install a Wireguard VPN profile from" echo " https://mullvad.net/en/account/#/wireguard-config/?platform=linux" echo " • Configure display settings and run 'gdm-update-display-settings'" echo " • Run 'themer' to install/update unofficial libadwaita themes"