Icon Theme Manager: Gestor Avanzado de Cachés de Iconos con YAD y Autenticación Única

Icon Theme Manager: Gestor Avanzado de Cachés de Iconos con YAD y Autenticación Única


Icon Theme Manager: Gestor Avanzado de Cachés de Iconos con YAD y Autenticación Única

Una herramienta técnica en Bash para gestionar, detectar y actualizar temas de iconos de forma eficiente en distribuciones Linux basadas en Debian y otras.


Introducción Técnica

Uno de los problemas más comunes al instalar o modificar temas de iconos en Linux es la necesidad de actualizar manualmente los cachés con gtk-update-icon-cache. Esto se vuelve especialmente tedioso cuando se tienen temas tanto en /usr/share/icons como en ~/.local/share/icons, ya que requiere permisos de root en el primer caso.

Además, herramientas como Zenity presentan limitaciones importantes en el manejo de progreso y ejecución con privilegios. Por esta razón, desarrollé Icon Theme Manager, una solución completa que utiliza YAD (Yet Another Dialog) con estilos CSS modernos y un sistema inteligente de ejecución con una sola petición de contraseña.

Características Técnicas Principales

  • Reemplazo completo de Zenity por YAD con estilos CSS personalizados (tema oscuro moderno).
  • Autenticación única con pkexec: se solicita la contraseña solo una vez aunque se actualicen decenas de temas.
  • Detección inteligente de temas válidos mediante la presencia de index.theme.
  • Escaneo dual: temas del sistema (/usr/share/icons) y del usuario (~/.local/share/icons).
  • Detección automática de distribución, entorno de escritorio y esquema de colores.
  • Barra de progreso en tiempo real con información detallada.
  • Interfaz moderna con CSS inline y mejor experiencia de usuario.
  • Gestión segura de scripts temporales para ejecución privilegiada.

Aspectos Técnicos Destacados

1. Sistema de Autenticación Única

El mayor avance técnico de esta versión es el uso de un helper script temporal generado dinámicamente:

#!/bin/bash
THEMES=("$@")
for i in "${!THEMES[@]}"; do
    THEME="${THEMES[$i]}"
    NAME=$(basename "$THEME")
    PROGRESS=$(( (i + 1) * 100 / TOTAL ))
    echo "# Actualizando ($((i+1))/$TOTAL): $NAME"
    echo "$PROGRESS"
    gtk-update-icon-cache -f -t "$THEME" &>/dev/null
done

2. Interfaz Moderna con YAD + CSS

Se implementó un estilo oscuro moderno directamente en la variable YAD_CSS, mejorando significativamente la experiencia visual respecto a Zenity.

3. Detección Inteligente

El script detecta automáticamente:

  • Distribución mediante /etc/os-release
  • Entorno de escritorio ($XDG_CURRENT_DESKTOP)
  • Tema actual de iconos mediante gsettings
  • Temas válidos filtrando solo carpetas que contienen index.theme

Instalación

La instalación es muy sencilla:

sudo nano /usr/local/bin/icon-theme-manager
# Pegar el script completo
#!/usr/bin/env bash
# ================================================
# Icon Theme Manager - Interfaz Moderna & 1 Pwd
# Usa YAD con CSS + Helper Script para pkexec único
# ================================================

APP_NAME="Icon Theme Manager"
APP_VERSION="3.0"
LOG_FILE="/tmp/icon-theme-manager.log"

