mirror of
				https://github.com/MatMasIt/gnome-therminal-autotheme.git
				synced 2025-10-31 01:30:04 +01:00 
			
		
		
		
	first commit
This commit is contained in:
		
							
								
								
									
										60
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | # GNOME Terminal Auto Theme Sync | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Automatically sync your GNOME Terminal theme with your system's light/dark mode preferences. | ||||||
|  |  | ||||||
|  | ## Features | ||||||
|  |  | ||||||
|  | - 🌓 Automatic theme switching between light and dark modes | ||||||
|  | - ⚡ Instant theme application when system preference changes | ||||||
|  | - 🔄 Background process that monitors system theme changes | ||||||
|  | - 🛠️ Easy installation and uninstallation | ||||||
|  |  | ||||||
|  | ## Installation | ||||||
|  |  | ||||||
|  | 1. **Download the project files**: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | git clone https://github.com/MatMasIt/gnome-terminal-autotheme.git | ||||||
|  | cd gnome-terminal-autotheme | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 2. **Run the installer**: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | ./install.sh | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 3. **Follow the prompts** to complete installation. | ||||||
|  |  | ||||||
|  | The installer will: | ||||||
|  | - Copy necessary files | ||||||
|  | - Set up autostart entry | ||||||
|  | - Start the theme sync service | ||||||
|  |  | ||||||
|  | ## Uninstallation | ||||||
|  |  | ||||||
|  | To remove the auto theme sync, simply run the installer again. | ||||||
|  |  | ||||||
|  | You'll be prompted to choose: | ||||||
|  | - Remove just the autostart entry or the whole installation | ||||||
|  | - Whether to keep your terminal in light or dark mode after uninstall | ||||||
|  |  | ||||||
|  | ## Requirements | ||||||
|  |  | ||||||
|  | - GNOME Desktop Environment (tested on GNOME 40+) | ||||||
|  | - GNOME Terminal | ||||||
|  | - Bash 4.0+ | ||||||
|  |  | ||||||
|  | ## Configuration | ||||||
|  |  | ||||||
|  | Advanced users can edit the theme definitions in: [sync-terminal-theme.sh](sync-terminal-theme.sh) | ||||||
|  |  | ||||||
|  | ## Contributing | ||||||
|  |  | ||||||
|  | Contributions are welcome! Please open an issue or pull request. | ||||||
|  |  | ||||||
|  | ## License | ||||||
|  |  | ||||||
|  | MIT License - See [LICENSE](LICENSE) file for details | ||||||
							
								
								
									
										7
									
								
								gnome-terminal-autotheme.desktop
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								gnome-terminal-autotheme.desktop
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | [Desktop Entry] | ||||||
|  | Type=Application | ||||||
|  | Exec=PATH/sync-terminal-theme.sh | ||||||
|  | Hidden=false | ||||||
|  | NoDisplay=false | ||||||
|  | X-GNOME-Autostart-enabled=true | ||||||
|  | Name=GNOME Terminal Theme Sync | ||||||
							
								
								
									
										305
									
								
								install.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										305
									
								
								install.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,305 @@ | |||||||
