diff --git a/lib/desktop.sh b/lib/desktop.sh index 1af12db..35debac 100644 --- a/lib/desktop.sh +++ b/lib/desktop.sh @@ -19,7 +19,9 @@ desktop_session_file() { # whichever GNOME one is installed (gnome.desktop, gnome-xorg.desktop). local f if [[ "$(desktop_kind)" == gnome ]]; then - for f in /usr/share/wayland-sessions/gnome*.desktop /usr/share/xsessions/gnome*.desktop; do + # The plain session, not GNOME Classic (gnome-classic.desktop, from gnome-shell-extensions) or Xorg's. + for f in /usr/share/wayland-sessions/gnome.desktop /usr/share/xsessions/gnome.desktop \ + /usr/share/wayland-sessions/gnome-wayland.desktop; do [[ -f "$f" ]] && { basename "$f"; return; } done echo gnome.desktop @@ -35,3 +37,14 @@ choose_login_manager() { elif [[ "${WANTED[single]:-0}" == 1 ]]; then LOGIN_MANAGER=sddm else LOGIN_MANAGER=plasmalogin; fi } + +desktop_installed() { + # desktop_installed kde|gnome: its session is installed (both can be: the + # menu then offers the theme of each). + local name=plasma f + [[ "$1" == gnome ]] && name=gnome + for f in /usr/share/wayland-sessions/$name*.desktop /usr/share/xsessions/$name*.desktop; do + [[ -f "$f" ]] && return 0 + done + return 1 +} diff --git a/lib/gnome-theme.sh b/lib/gnome-theme.sh new file mode 100644 index 0000000..8f69c81 --- /dev/null +++ b/lib/gnome-theme.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# SteamOS look for GNOME, the counterpart of lib/vapor-theme.sh: the Vapor +# palette from CachyOS's cachyos-vapor package (also the Steam Deck +# wallpapers), as dark mode, a blue accent, the wallpaper and libadwaita/GTK4 +# colors. Settings go through gsettings and its undo journal (lib/state.sh). +# Sourced by steamify.sh; not meant to be run on its own. + +GNOME_THEME_MARK="/* Steamify GNOME theme */" +GNOME_THEME_CSS="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-4.0/gtk.css" +GNOME_THEME_SHELL_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/themes/SteamifyVapor/gnome-shell" +# The Ubuntu-style look: the dock (Ubuntu Dock is Dash to Dock) and the User +# Themes extension, which loads the shell theme. (Desktop Icons NG and +# AppIndicator come with the conversion, lib/desktop-shortcut.sh.) +GNOME_THEME_PACKAGES=(gnome-shell-extensions) +GNOME_THEME_EXTENSIONS=(user-theme@gnome-shell-extensions.gcampax.github.com dash-to-dock@micxgx.gmail.com + steamify-desktop-start@steamify.github.io) +# CachyOS's dash-to-dock package (106) doesn't load on GNOME 51: upstream's release, from extensions.gnome.org's tag. +DOCK_URL="https://github.com/micheleg/dash-to-dock/releases/download/extensions.gnome.org-v110/dash-to-dock@micxgx.gmail.com.zip" +DOCK_SHA256=3e60680fe7217b905aac4f10deb042e39fcf49168c9b8fdcc5a711bdd49bd3d2 +GNOME_USER_EXTENSIONS="${XDG_DATA_HOME:-$HOME/.local/share}/gnome-shell/extensions" +GNOME_THEME_WALLPAPER="/usr/share/wallpapers/Steam Deck Logo Default.jpg" + +gnometheme_status() { + grep -qsF "$GNOME_THEME_MARK" "$GNOME_THEME_CSS" +} + +gnometheme_extensions_install() { + # The dock (pinned upstream release) and the start-on-the-desktop extension, in the user's own extensions folder. + local zip dir="$GNOME_USER_EXTENSIONS/dash-to-dock@micxgx.gmail.com" + if [[ ! -f "$dir/metadata.json" ]] || ! grep -q '"version": 110' "$dir/metadata.json"; then + zip="$(mktemp --suffix=.zip)" + if curl -fsSL --max-time 60 "$DOCK_URL" -o "$zip" && [[ "$(sha256sum < "$zip")" == "$DOCK_SHA256 -" ]]; then + rm -rf "$dir"; mkdir -p "$dir" + python3 -c 'import sys,zipfile;zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])' "$zip" "$dir" + glib-compile-schemas "$dir/schemas" 2>/dev/null + else + warn "Couldn't download the dock (Dash to Dock 110); it stays off." + fi + rm -f "$zip" + fi + dir="$GNOME_USER_EXTENSIONS/steamify-desktop-start@steamify.github.io" + mkdir -p "$dir" + patch_file steamify-desktop-start.js > "$dir/extension.js" + patch_file steamify-desktop-start.json > "$dir/metadata.json" +} + +gnometheme_shell() { + # The top bar and dash colors: a shell theme, loaded by User Themes, and the dock beside it. + sudo pacman -S --needed --noconfirm "${GNOME_THEME_PACKAGES[@]}" >/dev/null 2>&1 || + { warn "Couldn't install the dock and the shell theme extension; the colors of apps are set."; return 0; } + gnometheme_extensions_install + mkdir -p "$GNOME_THEME_SHELL_DIR" + patch_file steamify-gnome-shell.css > "$GNOME_THEME_SHELL_DIR/gnome-shell.css" + gset gnometheme org.gnome.shell.extensions.user-theme name "'SteamifyVapor'" || true + # Like Ubuntu's dock: on the left, full height, always there, in Vapor's panel color. + local d=org.gnome.shell.extensions.dash-to-dock + gset gnometheme $d dock-position "'LEFT'" || true + gset gnometheme $d extend-height true || true + gset gnometheme $d dock-fixed true || true + gset gnometheme $d transparency-mode "'FIXED'" || true + gset gnometheme $d custom-background-color true || true + gset gnometheme $d background-color "'#24272c'" || true + gset gnometheme $d background-opacity 0.95 || true + gset gnometheme $d running-indicator-style "'DOTS'" || true + gset gnometheme $d custom-theme-shrink true || true + local uuid enabled + for uuid in "${GNOME_THEME_EXTENSIONS[@]}"; do + enabled="$(gs get org.gnome.shell enabled-extensions 2>/dev/null)" || return 0 + [[ "$enabled" == *"$uuid"* ]] && continue + if [[ "$enabled" == "@as []" || "$enabled" == "[]" ]]; then enabled="['$uuid']" + else enabled="${enabled%]}, '$uuid']"; fi + gset gnometheme org.gnome.shell enabled-extensions "$enabled" + done +} + +gnometheme_enable() { + if ! pacman -Q cachyos-vapor >/dev/null 2>&1; then + info "Installing cachyos-vapor (its wallpapers and colors)..." + sudo pacman -S --needed --noconfirm cachyos-vapor || { err "Installing cachyos-vapor failed."; return 1; } + # Only remove it again on disable if we were the ones installing it. + state_set gnometheme installed_pkg 1 + fi + info "Applying the SteamOS look to GNOME..." + gset gnometheme org.gnome.desktop.interface color-scheme "'prefer-dark'" + gset gnometheme org.gnome.desktop.interface accent-color "'blue'" || true + gset gnometheme org.gnome.desktop.interface gtk-theme "'Vapor'" || true + if [[ -f "$GNOME_THEME_WALLPAPER" ]]; then + local uri="file://${GNOME_THEME_WALLPAPER// /%20}" + gset gnometheme org.gnome.desktop.background picture-uri "'$uri'" + gset gnometheme org.gnome.desktop.background picture-uri-dark "'$uri'" || true + gset gnometheme org.gnome.desktop.background picture-options "'zoom'" + fi + # GTK4/libadwaita apps ignore GTK themes: their colors come from this file. + mkdir -p "$(dirname "$GNOME_THEME_CSS")" + if [[ -f "$GNOME_THEME_CSS" ]] && ! gnometheme_status; then + cp -a "$GNOME_THEME_CSS" "$STATE_DIR/gnometheme-gtk4.css" + fi + { echo "$GNOME_THEME_MARK"; patch_file steamify-gnome-gtk4.css; } > "$GNOME_THEME_CSS" + gnometheme_shell + ok "SteamOS theme for GNOME on (apps pick up the colors when they start again)." +} + +gnometheme_disable() { + info "Restoring GNOME's previous look..." + grevert gnometheme + rm -rf "${GNOME_THEME_SHELL_DIR%/gnome-shell}" "$GNOME_USER_EXTENSIONS/steamify-desktop-start@steamify.github.io" \ + "$GNOME_USER_EXTENSIONS/dash-to-dock@micxgx.gmail.com" + if [[ -f "$STATE_DIR/gnometheme-gtk4.css" ]]; then + mv -f "$STATE_DIR/gnometheme-gtk4.css" "$GNOME_THEME_CSS" + else + gnometheme_status && rm -f "$GNOME_THEME_CSS" + fi + if [[ -n "$(state_get gnometheme installed_pkg)" ]]; then + # Fails, and stays installed, when the KDE theme or another package needs it. + sudo pacman -R --noconfirm cachyos-vapor >/dev/null 2>&1 || + info "Keeping cachyos-vapor installed (another package needs it)." + fi + state_clear gnometheme + ok "Previous GNOME look restored." +} diff --git a/lib/menu.sh b/lib/menu.sh index d697dca..7276c00 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -5,7 +5,7 @@ # Menu order. Components are turned on in this order and off in reverse; # gaming must come first (single user builds on it). -COMPONENTS=(gaming boot silent glyphs nvidia bigpicture nvsilent theme single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios) +COMPONENTS=(gaming boot silent glyphs nvidia bigpicture nvsilent theme gnometheme single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios) # One-off actions rather than on/off components: never preselected, never # re-applied, not listed as on or off. ACTIONS=(bios) @@ -26,7 +26,7 @@ NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support) # FEATURE_BASELINE. FEATURE_BASELINE=2.1.0 declare -A FEATURE_VERSION=( - [gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.12.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0 + [gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.12.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [gnometheme]=2.12.0 [glyphs]=2.1.0 [single]=2.1.0 [launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0 [kpin]=2.1.0 [hdmi]=2.1.0 ) @@ -39,6 +39,7 @@ declare -A LABEL=( [nvsilent]="Start Steam silently: in the tray at login, no window (untick: Steam's normal window)" [bigpicture]="Steam starts in Big Picture: the controller-friendly Steam (untick: Steam's normal window)" [theme]="Install SteamOS theme: Vapor look (cachyos-vapor)" + [gnometheme]="Install SteamOS theme for GNOME: Vapor look (dark, blue accent, Steam Deck wallpaper)" [glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode" [single]="Single user mode: no password, lock screen or log out (SDDM)" [launcher]="Steamify shortcut: the app on the desktop, Steamify Terminal in the launcher" @@ -60,8 +61,10 @@ component_available() { # The SteamOS conversion is offered on NVIDIA PCs too: it installs the patched gamescope there (lib/gamescope-nvidia.sh) # and turns off "Gaming on NVIDIA" (lib/nvidia.sh), which is not offered any more (nvidia_available). nvidia|bigpicture|nvsilent) nvidia_available ;; - # Plasma only: the Vapor theme and single user mode (KDE Wallet, screen locker, Plasma's menu). Not on GNOME. - theme|single) [[ "$(desktop_kind)" == kde ]] ;; + # Plasma's Vapor theme and single user mode (KDE Wallet, screen locker, Plasma's menu): when Plasma is installed. + # The GNOME theme: when GNOME is. With both installed, each shows. + theme|single) desktop_installed kde ;; + gnometheme) desktop_installed gnome ;; machine|poweroff) machine_available ;; vram) vram_available ;; # Steamify in the Steam library is for gaming mode's controller: not needed for Big Picture on the desktop (NVIDIA PCs; diff --git a/lib/state.sh b/lib/state.sh index 818ee09..14a38ac 100644 --- a/lib/state.sh +++ b/lib/state.sh @@ -59,6 +59,40 @@ krevert() { rm -f "$journal" } +gs() { + # gsettings, also without a session (the installer's chroot): then in a + # session bus of its own, which writes the user's dconf database. + if user_session; then gsettings "$@"; else dbus-run-session -- gsettings "$@"; fi +} + +gset() { + # gset : gsettings (GNOME), recording the + # old value in the component's journal like kset does. is in + # GVariant text form ('prefer-dark', true, 5). A key the schema lacks + # (newer GNOME only) is skipped, returning 1. + local component="$1" schema="$2" key="$3" value="$4" + local journal="$STATE_DIR/$component.gjournal" old id + gs get "$schema" "$key" >/dev/null 2>&1 || return 1 + mkdir -p "$STATE_DIR" + id="$(printf '%s\t%s' "$schema" "$key")" + if ! grep -qxF -- "$id" <(cut -f1-2 "$journal" 2>/dev/null); then + old="$(gs get "$schema" "$key")" + printf '%s\t%s\n' "$id" "$(printf '%s' "$old" | base64 -w0)" >> "$journal" + fi + gs set "$schema" "$key" "$value" +} + +grevert() { + # grevert : put back every gsettings key the component changed. + local journal="$STATE_DIR/$1.gjournal" schema key old + [[ -f "$journal" ]] || return 0 + while IFS=$'\t' read -r schema key old; do + old="$(printf '%s' "$old" | base64 -d)" + gs set "$schema" "$key" "$old" 2>/dev/null || gs reset "$schema" "$key" 2>/dev/null + done < <(tac "$journal") + rm -f "$journal" +} + has_journal() { [[ -s "$STATE_DIR/$1.journal" ]] } diff --git a/lib/vapor-theme.sh b/lib/vapor-theme.sh index d9b688a..859c90a 100644 --- a/lib/vapor-theme.sh +++ b/lib/vapor-theme.sh @@ -157,7 +157,7 @@ theme_disable() { restart_plasmashell_if_stopped qdbus6 org.kde.KWin /KWin org.kde.KWin.reconfigure >/dev/null 2>&1 || true - if [[ -n "$(state_get theme installed_pkg)" ]]; then + if [[ -n "$(state_get theme installed_pkg)" ]] && ! gnometheme_status; then # Fails, and stays installed, when another package (e.g. # cachyos-handheld) depends on it. sudo pacman -R --noconfirm cachyos-vapor >/dev/null 2>&1 || diff --git a/patches/steamify-desktop-start.js b/patches/steamify-desktop-start.js new file mode 100644 index 0000000..0a05868 --- /dev/null +++ b/patches/steamify-desktop-start.js @@ -0,0 +1,27 @@ +// GNOME opens the overview after login; Ubuntu starts on the desktop. So does +// this (Steamify GNOME theme): the overview stays closed while the shell +// starts up, and is available again right after. +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js'; + +export default class SteamifyDesktopStart extends Extension { + enable() { + if (!Main.layoutManager._startingUp) + return; + this._hadOverview = Main.sessionMode.hasOverview; + Main.sessionMode.hasOverview = false; + this._startupId = Main.layoutManager.connect('startup-complete', () => { + Main.sessionMode.hasOverview = this._hadOverview; + Main.overview.hide(); + }); + } + + disable() { + if (this._startupId) { + Main.layoutManager.disconnect(this._startupId); + this._startupId = null; + } + if (this._hadOverview !== undefined) + Main.sessionMode.hasOverview = this._hadOverview; + } +} diff --git a/patches/steamify-desktop-start.json b/patches/steamify-desktop-start.json new file mode 100644 index 0000000..ad38c2c --- /dev/null +++ b/patches/steamify-desktop-start.json @@ -0,0 +1,6 @@ +{ + "uuid": "steamify-desktop-start@steamify.github.io", + "name": "Steamify: start on the desktop", + "description": "Log in to the desktop, not the overview (like Ubuntu).", + "shell-version": ["45", "46", "47", "48", "49", "50", "51"] +} diff --git a/patches/steamify-gnome-gtk4.css b/patches/steamify-gnome-gtk4.css new file mode 100644 index 0000000..b137341 --- /dev/null +++ b/patches/steamify-gnome-gtk4.css @@ -0,0 +1,14 @@ +/* Steamify Vapor: libadwaita/GTK4 colors, from Vapor's palette (cachyos-vapor, Vapor.colors). */ +@define-color accent_bg_color #569fcc; +@define-color accent_fg_color #1f1f26; +@define-color accent_color #3daee9; +@define-color window_bg_color #24272c; +@define-color window_fg_color #eff0f1; +@define-color view_bg_color #151c23; +@define-color view_fg_color #eff0f1; +@define-color headerbar_bg_color #24272c; +@define-color headerbar_fg_color #eff0f1; +@define-color card_bg_color #2a2e32; +@define-color popover_bg_color #2a2e32; +@define-color sidebar_bg_color #1f2328; +@define-color dialog_bg_color #2a2e32; diff --git a/patches/steamify-gnome-shell.css b/patches/steamify-gnome-shell.css new file mode 100644 index 0000000..2dd75c8 --- /dev/null +++ b/patches/steamify-gnome-shell.css @@ -0,0 +1,47 @@ +/* Steamify Vapor: the SteamOS look for GNOME Shell. + * Starts from the stock GNOME Shell theme and recolors it with the + * palette of the Vapor theme (KDE Plasma's SteamOS look, cachyos-vapor). */ +@import url("resource:///org/gnome/shell/theme/gnome-shell.css"); + +/* Top bar: Vapor's panel color. */ +#panel, +#panel.lock-screen, +#panel.unlock-screen { + background-color: #24272c; +} +#panel .panel-button { color: #eff0f1; } +#panel .panel-button:hover, +#panel .panel-button:focus, +#panel .panel-button:active, +#panel .panel-button:checked, +#panel .panel-button:overview { + background-color: rgba(86, 159, 204, 0.35); + color: #eff0f1; +} + +/* Dash in the overview, popups and the calendar. */ +#dash .dash-background { background-color: #24272c; } +.popup-menu-content, +.candidate-popup-content, +.message-list-clear-button { + background-color: #24272c; +} +.popup-menu-item:hover, +.popup-menu-item:focus, +.popup-menu-item:active { + background-color: rgba(86, 159, 204, 0.35); +} + +/* Selection and focus in Vapor's blue. */ +.app-well-app:focus .overview-icon, +.app-well-app:selected .overview-icon, +.overview-tile:focus, +.overview-tile:selected, +.search-entry:focus { + background-color: rgba(86, 159, 204, 0.3); + border-color: #3daee9; +} +.button:focus, +.check-box:focus StBin { border-color: #3daee9; } +.slider { color: #3daee9; } +.workspace-thumbnail-indicator { border-color: #3daee9; } diff --git a/steamify.sh b/steamify.sh index 1b21594..c0fa518 100755 --- a/steamify.sh +++ b/steamify.sh @@ -19,7 +19,7 @@ VERSION=2.12.0 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -for lib in common state desktop packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia gamescope-nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do +for lib in common state desktop packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia gamescope-nvidia controllers cec boot-session vapor-theme gnome-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do # shellcheck source=/dev/null source "$SCRIPT_DIR/lib/$lib.sh" done