# ================================================
# Configuración de Estilos CSS (Modern Dark Theme)
# ================================================
YAD_CSS="window { background-color: #1e1e1e; color: #e2e8f0; border-radius: 12px; border: 1px solid #3e3e3e; }
          entry { background-color: #2d2d2d; border-radius: 6px; border: 1px solid #4a5568; }
          text { background-color: transparent; color: #e2e8f0; }
          button { background-color: #3b82f6; color: white; border-radius: 6px; border: none; padding: 8px 16px; font-weight: bold; box-shadow: 0 2px 4px rgba(0,0,0,0.3); transition: background 0.2s; }
          button:hover { background-color: #60a5fa; }
          list { border: 1px solid #3e3e3e; }
          progress { text-shadow: none; color: #e2e8f0; font-weight: bold; }
          * { font-family: 'Segoe UI', 'Roboto', 'Helvetica', sans-serif; font-size: 11pt; }"

# ================================================
# Funciones de Mensajería (YAD)
# ================================================

show_msg() {
    local type="$1"
    local text="$2"
    case "$type" in
        "info") yad --info --title="$APP_NAME" --text="$text" --width=500 --height=200 --css="$YAD_CSS" --button=gtk-ok:0 2>/dev/null ;;
        "error") yad --error --title="$APP_NAME" --text="$text" --width=500 --height=200 --css="$YAD_CSS" --button=gtk-close:0 2>/dev/null ;;
        "question") yad --question --title="$APP_NAME" --text="$text" --width=500 --height=180 --css="$YAD_CSS" --button=gtk-yes:0 --button=gtk-no:1 ;;
    esac
}

# ================================================
# Dependencias
# ================================================

check_dependencies() {
    local missing=()
    command -v yad >/dev/null || missing+=("yad")
    command -v gtk-update-icon-cache >/dev/null || missing+=("gtk-update-icon-cache")

    if [[ ${#missing[@]} -gt 0 ]]; then
        if show_msg "question" "Faltan dependencias: ${missing[*]}\n\n¿Instalarlas ahora?"; then
            if command -v apt-get >/dev/null; then
                pkexec apt-get update && pkexec apt-get install -y yad libgtk-3-bin
            elif command -v dnf >/dev/null; then
                pkexec dnf install -y yad gtk3
            fi
        else
            exit 1
        fi
    fi
}

# ================================================
# Lógica de Escaneo de Iconos
# ================================================

scan_icon_themes() {
    local themes=()

    # Escanear sistema
    if [[ -d "/usr/share/icons" ]]; then
        for dir in /usr/share/icons/*/; do
            [[ -f "${dir}index.theme" ]] && themes+=("/usr/share/icons/$(basename "${dir%/}")")
        done
    fi

    # Escanear usuario
    if [[ -d "$HOME/.local/share/icons" ]]; then
        for dir in "$HOME/.local/share/icons/"*/; do
            [[ -f "${dir}index.theme" ]] && themes+=("$HOME/.local/share/icons/$(basename "${dir%/}")")
        done
    fi

    printf '%s\n' "${themes[@]}"
}

# ================================================
# ACTUALIZACIÓN CON UNA SOLA CONTRASEÑA
# ================================================

update_all_caches() {
    local themes=()
    mapfile -t themes < <(scan_icon_themes)
    local total=${#themes[@]}

    if [[ $total -eq 0 ]]; then
        show_msg "error" "No se encontraron temas de iconos válidos (sin index.theme)."
        return
    fi

    if ! show_msg "question" "Se actualizarán $total temas.\n\nSe requiere contraseña de administrador UNA sola vez.\n\n¿Continuar?"; then
        return
    fi

    # Crear archivo de script auxiliar para ejecutar como root una sola vez
    local helper_script="/tmp/icon-theme-helper-$$"
    local pipe_output="/tmp/icon-theme-pipe-$$"

    rm -f "$helper_script" "$pipe_output"
    mkfifo "$pipe_output" # Crear pipe para el progreso en tiempo real

    # Generar el script auxiliar con los temas como argumentos
    cat > "$helper_script" </dev/null 2>&1; then
        echo "[ERROR] Fallo en \$NAME" >&2
    fi
done

echo "# ¡Actualización Completada!"
echo "100"
sleep 1 # Mantener el pipe abierto un poco
EOF

    chmod +x "$helper_script"

    # Ejecutar el helper script con pkexec (una sola vez) y enviar output al pipe
    # Esto pedirá la contraseña UNA vez y luego actualizará todos los temas
    pkexec "$helper_script" "${themes[@]}" > "$pipe_output" &
    local pk_pid=$!

    # Leer el pipe y mostrar progreso en YAD
    cat "$pipe_output" | yad --progress \
        --title="Actualizando Iconos..." \
        --text="Iniciando proceso de actualización..." \
        --width=550 --height=180 \
        --percentage=0 \
        --auto-close \
        --css="$YAD_CSS" \
        --button=gtk-cancel:1 &

    local yad_pid=$!

    # Limpiar cuando YAD se cierre
    while kill -0 $yad_pid 2>/dev/null; do
        sleep 0.5
        # Si el proceso pkexec muere, cerrar YAD
        if ! kill -0 $pk_pid 2>/dev/null; then
            kill $yad_pid 2>/dev/null
        fi
    done

    # Limpieza
    wait $pk_pid 2>/dev/null
    rm -f "$helper_script" "$pipe_output"

    show_msg "info" "Se actualizaron $total temas de iconos correctamente."
}

# ================================================
# Menú Principal
# ================================================

main_menu() {
    local choice
    choice=$(yad --list --title="$APP_NAME" \
        --text="Selecciona una acción:" \
        --column="Acción" --column="Descripción" \
        --width=700 --height=500 --center \
        --no-headers --hide-column=1 \
        --css="$YAD_CSS" \
        "update_all" "🔄  Actualizar TODOS los Cachés (1 contraseña)" \
        "list"       "🎨  Listar Temas Instalados" \
        "detect"     "🖥️  Detectar Info del Sistema" \
        "open_sys"   "📁  Abrir /usr/share/icons" \
        "open_usr"   "📁  Abrir ~/.local/share/icons" \
        "about"      "ℹ️   Acerca de" \
        --button="Ejecutar:0" --button="Salir:1" 2>/dev/null | awk -F'|' '{print $1}')

    case "$choice" in
        "update_all") update_all_caches ;;
        "list")
            yad --list --title="Temas Detectados" \
                --column="Ubicación" --column="Nombre del Tema" --column="Ruta Absoluta" \
                --width=900 --height=550 --css="$YAD_CSS" \
                $(scan_icon_themes | sed 's|/usr/share/icons|SYSTEM|;s|'$HOME'/\.local/share/icons|USER|' | awk '{print $1, substr($2, index($2,"/")+1), $2}') \
                --button=Cerrar:0
            ;;
        "detect")
            local distro=$(grep PRETTY_NAME /etc/os-release | cut -d= -f2 | tr -d '"')
            local theme="N/A"
            [[ -n "$XDG_CURRENT_DESKTOP" ]] && theme=$(gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | tr -d "'")
            show_msg "info" "Distribución: $distro\n\nTemas de Iconos Actuales: $theme"
            ;;
        "open_sys") xdg-open /usr/share/icons 2>/dev/null ;;
        "open_usr") mkdir -p "$HOME/.local/share/icons" && xdg-open "$HOME/.local/share/icons" 2>/dev/null ;;
        "about") show_msg "info" "$APP_NAME v$APP_VERSION\n\nDiseño modernizado con CSS YAD.\nActualización de iconos con una sola petición de contraseña." ;;
        "exit"|"") exit 0 ;;
    esac

    main_menu
}

# ================================================
# Inicio
# ================================================

main() {
    check_dependencies
    main_menu
}

main "$@"

sudo chmod +x /usr/local/bin/icon-theme-manager

Uso

Una vez instalado, puedes ejecutarlo desde terminal con:

icon-theme-manager

O desde el menú de aplicaciones. La opción más útil es "Actualizar TODOS los Cachés", que actualizará todos los temas detectados con una sola autenticación.

Mejoras respecto a versiones anteriores

Aspecto Versión anterior (Zenity) Versión 3.0 (YAD)
Estabilidad de progreso Limitada Excelente
Solicitudes de contraseña Múltiples Única
Apariencia Básica Moderna con CSS
Detección de temas Simple Inteligente (index.theme)

Publicado por: [FedericoRaika] | Categoría: Linux • Bash Scripting • Herramientas

🏷️ Etiquetas:

Compartir: 𝕏 Twitter Facebook LinkedIn

💬 Comentarios ()