|  | #!/usr/bin/env bash | ||||||
|  |  | ||||||
|  | set -euo pipefail | ||||||
|  | IFS=$'\n\t' | ||||||
|  |  | ||||||
|  | # Constants | ||||||
|  | readonly DEFAULT_DIR="$HOME/.local/share/gnome-terminal-autotheme" | ||||||
|  | readonly DESKTOP_FILE_NAME="gnome-terminal-autotheme.desktop" | ||||||
|  | readonly AUTOSTART_DIR="$HOME/.config/autostart" | ||||||
|  | readonly AUTOSTART_TARGET="$AUTOSTART_DIR/$DESKTOP_FILE_NAME" | ||||||
|  | readonly SCRIPT_NAME="sync-terminal-theme.sh" | ||||||
|  | readonly VERSION="1.1.0" | ||||||
|  |  | ||||||
|  | # Colors for output | ||||||
|  | readonly RED='\033[0;31m' | ||||||
|  | readonly GREEN='\033[0;32m' | ||||||
|  | readonly YELLOW='\033[0;33m' | ||||||
|  | readonly BLUE='\033[0;34m' | ||||||
|  | readonly NC='\033[0m' # No Color | ||||||
|  |  | ||||||
|  | # Utility functions | ||||||
|  | error() { | ||||||
|  |   echo -e "${RED}[ERROR]${NC} $1" >&2 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | warning() { | ||||||
|  |   echo -e "${YELLOW}[WARNING]${NC} $1" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | info() { | ||||||
|  |   echo -e "${BLUE}[INFO]${NC} $1" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | success() { | ||||||
|  |   echo -e "${GREEN}[SUCCESS]${NC} $1" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | check_installed() { | ||||||
|  |   command -v "$1" >/dev/null 2>&1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | stop_existing_processes() { | ||||||
|  |   local pids | ||||||
|  |   pids=$(pgrep -f "$SCRIPT_NAME" || true) | ||||||
|  |  | ||||||
|  |   if [[ -n "$pids" ]]; then | ||||||
|  |     info "Stopping existing theme sync processes..." | ||||||
|  |     for pid in $pids; do | ||||||
|  |       if kill -0 "$pid" 2>/dev/null; then | ||||||
|  |         kill "$pid" && info "Stopped process $pid" || warning "Failed to stop process $pid" | ||||||
|  |       fi | ||||||
|  |     done | ||||||
|  |     # Wait a moment for processes to terminate | ||||||
|  |     sleep 0.5 | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  |  | ||||||
|  | validate_path() { | ||||||
|  |   local path="$1" | ||||||
|  |   [[ -z "$path" ]] && { error "Path cannot be empty"; return 1; } | ||||||
|  |   [[ "$path" == "/" ]] && { error "Cannot use root directory"; return 1; } | ||||||
|  |   [[ "$path" =~ ^/etc ]] && { error "System directories not allowed"; return 1; } | ||||||
|  |   return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | is_gnome() { | ||||||
|  |   [[ "$XDG_CURRENT_DESKTOP" =~ GNOME|gnome ]] || check_installed gnome-session | ||||||
|  | } | ||||||
|  |  | ||||||
|  | start_sync() { | ||||||
|  |   info "Running sync script now in the background..." | ||||||
|  |   nohup bash "$INSTALL_DIR/$SCRIPT_NAME" >/dev/null 2>&1 & | ||||||
|  |   disown | ||||||
|  |   success "Theme sync script running in background (PID: $!)" | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | check_integrity() { | ||||||
|  |   local install_dir="${1:-$DEFAULT_DIR}" | ||||||
|  |   info "Checking installation integrity in: $install_dir" | ||||||
|  |  | ||||||
|  |   local desktop_file="$AUTOSTART_TARGET" | ||||||
|  |   local target_exec | ||||||
|  |  | ||||||
|  |   if [[ ! -f "$desktop_file" ]]; then | ||||||
|  |     error "Autostart desktop entry not found: $desktop_file" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   # Extract Exec path from .desktop file | ||||||
|  |   target_exec=$(grep -oP '^Exec=\K.+' "$desktop_file" | head -n1) | ||||||
|  |   if [[ -z "$target_exec" ]]; then | ||||||
|  |     error "No Exec entry found in desktop file" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   if [[ ! -f "$target_exec" ]]; then | ||||||
|  |     error "Script file referenced in .desktop does not exist: $target_exec" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   if [[ ! -x "$target_exec" ]]; then | ||||||
|  |     error "Script file is not executable: $target_exec" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   if ! head -n 1 "$target_exec" | grep -qE '^#!.*/bash'; then | ||||||
|  |     error "Script does not start with a valid bash shebang: $target_exec" | ||||||
|  |     return 1 | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   success "All basic integrity checks passed" | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | uninstall() { | ||||||
|  |   local install_dir="$1" | ||||||
|  |   local uninstall_choice="${2:-autostart}" | ||||||
|  |   local theme_choice="${3:-d}" | ||||||
|  |  | ||||||
|  |   info "Starting uninstallation..." | ||||||
|  |    | ||||||
|  |   # Kill running process | ||||||
|  |   stop_existing_processes | ||||||
|  |  | ||||||
|  |   # Remove autostart entry | ||||||
|  |   if [[ -f "$AUTOSTART_TARGET" ]]; then | ||||||
|  |     rm -f -- "$AUTOSTART_TARGET" && success "Autostart entry removed" || error "Failed to remove autostart entry" | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   # Apply final theme | ||||||
|  |   case "${theme_choice,,}" in | ||||||
|  |     l|light) | ||||||
|  |       bash "$install_dir/$SCRIPT_NAME" light && success "Applied light theme" || error "Failed to apply light theme" | ||||||
|  |       ;; | ||||||
|  |     d|dark) | ||||||
|  |       bash "$install_dir/$SCRIPT_NAME" dark && success "Applied dark theme" || error "Failed to apply dark theme" | ||||||
|  |       ;; | ||||||
|  |     *) | ||||||
|  |       warning "No theme change applied" | ||||||
|  |       ;; | ||||||
|  |   esac | ||||||
|  |  | ||||||
|  |   # Remove installation directory if requested | ||||||
|  |   if [[ "$uninstall_choice" =~ ^whole$ ]]; then | ||||||
|  |     if [[ -d "$install_dir" ]]; then | ||||||
|  |       rm -rf -- "$install_dir" && success "Installation directory removed" || error "Failed to remove directory" | ||||||
|  |     else | ||||||
|  |       warning "Installation directory not found" | ||||||
|  |     fi | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   success "Uninstallation complete" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | install() { | ||||||
|  |  | ||||||
|  |   local reinstall="${1:-false}" | ||||||
|  |   local provided_path="${2:-}" | ||||||
|  |  | ||||||
|  |   info "Starting installation..." | ||||||
|  |  | ||||||
|  |   stop_existing_processes | ||||||
|  |  | ||||||
|  |   # Check for gnome-terminal | ||||||
|  |   if ! check_installed gnome-terminal; then | ||||||
|  |     warning "gnome-terminal not found" | ||||||
|  |     read -rp "Continue anyway? [y/N]: " proceed_terminal | ||||||
|  |     [[ "${proceed_terminal,,}" =~ ^y ]] || { error "Aborted"; exit 1; } | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   # Check for GNOME | ||||||
|  |   if ! is_gnome; then | ||||||
|  |     warning "GNOME not detected" | ||||||
|  |     read -rp "Continue anyway? [y/N]: " proceed_gnome | ||||||
|  |     [[ "${proceed_gnome,,}" =~ ^y ]] || { error "Aborted"; exit 1; } | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   # Use provided path or prompt user | ||||||
|  |   if [[ -n "$provided_path" ]]; then | ||||||
|  |     INSTALL_DIR=$(realpath -m "$provided_path") | ||||||
|  |   else | ||||||
|  |     read -rp "Enter install path [default: $DEFAULT_DIR]: " install_dir | ||||||
|  |     INSTALL_DIR=$(realpath -m "${install_dir:-$DEFAULT_DIR}") | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   if ! validate_path "$INSTALL_DIR"; then | ||||||
|  |     error "Invalid install path: $INSTALL_DIR" | ||||||
|  |     exit 1 | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   # Create directory | ||||||
|  |   mkdir -p -- "$INSTALL_DIR" || { error "Failed to create directory"; exit 1; } | ||||||
|  |  | ||||||
|  |   # Verify source files exist | ||||||
|  |   if [[ ! -f "$SCRIPT_NAME" || ! -f "$DESKTOP_FILE_NAME" ]]; then | ||||||
|  |     error "Missing required files: $SCRIPT_NAME and $DESKTOP_FILE_NAME must be in current directory" | ||||||
|  |     exit 1 | ||||||
|  |   fi | ||||||
|  |  | ||||||
|  |   # Copy files | ||||||
|  |   cp -- "$SCRIPT_NAME" "$INSTALL_DIR/" || { error "Failed to copy script"; exit 1; } | ||||||
|  |   cp -- "$DESKTOP_FILE_NAME" "$INSTALL_DIR/" || { error "Failed to copy desktop file"; exit 1; } | ||||||
|  |  | ||||||
|  |   # Make script executable | ||||||
|  |   chmod +x "$INSTALL_DIR/$SCRIPT_NAME" || { error "Failed to make script executable"; exit 1; } | ||||||
|  |  | ||||||
|  |   # Create autostart entry | ||||||
|  |   mkdir -p -- "$AUTOSTART_DIR" || { error "Failed to create autostart directory"; exit 1; } | ||||||
|  |  | ||||||
|  |   # Escape path for sed | ||||||
|  |   local escaped_path=$(printf '%q' "$INSTALL_DIR/$SCRIPT_NAME") | ||||||
|  |   sed "s|Exec=.*|Exec=$escaped_path|" "$INSTALL_DIR/$DESKTOP_FILE_NAME" > "$AUTOSTART_TARGET" || { | ||||||
|  |     error "Failed to create autostart entry" | ||||||
|  |     exit 1 | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   success "Installation complete" | ||||||
|  |   success "Script installed to: $INSTALL_DIR" | ||||||
|  |   success "Autostart entry created: $AUTOSTART_TARGET" | ||||||
|  |  | ||||||
|  |   # Start sync process | ||||||
|  |   start_sync | ||||||
|  | } | ||||||
|  |  | ||||||
|  | main() { | ||||||
|  |   echo -e "${BLUE}=== GNOME Terminal Auto Theme Sync v$VERSION ===${NC}" | ||||||
|  |  | ||||||
|  |   # Check if installed | ||||||
|  |   if [[ -f "$AUTOSTART_TARGET" ]]; then | ||||||
|  |     local old_install_dir=$(grep -oP 'Exec=\K.+' "$AUTOSTART_TARGET" | sed "s|/$SCRIPT_NAME||") | ||||||
|  |      | ||||||
|  |     if [[ -z "$old_install_dir" || ! -d "$old_install_dir" ]]; then | ||||||
|  |       warning "Could not determine valid install path from autostart entry (you may want to look into it)" | ||||||
|  |       info "Fallback to default installation directory" | ||||||
|  |       old_install_dir="$DEFAULT_DIR" | ||||||
|  |       if [[ ! -d "$old_install_dir" ]]; then | ||||||
|  |         error "Default install directory does not exist: $old_install_dir" | ||||||
|  |         exit 1 | ||||||
|  |       fi | ||||||
|  |     fi | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |     info "Theme watcher already installed at: $old_install_dir" | ||||||
|  |      | ||||||
|  |     read -rp "Do you want to (u)ninstall, (r)einstall or check (i)ntegrity? [u/r/i/N]: " choice | ||||||
|  |     case "${choice,,}" in | ||||||
|  |       u)  | ||||||
|  |         # Loop until a valid choice is entered for uninstall | ||||||
|  |         while true; do | ||||||
|  |           read -rp "Uninstall (w)hole installation or (a)utostart entry? [w/a]: " uninstall_choice | ||||||
|  |           case "${uninstall_choice,,}" in | ||||||
|  |               a) uninstall_choice="autostart"; break ;;   | ||||||
|  |               w) uninstall_choice="whole"; break ;;  | ||||||
|  |           esac | ||||||
|  |           echo "Invalid choice, please enter 'w' for whole or 'a' for autostart." | ||||||
|  |         done | ||||||
|  |  | ||||||
|  |         # Loop until a valid choice is entered for theme selection | ||||||
|  |         while true; do | ||||||
|  |           read -rp "Set terminal theme to (l)ight or (d)ark after uninstall? [l/d]: " theme_choice | ||||||
|  |           case "${theme_choice,,}" in | ||||||
|  |               l) theme_choice="l"; break ;;   | ||||||
|  |               d) theme_choice="d"; break ;;  | ||||||
|  |           esac | ||||||
|  |           echo "Invalid choice, please enter 'l' for light or 'd' for dark." | ||||||
|  |         done | ||||||
|  |  | ||||||
|  |         uninstall "$old_install_dir" "$uninstall_choice" "$theme_choice" | ||||||
|  |         exit 0 | ||||||
|  |         ;; | ||||||
|  |       r)  | ||||||
|  |         read -rp "Enter new install path [default: $DEFAULT_DIR]: " install_dir | ||||||
|  |         INSTALL_DIR="${install_dir:-$DEFAULT_DIR}" | ||||||
|  |         INSTALL_DIR=$(realpath -m "$INSTALL_DIR") | ||||||
|  |  | ||||||
|  |         if [[ "$INSTALL_DIR" != "$old_install_dir" ]]; then | ||||||
|  |           read -rp "The new install path is different from the old one ($old_install_dir). Remove old directory? [y/N]: " remove_old | ||||||
|  |           if [[ "${remove_old,,}" =~ ^y ]]; then | ||||||
|  |             if [[ -d "$old_install_dir" ]]; then | ||||||
|  |               rm -rf -- "$old_install_dir" && success "Old installation directory removed" || error "Failed to remove old directory" | ||||||
|  |             else | ||||||
|  |               warning "Old installation directory not found" | ||||||
|  |             fi | ||||||
|  |           fi | ||||||
|  |         fi | ||||||
|  |  | ||||||
|  |         install true "$INSTALL_DIR" | ||||||
|  |         ;; | ||||||
|  |       i) | ||||||
|  |         check_integrity "$old_install_dir" | ||||||
|  |         exit $? | ||||||
|  |         ;; | ||||||
|  |       *)  | ||||||
|  |         info "No changes made" | ||||||
|  |         exit 0 | ||||||
|  |         ;; | ||||||
|  |     esac | ||||||
|  |   else | ||||||
|  |     install | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  |  | ||||||
|  | main | ||||||
							
								
								
									
										54
									
								
								sync-terminal-theme.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										54
									
								
								sync-terminal-theme.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | #!/bin/bash | ||||||
|  |  | ||||||
|  | # Get the default profile UUID | ||||||
|  | PROFILE_ID=$(gsettings get org.gnome.Terminal.ProfilesList default | tr -d \') | ||||||
|  | PROFILE_PATH="/org/gnome/terminal/legacy/profiles:/:$PROFILE_ID" | ||||||
|  |  | ||||||
|  | # Define themes | ||||||
|  | set_dark_theme() { | ||||||
|  |     gsettings set org.gnome.Terminal.Legacy.Settings theme-variant 'dark' | ||||||
|  |     dconf write $PROFILE_PATH/use-theme-colors false | ||||||
|  |     dconf write $PROFILE_PATH/foreground-color "'#d4d4d4'" | ||||||
|  |     dconf write $PROFILE_PATH/background-color "'#1e1e1e'" | ||||||
|  |     dconf write $PROFILE_PATH/palette "['#1e1e1e', '#f44747', '#619955', '#ffaf00', '#85dfff', '#d27bff', '#4EC9B0', '#d4d4d4', '#808080', '#f44747', '#619955', '#ffaf00', '#85dfff', '#d27bff', '#4EC9B0', '#ffffff']" | ||||||
|  |     dconf write $PROFILE_PATH/cursor-color "'#d4d4d4'" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | set_light_theme() { | ||||||
|  |     gsettings set org.gnome.Terminal.Legacy.Settings theme-variant 'light' | ||||||
|  |     dconf write $PROFILE_PATH/use-theme-colors false | ||||||
|  |     dconf write $PROFILE_PATH/foreground-color "'#000000'" | ||||||
|  |     dconf write $PROFILE_PATH/background-color "'#ffffff'" | ||||||
|  |     dconf write $PROFILE_PATH/palette "['#000000', '#cc0000', '#4e9a06', '#c4a000', '#3465a4', '#75507b', '#06989a', '#d3d7cf', '#555753', '#ef2929', '#8ae234', '#fce94f', '#729fcf', '#ad7fa8', '#34e2e2', '#eeeeec']" | ||||||
|  |     dconf write $PROFILE_PATH/cursor-color "'#000000'" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | update_terminal_theme() { | ||||||
|  |     SCHEME=$(gsettings get org.gnome.desktop.interface color-scheme) | ||||||
|  |  | ||||||
|  |     if [[ "$SCHEME" == *"dark"* ]]; then | ||||||
|  |         set_dark_theme | ||||||
|  |     else | ||||||
|  |         set_light_theme | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # Check for manual arguments (light or dark) | ||||||
|  | if [[ "${1:-}" == "light" ]]; then | ||||||
|  |     set_light_theme | ||||||
|  |     echo "[sync-script] Applied light theme manually." | ||||||
|  |     exit 0 | ||||||
|  | elif [[ "${1:-}" == "dark" ]]; then | ||||||
|  |     set_dark_theme | ||||||
|  |     echo "[sync-script] Applied dark theme manually." | ||||||
|  |     exit 0 | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | # Run once immediately to apply based on the current GNOME theme | ||||||
|  | update_terminal_theme | ||||||
|  |  | ||||||
|  | # Monitor and auto-update GNOME theme changes | ||||||
|  | echo "[sync-script] Monitoring GNOME theme changes..." | ||||||
|  | gsettings monitor org.gnome.desktop.interface color-scheme | while read -r; do | ||||||
|  |     update_terminal_theme | ||||||
|  | done | ||||||
		Reference in New Issue
	
	Block a user