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