diff --git a/.config/matugen/config.toml b/.config/matugen/config.toml index 481a9753..863bc798 100644 --- a/.config/matugen/config.toml +++ b/.config/matugen/config.toml @@ -51,7 +51,7 @@ output_path = '~/.config/matugen/generated/hyprlock-colors.conf' input_path = '~/.config/matugen/templates/colors.css' output_path = '~/.config/matugen/generated/waybar-colors.css' post_hook = ''' -~/user_scripts/waybar/waybar_autostart.sh || true; +~/user_scripts/waybar/waybar_autostart.sh theme-change || true; ''' [templates.swaync] @@ -122,7 +122,6 @@ input_path = '~/.config/matugen/templates/zathura-colors' output_path = '~/.config/matugen/generated/zathura-colors' post_hook = 'ln -nfs $HOME/.config/matugen/generated/zathura-colors $HOME/.config/zathura/zathurarc' - # [templates.starship] # input_path = '~/.config/matugen/templates/starship-colors.toml' # output_path = '~/.config/matugen/generated/starship-colors.toml' @@ -156,7 +155,7 @@ ln -nfs $HOME/.config/matugen/generated/obsidian-theme.css $HOME/Documents/pensi input_path = '~/.config/matugen/templates/midnight-discord.css' output_path = '~/.config/matugen/generated/midnight-discord.css' post_hook = ''' -mkdir -p $HOME/~/.config/vesktop/themes/; +mkdir -p $HOME/.config/vesktop/themes/; ln -nfs $HOME/.config/matugen/generated/midnight-discord.css $HOME/.config/vesktop/themes/midnight-discord.css ''' diff --git a/user_scripts/theme_matugen/theme_ctl.sh b/user_scripts/theme_matugen/theme_ctl.sh index c7bc33d2..dface30a 100755 --- a/user_scripts/theme_matugen/theme_ctl.sh +++ b/user_scripts/theme_matugen/theme_ctl.sh @@ -39,6 +39,7 @@ readonly DEFAULT_CONTRAST="0" readonly FLOCK_TIMEOUT_SEC=30 readonly DAEMON_POLL_INTERVAL=0.1 readonly DAEMON_POLL_LIMIT=50 +readonly WAYBAR_STATE_FILE="${XDG_RUNTIME_DIR:-/tmp}/waybar_was_running" # --- STATE VARIABLES (populated by read_state) --- THEME_MODE="" @@ -79,6 +80,21 @@ check_deps() { (( ${#missing[@]} == 0 )) || die "Missing required commands: ${missing[*]}" } +# --- WAYBAR STATE --- + +detect_waybar_state() { + rm -f "$WAYBAR_STATE_FILE" + pgrep -x waybar >/dev/null 2>&1 && touch "$WAYBAR_STATE_FILE" || true +} + +restore_waybar_state() { + local autostart="${HOME}/user_scripts/waybar/waybar_autostart.sh" + if [[ -f "$WAYBAR_STATE_FILE" ]]; then + rm -f "$WAYBAR_STATE_FILE" + [[ -x "$autostart" ]] && { "$autostart" & } || true + fi +} + # --- STATE MANAGEMENT --- update_public_state() { @@ -318,6 +334,8 @@ apply_random_wallpaper() { log "Selected: ${wallpaper##*/}" + detect_waybar_state + ensure_swww_running swww img "$wallpaper" \ --transition-type grow \ @@ -325,6 +343,8 @@ apply_random_wallpaper() { --transition-fps 60 generate_colors "$wallpaper" + + restore_waybar_state } regenerate_current() { @@ -358,7 +378,9 @@ regenerate_current() { log "Current wallpaper: ${resolved_wallpaper##*/}" fi + detect_waybar_state generate_colors "$resolved_wallpaper" + restore_waybar_state } generate_colors() { diff --git a/user_scripts/waybar/waybar_autostart.sh b/user_scripts/waybar/waybar_autostart.sh index 9a7c2163..58c95920 100755 --- a/user_scripts/waybar/waybar_autostart.sh +++ b/user_scripts/waybar/waybar_autostart.sh @@ -1,97 +1,104 @@ #!/usr/bin/env bash -# ----------------------------------------------------------------------------- -# Description: Robustly restarts Waybar for Hyprland/UWSM sessions. -# Uses systemd-run to spawn from a clean user environment, -# avoiding XDG_ACTIVATION_TOKEN inheritance issues. -# Author: dusk -# ----------------------------------------------------------------------------- - set -euo pipefail -# --- Constants --- +# ------------------------------------------------------ +# Robust Waybar launcher for Hyprland / systemd +# ------------------------------------------------------ readonly APP_NAME="waybar" readonly TIMEOUT_SEC=5 -# --- Terminal-Aware Colors (stderr detection) --- +# State file written by theme_ctl.sh before Matugen runs. +# Presence means Waybar was running before the theme change. +readonly WAYBAR_STATE_FILE="${XDG_RUNTIME_DIR:-/tmp}/waybar_was_running" + +# Terminal-aware colors if [[ -t 2 ]]; then readonly C_RED=$'\033[0;31m' readonly C_GREEN=$'\033[0;32m' readonly C_BLUE=$'\033[0;34m' readonly C_RESET=$'\033[0m' else - readonly C_RED='' - readonly C_GREEN='' - readonly C_BLUE='' - readonly C_RESET='' + readonly C_RED='' C_GREEN='' C_BLUE='' C_RESET='' fi -# --- Logging Functions (Strictly to stderr) --- -# Redirecting logs to stderr keeps stdout clean for piping if needed. -log_info() { printf '%s[INFO]%s %s\n' "${C_BLUE}" "${C_RESET}" "$*" >&2; } -log_success() { printf '%s[OK]%s %s\n' "${C_GREEN}" "${C_RESET}" "$*" >&2; } -log_err() { printf '%s[ERROR]%s %s\n' "${C_RED}" "${C_RESET}" "$*" >&2; } +log_info() { printf '%s[INFO]%s %s\n' "${C_BLUE}" "${C_RESET}" "$*" >&2; } +log_success() { printf '%s[OK]%s %s\n' "${C_GREEN}" "${C_RESET}" "$*" >&2; } +log_err() { printf '%s[ERROR]%s %s\n' "${C_RED}" "${C_RESET}" "$*" >&2; } -# --- Fallback Strategy --- -# Note: As discovered, this method may not cure the "workspace inheritance" -# bug, but it ensures Waybar launches if systemd is broken. -launch_fallback() { - log_info "Attempting fallback launch (setsid)..." - ( - unset XDG_ACTIVATION_TOKEN DESKTOP_STARTUP_ID - setsid "${APP_NAME}" "$@" /dev/null 2>&1 & - ) - log_success "${APP_NAME} launched (fallback mode)." -} +# ============================================================ +# STATE FILE GUARD +# When called with "theme-change", respect the state file: +# - State file present → Waybar was running → proceed to launch +# - State file absent → Waybar was hidden → exit cleanly +# When called without "theme-change" (e.g. from a keybind or +# session startup), always proceed regardless. +# ============================================================ +if [[ "${1:-}" == "theme-change" ]]; then + if [[ ! -f "$WAYBAR_STATE_FILE" ]]; then + log_info "theme-change mode: Waybar was hidden before theme change, skipping launch." + exit 0 + fi + log_info "theme-change mode: Waybar was running before theme change, proceeding." + rm -f "$WAYBAR_STATE_FILE" + shift +fi -# --- Preflight Checks --- -(( EUID != 0 )) || { log_err "This script must NOT be run as root."; exit 1; } -command -v "${APP_NAME}" >/dev/null 2>&1 || { log_err "${APP_NAME} binary not found."; exit 1; } -[[ -d ${XDG_RUNTIME_DIR:-} ]] || { log_err "XDG_RUNTIME_DIR is not set or invalid."; exit 1; } +# ============================================================ +# PREFLIGHT +# ============================================================ +(( EUID != 0 )) || { log_err "Do NOT run as root"; exit 1; } +command -v "${APP_NAME}" >/dev/null 2>&1 || { log_err "${APP_NAME} not found"; exit 1; } +[[ -d ${XDG_RUNTIME_DIR:-} ]] || { log_err "XDG_RUNTIME_DIR invalid"; exit 1; } readonly LOCK_FILE="${XDG_RUNTIME_DIR}/${APP_NAME}_manager.lock" - -# --- Concurrency Lock --- -# FD 9 is used to hold the lock until the script exits. exec 9>"${LOCK_FILE}" -flock -n 9 || { log_err "Another instance is running. Exiting."; exit 1; } +flock -n 9 || { log_err "Another instance running"; exit 1; } -# --- Process Management --- +# ============================================================ +# MANAGE EXISTING INSTANCES +# ============================================================ log_info "Managing ${APP_NAME} instances..." if pgrep -x "${APP_NAME}" >/dev/null 2>&1; then log_info "Stopping existing instances..." pkill -x "${APP_NAME}" >/dev/null 2>&1 || true - # Poll for termination (Bash C-style loop) - for (( i = 0; i < TIMEOUT_SEC * 10; i++ )); do + for (( i=0; i < TIMEOUT_SEC*10; i++ )); do pgrep -x "${APP_NAME}" >/dev/null 2>&1 || break sleep 0.1 done - # Force kill if still resistant if pgrep -x "${APP_NAME}" >/dev/null 2>&1; then - log_err "Process hung. Sending SIGKILL..." + log_err "Hung process, sending SIGKILL..." pkill -9 -x "${APP_NAME}" >/dev/null 2>&1 || true sleep 0.2 fi + log_success "Cleanup complete." else log_info "No running instance found." fi -# --- Launch Sequence --- +# ============================================================ +# LAUNCH +# ============================================================ +launch_fallback() { + log_info "Attempting fallback launch (setsid)..." + ( + unset XDG_ACTIVATION_TOKEN DESKTOP_STARTUP_ID + setsid "${APP_NAME}" "$@" /dev/null 2>&1 & + ) + log_success "${APP_NAME} launched (fallback mode)." +} + log_info "Starting ${APP_NAME}..." if command -v systemd-run >/dev/null 2>&1; then - # Optimization: Use Bash 5.0+ $EPOCHSECONDS instead of forking $(date) - # Security: Add $$ (PID) to unit name to prevent collision on rapid re-runs unit_name="${APP_NAME}-mgr-${EPOCHSECONDS}-$$" - - # '--' separates options from the command to prevent flag injection if systemd-run --user --quiet --unit="${unit_name}" -- "${APP_NAME}" "$@" >/dev/null 2>&1; then log_success "${APP_NAME} launched via systemd unit: ${unit_name}" else - log_err "systemd-run failed; attempting fallback." + log_err "systemd-run failed; trying fallback..." launch_fallback "$@" fi else