#!/bin/sh
# hintergrund.sh – Kärntner Linuxtåg 2026 (Carinthian Linux Day, Fr 30.10.2026, Villach)
# Lebendiger Hintergrund für Linux – BETA (bisher nur auf nachgestellten Desktops getestet)
#
#   curl -fsSL https://carinthianlinuxday.at/hintergrund.sh | sh                     Motiv „Gitterraum“
#   curl -fsSL https://carinthianlinuxday.at/hintergrund.sh | sh -s -- horizont       anderes Motiv
#   curl -fsSL https://carinthianlinuxday.at/hintergrund.sh | sh -s -- --entfernen    wieder entfernen
#   sh hintergrund.sh [MOTIV] [--statisch] [--entfernen] [--status] [--hilfe] …       gespeichert
#
# Motive: gitterraum (Standard), horizont, haelfte („Hålbe Woahrheit“), minimal, terminal – dieselben wie auf
# https://carinthianlinuxday.at/Veranstaltungen/CLD26/hintergrundbilder.html
#
# Was passiert:
#   1. Das Paket des gewählten Motivs wird über HTTPS geladen (curl oder wget) und gegen die SHA-256-Summe geprüft,
#      die unten in diesem Skript steht. Stimmt sie nicht, bricht das Skript ab, ohne etwas zu verändern.
#   2. Der Desktop wird über XDG_CURRENT_DESKTOP erkannt (oder mit --desktop=… vorgegeben):
#        KDE Plasma 6/5           Hintergrund-Plugin: das Motiv, der Drahtgitter-Tux dreht sich
#                                 (hält an bei maximierten Fenstern, im Akkubetrieb und ohne Grafikkarte)
#        GNOME, Budgie, Cinnamon, 12 Tageszeit-Bilder, zwischen denen der Desktop selbst überblendet
#        MATE, Xfce               (Xfce: wechselt alle 2 Stunden ohne Überblendung)
#        LXDE (auch Raspberry Pi  das Motiv als ruhendes Bild (PNG in Bildschirmgröße; ohne rsvg-convert/Inkscape/
#        OS), LXQt               ImageMagick das nächstliegende fertige Bild aus dem Paket)
#        sway, Hyprland, i3 …     Bilder werden abgelegt, dazu eine Anleitung – an der Einstellung ändert sich nichts
#      Bildschirmgröße: Das Skript misst den Bildschirm (kscreen-doctor, Mutter über D-Bus, swaymsg, hyprctl, wlr-randr,
#      xrandr, sonst /sys/class/drm; mit --groesse=BxH vorgebbar) und setzt das Motiv genau dafür zusammen – mit
#      denselben Zuschnitt-Regeln wie der PNG-Download der Website. KDE setzt es im Plugin selbst für jede Form zusammen.
#   3. Der bisherige Hintergrund wird gemerkt; --entfernen stellt ihn wieder her und prüft das, bevor es löscht.
#      Hast du inzwischen selbst einen anderen Hintergrund gewählt, bleibt der unangetastet.
#
# Kein sudo: Es wird nur unter deinem Home-Verzeichnis geschrieben ($XDG_DATA_HOME, $XDG_STATE_HOME, $XDG_CONFIG_HOME
# bzw. ~/.local/share, ~/.local/state, ~/.config). Alles steckt in Funktionen; erst die letzte Zeile startet das
# Skript, und zwar in geschweiften Klammern – fehlt auch nur ein Byte am Ende, ist das ein Syntaxfehler und es
# läuft gar nichts.
#
# Nur zum Testen: LINUXTAG_HINTERGRUND_BASIS=URL lädt die Pakete von einer anderen Adresse (https://…, oder
# http:// nur für 127.0.0.1/localhost). Die Prüfsummen gelten trotzdem.
#
# Quelle: tools/hintergrund/linux/hintergrund.sh im Repository der Website; gebaut (Prüfsummen eingesetzt) von
# tools/hintergrund-linux-bauen.mjs. License: GPL-2.0-or-later. Bilder: CC BY-SA 4.0 (siehe LICENSE im Paket).

# >>> vom Bauskript eingesetzt (tools/hintergrund-linux-bauen.mjs) >>>
lt_pakete() {   # $1 = Motiv → LT_DATEI, LT_SUMME; LT_VERSION
    LT_VERSION=0.9.2
    case $1 in
        gitterraum) LT_DATEI=linuxtag-2026-gitterraum-0.9.2.tar.gz LT_SUMME=b827b55dcbe774ef11b02992a03787662ddeea0c5de6cac2597f9855f5d7d335 ;;
        horizont) LT_DATEI=linuxtag-2026-horizont-0.9.2.tar.gz LT_SUMME=5059ed22d0471d6a56eacd51c5c4213e028b310b222c7d4e360d23381dea5982 ;;
        haelfte) LT_DATEI=linuxtag-2026-haelfte-0.9.2.tar.gz LT_SUMME=2fbde3a3e5c43aecc25fe3c96f1efbb566e01fdedcc3628028fc456a96cb2dc7 ;;
        minimal) LT_DATEI=linuxtag-2026-minimal-0.9.2.tar.gz LT_SUMME=350b23650d225c61f62a9ae88c8ee2c49660fece5c80ffb3308b75194ce59a1c ;;
        terminal) LT_DATEI=linuxtag-2026-terminal-0.9.2.tar.gz LT_SUMME=c508a30a7807dde5e6396c2f508ac0621dd40fb086fe0fa57cca3672ba5b96c4 ;;
        *) return 1 ;;
    esac
    return 0
}
# <<< vom Bauskript eingesetzt <<<

# ---------------------------------------------------------------------------------------------------- Grundlagen
lt_grundwerte() {
    LT_KENNUNG=linuxtag-hintergrund
    LT_TITEL='Kärntner Linuxtåg 2026'
    LT_BASIS_STANDARD=https://carinthianlinuxday.at/hintergrund/
    LT_MOTIVE='gitterraum horizont haelfte minimal terminal'
    LT_KDE_ID=at.linuxtog.kv26
    LT_TAB=$(printf '\t')
    LT_TMP=
    LT_STANDARD_B=3840          # Bildschirmgröße, wenn nichts erkannt wird
    LT_STANDARD_H=2160
    LT_UEBERBLENDUNG=3600       # Sekunden Überblendung am Ende jeder Phase (GNOME/Cinnamon/MATE)

    # XDG-Ordner (laut Spezifikation nur absolute Pfade, sonst Standard). HOME prüft main – für --hilfe und
    # --version darf es fehlen.
    case ${XDG_DATA_HOME:-} in /*) LT_DATA_HOME=$XDG_DATA_HOME ;; *) LT_DATA_HOME=${HOME:-}/.local/share ;; esac
    case ${XDG_STATE_HOME:-} in /*) LT_STATE_HOME=$XDG_STATE_HOME ;; *) LT_STATE_HOME=${HOME:-}/.local/state ;; esac
    case ${XDG_CONFIG_HOME:-} in /*) LT_CONFIG_HOME=$XDG_CONFIG_HOME ;; *) LT_CONFIG_HOME=${HOME:-}/.config ;; esac

    LT_DATEN=$LT_DATA_HOME/$LT_KENNUNG                    # Bilder, je Motiv ein Unterordner
    LT_ZUSTAND=$LT_STATE_HOME/$LT_KENNUNG                 # vorher.txt + installiert.txt
    LT_VORHER=$LT_ZUSTAND/vorher.txt                      # Einstellungen VOR dem ersten Linuxtåg-Hintergrund
    LT_INSTALLIERT=$LT_ZUSTAND/installiert.txt            # was gerade eingerichtet ist
    LT_PROPS=$LT_DATA_HOME/gnome-background-properties/$LT_KENNUNG.xml
    LT_KDE_ZIEL=$LT_DATA_HOME/plasma/wallpapers/$LT_KDE_ID
    LT_DRM=${LINUXTAG_DRM_DIR:-/sys/class/drm}            # nur zum Testen überschreibbar
}

lt_sag()    { printf '%s\n' "$*"; }
lt_info()   { printf '  • %s\n' "$*"; }
lt_warn()   { printf 'Achtung: %s\n' "$*" >&2; }
lt_fehler() { printf 'Fehler: %s\n' "$*" >&2; }
lt_hat()    { command -v "$1" >/dev/null 2>&1; }

# Wert für die Shell in einfache Anführungszeichen setzen (' → '\'') – für Befehle, die wir zum Kopieren ausgeben
lt_zitat()  { printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"; }

# Zeile aus vorher.txt in Felder zerlegen (Tabulator). Nicht mit IFS=Tab + read: Ein Tabulator zählt dort als
# Leerraum, mehrere hintereinander werden zu einem – ein leeres Feld würde verschluckt.
# shellcheck disable=SC2034 # lt_feld wird per eval gelesen
lt_felder() {   # Zeile → LT_F1 … LT_F5
    lt_rest=$1
    for lt_nr in 1 2 3 4 5; do
        case $lt_rest in
            *"$LT_TAB"*) lt_feld=${lt_rest%%"$LT_TAB"*}; lt_rest=${lt_rest#*"$LT_TAB"} ;;
            *)           lt_feld=$lt_rest; lt_rest= ;;
        esac
        eval "LT_F$lt_nr=\$lt_feld"
    done
}

lt_aufraeumen() {
    if [ -n "${LT_TMP:-}" ] && [ -d "$LT_TMP" ]; then
        rm -rf "$LT_TMP"
    fi
    LT_TMP=
    # abgebrochen mitten im Ablegen der Bilder: Nebenordner weg; fehlt der Motiv-Ordner, den alten zurück
    if [ -n "${LT_NEU_ORDNER:-}" ]; then
        rm -rf "$LT_NEU_ORDNER"
        if [ -n "${LT_ALT_ORDNER:-}" ] && [ -d "$LT_ALT_ORDNER" ] && [ ! -e "$LT_ZIEL" ]; then
            mv "$LT_ALT_ORDNER" "$LT_ZIEL"
        fi
        LT_NEU_ORDNER=
    fi
}

# Ende mit Code (räumt den temporären Ordner auf)
lt_ende() {
    lt_aufraeumen
    exit "$1"
}

lt_hilfe() {
    cat <<EOF
$LT_TITEL – lebendiger Hintergrund für Linux (BETA, Version $LT_VERSION)

Aufruf:   curl -fsSL https://carinthianlinuxday.at/hintergrund.sh | sh -s -- [MOTIV] [OPTION …]
          sh hintergrund.sh [MOTIV] [OPTION …]

Motive:   gitterraum (Standard), horizont, haelfte („Hålbe Woahrheit“), minimal, terminal
          Ein anderes Motiv ersetzt das bisherige; dein ursprünglicher Hintergrund bleibt gemerkt.

  --motiv=NAME       Motiv (wie oben, statt des Worts ohne Strich)
  --statisch         ruhendes Bild statt Bewegung (KDE: Drahtgitter steht still; GNOME & Co.: ein Bild statt
                     Tageszeit-Diashow)
  --bewegt           KDE: Drehung auch einschalten, wenn keine Grafikkarte erkannt wird
  --groesse=BxH      Bildschirmgröße in Pixeln vorgeben statt erkennen (64 … 16384, z. B. --groesse=2560x1440).
                     Das Motiv wird genau für diese Größe zusammengesetzt (KDE macht das selbst).
  --hochformat       erkannte Größe hochkant bzw. quer verwenden (z. B. wenn der Bildschirm gedreht ist, das
  --querformat       aber nicht erkannt wird)
  --entfernen        Linuxtåg-Hintergrund entfernen, vorherigen Hintergrund wiederherstellen
  --status           anzeigen, was eingerichtet ist (verändert nichts)
  --desktop=NAME     Desktop vorgeben statt erkennen:
                     kde, gnome, cinnamon, mate, xfce, lxde, lxqt, andere
  --plasma=5|6       KDE: Plasma-Version vorgeben
  --hilfe            diese Hilfe          --version   Version anzeigen

Rückgabewerte: 0 fertig · 1 Fehler, nichts verändert · 2 falscher Aufruf · 3 Desktop nicht erkannt ·
               4 nur teilweise geklappt (Meldungen oben beachten)

Neuer Bildschirm oder gedreht? Einfach denselben Befehl noch einmal ausführen – das Motiv wird neu zusammengesetzt.
EOF
    [ -n "${HOME:-}" ] && printf 'Dateien: %s, Merkliste: %s\n' "$LT_DATEN" "$LT_ZUSTAND"
    return 0
}

# ---------------------------------------------------------------------------------------------------- Argumente
lt_argumente() {
    LT_MODUS=einrichten
    LT_MOTIV=
    LT_STATISCH=0
    LT_BEWEGT=0
    LT_DESKTOP_VORGABE=
    LT_PLASMA_VORGABE=
    LT_FORMAT_VORGABE=
    LT_GROESSE_VORGABE=
    lt_nur_motive=0
    for lt_arg in "$@"; do
        if [ "$lt_nur_motive" = 1 ]; then
            lt_motiv_setzen "$lt_arg" || return 2
            continue
        fi
        case $lt_arg in
            --)                          lt_nur_motive=1 ;;      # Ende der Optionen
            --entfernen|--remove)        lt_modus_setzen entfernen "$lt_arg" || return 2 ;;
            --status)                    lt_modus_setzen status "$lt_arg" || return 2 ;;
            --hilfe|--help|-h)           lt_modus_setzen hilfe "$lt_arg" || return 2 ;;
            --version|-V)                lt_modus_setzen version "$lt_arg" || return 2 ;;
            --statisch)                  LT_STATISCH=1 ;;
            --bewegt)                    LT_BEWEGT=1 ;;
            --hochformat|--querformat)
                lt_f=${lt_arg#--}
                lt_f=${lt_f%format}
                if [ -n "$LT_FORMAT_VORGABE" ] && [ "$LT_FORMAT_VORGABE" != "$lt_f" ]; then
                    lt_fehler "--hochformat und --querformat schließen sich aus"
                    return 2
                fi
                LT_FORMAT_VORGABE=$lt_f ;;
            --motiv=?*)                  lt_motiv_setzen "${lt_arg#*=}" || return 2 ;;
            --desktop=?*)
                lt_v=$(printf '%s' "${lt_arg#*=}" | tr '[:upper:]' '[:lower:]')
                lt_einmal "$LT_DESKTOP_VORGABE" "$lt_v" --desktop || return 2
                LT_DESKTOP_VORGABE=$lt_v ;;
            --plasma=?*)
                lt_einmal "$LT_PLASMA_VORGABE" "${lt_arg#*=}" --plasma || return 2
                LT_PLASMA_VORGABE=${lt_arg#*=} ;;
            --groesse=?*|--größe=?*|--grösse=?*)
                lt_einmal "$LT_GROESSE_VORGABE" "${lt_arg#*=}" --groesse || return 2
                LT_GROESSE_VORGABE=${lt_arg#*=} ;;
            --desktop=|--plasma=|--motiv=|--groesse=|--größe=|--grösse=)
                lt_fehler "$lt_arg braucht einen Wert (Hilfe: --hilfe)"
                return 2 ;;
            -*)                          lt_fehler "unbekannte Option: $lt_arg (Hilfe: --hilfe)"; return 2 ;;
            *)                           lt_motiv_setzen "$lt_arg" || return 2 ;;
        esac
    done
    if [ -n "$LT_DESKTOP_VORGABE" ]; then
        case $LT_DESKTOP_VORGABE in
            kde|gnome|cinnamon|mate|xfce|lxde|lxqt) ;;
            andere|anleitung) LT_DESKTOP_VORGABE=anleitung ;;
            *) lt_fehler "--desktop=$LT_DESKTOP_VORGABE kenne ich nicht (kde, gnome, cinnamon, mate, xfce, lxde, lxqt, andere)"
               return 2 ;;
        esac
    fi
    case $LT_PLASMA_VORGABE in
        ''|5|6) ;;
        *) lt_fehler "--plasma= braucht 5 oder 6"; return 2 ;;
    esac
    if [ "$LT_STATISCH" = 1 ] && [ "$LT_BEWEGT" = 1 ]; then
        lt_fehler "--statisch und --bewegt schließen sich aus"
        return 2
    fi
    if [ -n "$LT_GROESSE_VORGABE" ]; then
        # B×H mit x oder ×, je 64 … 16384 (wie die Download-Seite)
        lt_g=$(printf '%s' "$LT_GROESSE_VORGABE" | sed 's/×/x/; s/X/x/')
        lt_gb=${lt_g%%x*}
        lt_gh=${lt_g#*x}
        case $lt_gb:$lt_gh in
            *[!0-9:]*|:*|*:|0*|*:0*) lt_gb=0 ;;
        esac
        if [ "${#lt_gb}" -gt 5 ] || [ "${#lt_gh}" -gt 5 ] || [ "$lt_gb" -lt 64 ] || [ "$lt_gb" -gt 16384 ] ||
           [ "$lt_gh" -lt 64 ] || [ "$lt_gh" -gt 16384 ]; then
            lt_fehler "--groesse=$LT_GROESSE_VORGABE: bitte Breite x Höhe in Pixeln, je 64 bis 16384 (z. B. --groesse=2560x1440)"
            return 2
        fi
        if [ -n "$LT_FORMAT_VORGABE" ]; then
            lt_fehler "--groesse und --${LT_FORMAT_VORGABE}format schließen sich aus (die Größe legt das Format schon fest)"
            return 2
        fi
        LT_GROESSE_VORGABE=${lt_gb}x$lt_gh
    fi
    return 0
}

# Option nur einmal – oder zweimal mit demselben Wert
lt_einmal() {   # bisher neu Option
    if [ -n "$1" ] && [ "$1" != "$2" ]; then
        lt_fehler "$3 zweimal mit verschiedenen Werten ($1, $2)"
        return 2
    fi
    return 0
}

lt_modus_setzen() {   # Modus Option
    if [ "$LT_MODUS" != einrichten ] && [ "$LT_MODUS" != "$1" ]; then
        lt_fehler "bitte nur eine Aufgabe angeben: $2 passt nicht zu --$LT_MODUS"
        return 2
    fi
    LT_MODUS=$1
}

lt_motiv_setzen() {
    # tr arbeitet byteweise: Ä/Å bleiben groß – deshalb stehen unten beide Schreibweisen
    lt_m=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')
    case $lt_m in
        hälfte|hÄlfte|halbe|hålbe|hÅlbe|haelfte) lt_m=haelfte ;;
    esac
    # nur Kleinbuchstaben a–z – sonst passte z. B. „gitterraum horizont“ (ein Argument) unten als Teil der Liste
    case $lt_m in
        ''|*[!abcdefghijklmnopqrstuvwxyz]*) lt_m=- ;;
    esac
    case " $LT_MOTIVE " in
        *" $lt_m "*) ;;
        *) lt_fehler "Motiv „$1“ gibt es nicht. Zur Wahl: gitterraum, horizont, haelfte, minimal, terminal"
           return 2 ;;
    esac
    if [ -n "$LT_MOTIV" ] && [ "$LT_MOTIV" != "$lt_m" ]; then
        lt_fehler "bitte nur ein Motiv angeben ($LT_MOTIV oder $lt_m)"
        return 2
    fi
    LT_MOTIV=$lt_m
    return 0
}

# ---------------------------------------------------------------------------------------------------- Desktop
# Ein Eintrag aus XDG_CURRENT_DESKTOP (klein geschrieben) → Familie
lt_desktop_eintrag() {
    case $1 in
        kde|plasma|plasmawayland|plasmax11)                     echo kde ;;
        x-cinnamon|cinnamon|cinnamon-wayland)                  echo cinnamon ;;
        mate)                                                   echo mate ;;
        xfce|xfce4|xfce-*)                                      echo xfce ;;
        lxqt)                                                   echo lxqt ;;
        lxde|lxde-*)                                            echo lxde ;;
        gnome|gnome-*|ubuntu|ubuntu-*|unity|budgie|budgie-*|pantheon|pop|zorin) echo gnome ;;
        sway|hyprland|wayfire|river|labwc|niri|i3|bspwm|cosmic|enlightenment|openbox|awesome|qtile|dwm|xmonad|herbstluftwm|icewm|fluxbox|deepin|dde|wlroots|hikari|weston|miracle-wm|gamescope)
                                                                echo anleitung ;;
        *)                                                      echo '' ;;
    esac
}

lt_desktop_erkennen() {
    LT_DESKTOP=
    LT_DESKTOP_NAME=${XDG_CURRENT_DESKTOP:-${DESKTOP_SESSION:-}}
    if [ -n "$LT_DESKTOP_VORGABE" ]; then
        LT_DESKTOP=$LT_DESKTOP_VORGABE
        LT_DESKTOP_NAME="$LT_DESKTOP_VORGABE (vorgegeben)"
        return 0
    fi
    # XDG_CURRENT_DESKTOP zuerst (Liste mit Doppelpunkten, erster bekannter Eintrag gewinnt), sonst DESKTOP_SESSION
    for lt_quelle in "${XDG_CURRENT_DESKTOP:-}" "${DESKTOP_SESSION:-}"; do
        [ -n "$lt_quelle" ] || continue
        lt_alt_ifs=$IFS
        IFS=:
        # shellcheck disable=SC2086 # Aufteilen an Doppelpunkten ist gewollt
        set -- $lt_quelle
        IFS=$lt_alt_ifs
        for lt_e in "$@"; do
            lt_f=$(lt_desktop_eintrag "$(printf '%s' "$lt_e" | tr '[:upper:]' '[:lower:]')")
            if [ -n "$lt_f" ]; then
                LT_DESKTOP=$lt_f
                return 0
            fi
        done
        # nur DESKTOP_SESSION prüfen, wenn XDG_CURRENT_DESKTOP leer ist
        [ -n "${XDG_CURRENT_DESKTOP:-}" ] && return 1
    done
    return 1
}

lt_desktop_text() {
    case $1 in
        kde) echo 'KDE Plasma' ;; gnome) echo 'GNOME (auch Budgie, Unity, Pantheon)' ;; cinnamon) echo Cinnamon ;;
        mate) echo MATE ;; xfce) echo Xfce ;; lxde) echo LXDE ;; lxqt) echo LXQt ;;
        anleitung) echo 'andere Umgebung (nur Anleitung)' ;; *) echo unbekannt ;;
    esac
}

# ---------------------------------------------------------------------------------------------------- Bildschirm
# Größe des Bildschirms in echten Pixeln (nach Drehung), für die das Motiv zusammengesetzt wird → LT_B, LT_H,
# LT_GROESSE_QUELLE (Text für die Ausgabe), LT_GROESSE_HINWEIS (mehrere Bildschirme …).
# Quellen, die beste zuerst; jede ist freiwillig – fehlt das Programm, antwortet es nicht oder kommt Unsinn, geht es
# mit der nächsten weiter:
#   kscreen-doctor -j / -o (KDE) · Mutter über D-Bus (GNOME, auch Wayland: logische Monitore mit Drehung) ·
#   swaymsg · hyprctl · wlr-randr · xrandr (X11/XWayland) · /sys/class/drm (Panel-Größe, ohne Drehung)
# Jede Quelle liefert je eingeschaltetem Bildschirm eine Zeile „B H haupt name“ (haupt = 1 beim Hauptbildschirm).
# Gewählt wird der Hauptbildschirm, sonst der größte. Unbekannt → 3840 × 2160.

# Programm mit Zeitlimit (falls „timeout“ fehlt, ohne)
lt_zeitlimit() {
    if lt_hat timeout; then timeout 5 "$@"; else "$@"; fi
}

# JSON oder GVariant-Text (gdbus) → Zeilen „Pfad<Tab>Wert“, z. B. „outputs.0.modes.2.size.width<Tab>1920“.
# Objekte/Wörterbücher: Pfadteil = Schlüssel; Listen/Tupel: Pfadteil = Nummer ab 0; <…> (Variant) und
# Typangaben (uint32, @a{sv} …) zählen nicht. Reicht für die Antworten der Bildschirm-Programme.
lt_flach() {
    LC_ALL=C awk '
        { t = t $0 " " }
        function pfad(   i, p) { p = ""; for (i = 1; i <= d; i++) p = p (i > 1 ? "." : "") (typ[i] == "o" ? k[i] : n[i]); return p }
        function wert(v) { if (d > 0 && typ[d] == "o" && erw[d]) k[d] = v; else print pfad() "\t" v }
        END {
            d = 0; L = length(t); i = 1
            while (i <= L) {
                c = substr(t, i, 1)
                if (c == "{") { d++; typ[d] = "o"; k[d] = ""; erw[d] = 1; i++; continue }
                if (c == "[" || c == "(") { d++; typ[d] = "a"; n[d] = 0; i++; continue }
                if (c == "}" || c == "]" || c == ")") { if (d > 0) d--; i++; continue }
                if (c == ",") { if (typ[d] == "a") n[d]++; else erw[d] = 1; i++; continue }
                if (c == ":") { erw[d] = 0; i++; continue }
                if (c == "\"" || c == "\047") {
                    q = c; v = ""; i++
                    while (i <= L) {
                        c = substr(t, i, 1)
                        if (c == "\\") { v = v substr(t, i + 1, 1); i += 2; continue }
                        if (c == q) break
                        v = v c; i++
                    }
                    i++; wert(v); continue
                }
                if (c ~ /[ \t<>]/) { i++; continue }
                if (c == "@") { while (i <= L && substr(t, i, 1) != " ") i++; continue }   # Typangabe @a{sv}
                v = ""
                while (i <= L) { c = substr(t, i, 1); if (c ~ /[][(){},:<> \t"\047]/) break; v = v c; i++ }
                if (v ~ /^(u?int(16|32|64)|byte|double|boolean|string|objectpath|signature|handle)$/) continue
                if (v != "") wert(v)
            }
        }'
}

lt_q_kscreen() {
    lt_hat kscreen-doctor || return 1
    lt_j=$(lt_zeitlimit kscreen-doctor -j 2>/dev/null) || lt_j=
    if [ -n "$lt_j" ]; then
        # Plasma 6: priority 1 = Hauptbildschirm; Plasma 5: primary. rotation: 1 normal, 2 links, 4 kopf, 8 rechts
        printf '%s' "$lt_j" | lt_flach | LC_ALL=C awk -F '\t' '
            $1 ~ /^outputs\.[0-9]+\./ {
                split($1, p, "."); o = p[2]; r = substr($1, length("outputs." o ".") + 1)
                if (r == "enabled") an[o] = $2; else if (r == "connected") da[o] = $2
                else if (r == "currentModeId") cur[o] = $2; else if (r == "rotation") rot[o] = $2
                else if (r == "priority") prio[o] = $2; else if (r == "primary") prim[o] = $2
                else if (r == "name") name[o] = $2
                else if (r ~ /^modes\.[0-9]+\.id$/) { split(r, q, "."); mid[o, q[2]] = $2 }
                else if (r ~ /^modes\.[0-9]+\.size\.width$/) { split(r, q, "."); mw[o, q[2]] = $2 }
                else if (r ~ /^modes\.[0-9]+\.size\.height$/) { split(r, q, "."); mh[o, q[2]] = $2 }
                alle[o] = 1
            }
            END {
                for (o in alle) {
                    if (an[o] != "true" || da[o] == "false") continue
                    w = 0; h = 0
                    for (j = 0; (o, j) in mid; j++) if (mid[o, j] == cur[o]) { w = mw[o, j]; h = mh[o, j] }
                    if (rot[o] == 2 || rot[o] == 8) { x = w; w = h; h = x }
                    print w, h, (prio[o] == 1 || prim[o] == "true") ? 1 : 0, name[o]
                }
            }'
        return 0
    fi
    # ältere Fassungen / ohne -j: Textausgabe (Farben entfernen; „Output:“ beginnt einen Bildschirm, aktueller
    # Modus mit *, „Rotation: 2|8“ = hochkant, „priority 1“ oder „primary“ = Hauptbildschirm)
    lt_esc=$(printf '\033')
    lt_zeitlimit kscreen-doctor -o 2>/dev/null | sed "s/$lt_esc\[[0-9;]*m//g" | LC_ALL=C awk '
        function aus() { if (n != "" && an && w > 0) { if (rot == 2 || rot == 8) { x = w; w = h; h = x }; print w, h, haupt, n } }
        /Output:/ { aus(); n = ""; an = 0; w = 0; h = 0; rot = 1; haupt = 0
                    for (i = 1; i <= NF; i++) if ($i == "Output:") { n = $(i + 2) } }
        { for (i = 1; i <= NF; i++) {
              if ($i == "enabled") an = 1
              if ($i == "disabled") an = 0
              if ($i == "primary") haupt = 1
              if ($i == "priority" && $(i + 1) == "1") haupt = 1
              if ($i == "Rotation:") rot = $(i + 1) + 0
              if ($i ~ /^[0-9]+:[0-9]+x[0-9]+@.*\*/) { m = $i; sub(/^[0-9]+:/, "", m); split(m, g, /[x@]/); w = g[1] + 0; h = g[2] + 0 }
          } }
        END { aus() }'
}

lt_q_mutter() {
    lt_hat gdbus || return 1
    # nur mit Sitzungsbus (ohne versucht GLib einen zu starten und legt dabei ~/.cache an)
    [ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ] || [ -S "${XDG_RUNTIME_DIR:-/nonexistent}/bus" ] || return 1
    lt_j=$(lt_zeitlimit gdbus call --session --dest org.gnome.Mutter.DisplayConfig --object-path /org/gnome/Mutter/DisplayConfig \
        --method org.gnome.Mutter.DisplayConfig.GetCurrentState 2>/dev/null) || return 1
    # (serial, Monitore [((Anschluss …), [(Modus, B, H, …, {is-current})], …)], logische Monitore
    #  [(x, y, Maßstab, Drehung, Haupt, [(Anschluss …)], …)], …); Drehung 1/3/5/7 = hochkant
    printf '%s' "$lt_j" | lt_flach | LC_ALL=C awk -F '\t' '
        { split($1, p, ".") }
        p[1] == 1 && p[3] == 0 && p[4] == 0 && p[5] == "" { anschluss[p[2]] = $2 }
        p[1] == 1 && p[3] == 1 && p[5] == 1 { mw[p[2], p[4]] = $2 }
        p[1] == 1 && p[3] == 1 && p[5] == 2 { mh[p[2], p[4]] = $2 }
        p[1] == 1 && p[3] == 1 && p[5] == 6 && p[6] == "is-current" && $2 == "true" { akt[p[2]] = p[4] }
        p[1] == 2 && p[3] == 3 { dreh[p[2]] = $2 }
        p[1] == 2 && p[3] == 4 { haupt[p[2]] = ($2 == "true") }
        p[1] == 2 && p[3] == 5 && p[5] == 0 { lm[$2] = p[2] }
        END {
            for (m in anschluss) {
                a = anschluss[m]
                if (!(a in lm) || !(m in akt)) continue
                l = lm[a]; w = mw[m, akt[m]]; h = mh[m, akt[m]]
                if (dreh[l] % 2 == 1) { x = w; w = h; h = x }
                print w, h, haupt[l] ? 1 : 0, a
            }
        }'
}

lt_q_sway() {
    [ -n "${SWAYSOCK:-}" ] && lt_hat swaymsg || return 1
    lt_j=$(lt_zeitlimit swaymsg -r -t get_outputs 2>/dev/null) || return 1
    printf '%s' "$lt_j" | lt_flach | LC_ALL=C awk -F '\t' '
        { split($1, p, "."); o = p[1]; r = substr($1, length(o) + 2); alle[o] = 1 }
        r == "active" { an[o] = $2 } r == "name" { name[o] = $2 } r == "primary" { prim[o] = $2 }
        r == "transform" { tr[o] = $2 }
        r == "current_mode.width" { w[o] = $2 } r == "current_mode.height" { h[o] = $2 }
        END {
            for (o in alle) {
                if (an[o] != "true" || w[o] == "") continue
                b = w[o]; g = h[o]
                if (tr[o] ~ /90|270/) { x = b; b = g; g = x }
                print b, g, prim[o] == "true" ? 1 : 0, name[o]
            }
        }'
}

lt_q_hyprland() {
    [ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ] && lt_hat hyprctl || return 1
    lt_j=$(lt_zeitlimit hyprctl monitors -j 2>/dev/null) || return 1
    printf '%s' "$lt_j" | lt_flach | LC_ALL=C awk -F '\t' '
        { split($1, p, "."); o = p[1]; r = substr($1, length(o) + 2); alle[o] = 1 }
        r == "name" { name[o] = $2 } r == "width" { w[o] = $2 } r == "height" { h[o] = $2 }
        r == "transform" { tr[o] = $2 } r == "disabled" { aus[o] = $2 }
        END {
            for (o in alle) {
                if (aus[o] == "true" || w[o] == "") continue
                b = w[o]; g = h[o]
                if (tr[o] % 2 == 1) { x = b; b = g; g = x }
                print b, g, 0, name[o]
            }
        }'
}

lt_q_wlr() {
    [ -n "${WAYLAND_DISPLAY:-}" ] && lt_hat wlr-randr || return 1
    lt_zeitlimit wlr-randr 2>/dev/null | LC_ALL=C awk '
        function aus() { if (n != "" && an && w > 0) { if (tr ~ /90|270/) { x = w; w = h; h = x }; print w, h, 0, n } }
        /^[^ \t]/ { aus(); n = $1; an = 1; w = 0; h = 0; tr = "normal"; next }
        /^[ \t]+Enabled:/ { an = ($2 == "yes") }
        /^[ \t]+Transform:/ { tr = $2 }
        /current/ && $1 ~ /^[0-9]+x[0-9]+$/ { split($1, g, "x"); w = g[1] + 0; h = g[2] + 0 }
        END { aus() }'
}

# xrandr: „HDMI-1 connected primary 1920x1080+0+0 …“ – die Größe ist schon gedreht
lt_q_xrandr() {
    [ -n "${DISPLAY:-}" ] && lt_hat xrandr || return 1
    lt_zeitlimit xrandr --current 2>/dev/null | LC_ALL=C awk '
        $2 == "connected" {
            haupt = ($3 == "primary")
            for (i = 3; i <= NF; i++) if ($i ~ /^[0-9]+x[0-9]+\+-?[0-9]+\+-?[0-9]+$/) {
                split($i, g, /[x+]/); print g[1] + 0, g[2] + 0, haupt, $1; break
            }
        }'
}

# /sys/class/drm: bevorzugter Modus je angeschlossenem Bildschirm – Panel-Größe ohne Drehung (Tablets mit
# Hochkant-Panel laufen meist quer, deshalb gilt hier immer Querformat)
lt_q_drm() {
    for lt_st in "$LT_DRM"/card*-*/status; do
        [ -r "$lt_st" ] || continue
        [ "$(cat "$lt_st" 2>/dev/null)" = connected ] || continue
        lt_mf=${lt_st%/status}/modes
        [ -r "$lt_mf" ] || continue
        IFS= read -r lt_mode < "$lt_mf" || continue
        lt_mb=${lt_mode%%x*}
        lt_mh=${lt_mode#*x}
        lt_mh=${lt_mh%%[!0-9]*}
        case "$lt_mb:$lt_mh" in *[!0-9:]*|:*|*:) continue ;; esac
        if [ "$lt_mh" -gt "$lt_mb" ]; then lt_x=$lt_mb; lt_mb=$lt_mh; lt_mh=$lt_x; fi
        lt_n=${lt_st%/status}
        printf '%s %s 0 %s\n' "$lt_mb" "$lt_mh" "${lt_n##*/card[0-9]-}"
    done
}

# Zeilen „B H haupt name“ → Hauptbildschirm, sonst der größte. Gibt „B H name grund anzahl gemischt“ aus
# (grund: haupt | groesster | einziger; gemischt = 1, wenn die Bildschirme verschiedene Seitenverhältnisse haben).
lt_ausgang_waehlen() {
    LC_ALL=C awk '
        $1 ~ /^[0-9]+$/ && $2 ~ /^[0-9]+$/ && $1 >= 64 && $2 >= 64 && $1 <= 16384 && $2 <= 16384 {
            n++; w[n] = $1; h[n] = $2; hp[n] = $3; nm[n] = $4
        }
        END {
            if (!n) exit 1
            b = 0
            for (i = 1; i <= n; i++) if (hp[i] == 1) { b = i; break }
            grund = "haupt"
            if (!b) { grund = "groesster"; for (i = 1; i <= n; i++) if (!b || w[i] * h[i] > w[b] * h[b]) b = i }
            if (n == 1) grund = "einziger"
            gem = 0
            for (i = 1; i <= n; i++) { r = (w[i] / h[i]) / (w[b] / h[b]); if (r > 1.01 || r < 0.99) gem = 1 }
            print w[b], h[b], (nm[b] == "" ? "?" : nm[b]), grund, n, gem
        }'
}

lt_bildschirm() {
    LT_B=0
    LT_H=0
    LT_GROESSE_QUELLE=
    LT_GROESSE_HINWEIS=
    if [ -n "${LT_GROESSE_VORGABE:-}" ]; then
        LT_B=${LT_GROESSE_VORGABE%x*}
        LT_H=${LT_GROESSE_VORGABE#*x}
        LT_GROESSE_QUELLE="vorgegeben (--groesse)"
        return 0
    fi
    for lt_q in kscreen mutter sway hyprland wlr xrandr drm; do
        case $lt_q in
            kscreen) [ "${LT_DESKTOP:-}" = kde ] || [ -n "${KDE_FULL_SESSION:-}" ] || continue ;;
            mutter)  case ${LT_DESKTOP:-}:${XDG_CURRENT_DESKTOP:-} in gnome:*|*GNOME*|*gnome*) ;; *) continue ;; esac ;;
        esac
        case $lt_q in
            kscreen)  lt_w=$(lt_q_kscreen 2>/dev/null | lt_ausgang_waehlen) ;;
            mutter)   lt_w=$(lt_q_mutter 2>/dev/null | lt_ausgang_waehlen) ;;
            sway)     lt_w=$(lt_q_sway 2>/dev/null | lt_ausgang_waehlen) ;;
            hyprland) lt_w=$(lt_q_hyprland 2>/dev/null | lt_ausgang_waehlen) ;;
            wlr)      lt_w=$(lt_q_wlr 2>/dev/null | lt_ausgang_waehlen) ;;
            xrandr)   lt_w=$(lt_q_xrandr 2>/dev/null | lt_ausgang_waehlen) ;;
            *)        lt_w=$(lt_q_drm 2>/dev/null | lt_ausgang_waehlen) ;;
        esac || continue
        [ -n "$lt_w" ] || continue
        # shellcheck disable=SC2086 # Felder absichtlich aufteilen
        set -- $lt_w
        LT_B=$1
        LT_H=$2
        case $lt_q in
            kscreen) LT_GROESSE_QUELLE="kscreen-doctor" ;; mutter) LT_GROESSE_QUELLE="Mutter (D-Bus)" ;;
            sway) LT_GROESSE_QUELLE="swaymsg" ;; hyprland) LT_GROESSE_QUELLE="hyprctl" ;; wlr) LT_GROESSE_QUELLE="wlr-randr" ;;
            xrandr) LT_GROESSE_QUELLE="xrandr" ;; drm) LT_GROESSE_QUELLE="/sys/class/drm, ohne Drehung" ;;
        esac
        LT_GROESSE_QUELLE="$LT_GROESSE_QUELLE, Bildschirm $3"
        if [ "$5" -gt 1 ]; then
            case $4 in haupt) lt_g="den Hauptbildschirm $3" ;; *) lt_g="den größten Bildschirm ($3)" ;; esac
            if [ "$6" = 1 ]; then
                LT_GROESSE_HINWEIS="$5 Bildschirme mit verschiedenem Seitenverhältnis – das Motiv ist für $lt_g zusammengesetzt; auf den anderen schneidet der Desktop zu"
            else
                LT_GROESSE_HINWEIS="$5 Bildschirme – das Motiv ist für $lt_g zusammengesetzt"
            fi
        fi
        break
    done
    if [ "$LT_B" -lt 64 ] || [ "$LT_H" -lt 64 ]; then
        LT_B=$LT_STANDARD_B
        LT_H=$LT_STANDARD_H
        LT_GROESSE_QUELLE="nicht erkannt – Standard"
    fi
    # erkannte Größe hoch- bzw. querkant verwenden
    case ${LT_FORMAT_VORGABE:-} in
        hoch) if [ "$LT_B" -gt "$LT_H" ]; then lt_x=$LT_B; LT_B=$LT_H; LT_H=$lt_x; LT_GROESSE_QUELLE="$LT_GROESSE_QUELLE, --hochformat"; fi ;;
        quer) if [ "$LT_H" -gt "$LT_B" ]; then lt_x=$LT_B; LT_B=$LT_H; LT_H=$lt_x; LT_GROESSE_QUELLE="$LT_GROESSE_QUELLE, --querformat"; fi ;;
    esac
    return 0
}

# ---------------------------------------------------------------------------------------------------- Merkliste
# vorher.txt: eine Zeile je Einstellung, Felder durch Tabulator getrennt. Bei jedem Lauf gilt: Zeigt der Desktop gerade
# NICHT auf einen Linuxtåg-Hintergrund, ist das die neueste eigene Wahl des Benutzers – sie ersetzt das Gemerkte
# (gsettings je Schema, Xfce je Arbeitsfläche, Plasma je Arbeitsfläche). Zeigt er noch auf uns (Motiv wechseln, noch
# einmal ausführen), bleibt das Gemerkte, und es wird nur ergänzt, was fehlt. Eigene Werte werden nie gemerkt.
lt_gemerkt() {   # Präfix
    [ -f "$LT_VORHER" ] || return 1
    while IFS= read -r lt_z; do
        case $lt_z in "$1"*) return 0 ;; esac
    done < "$LT_VORHER"
    return 1
}

lt_merken() {    # Zeile
    mkdir -p "$LT_ZUSTAND" || return 1
    printf '%s\n' "$1" >> "$LT_VORHER"
}

# Zeilen mit diesem Anfang aus der Merkliste streichen (der Desktop zeigt inzwischen ein eigenes Bild des Benutzers –
# das ist ab jetzt „vorher“)
lt_vergessen() {   # Präfix
    [ -f "$LT_VORHER" ] || return 0
    LC_ALL=C awk -v p="$1" 'index($0, p) != 1' "$LT_VORHER" > "$LT_VORHER.neu" && mv -f "$LT_VORHER.neu" "$LT_VORHER"
}

# Verweist ein Wert auf unsere eigenen Dateien? Nur unsere Ordner zählen: …/linuxtag-hintergrund/… (dieses Skript),
# das Plasma-Plugin und der Ordner des Prototyps …/backgrounds/linuxtag-2026/. NICHT jeder Name mit „linuxtag-2026“
# – so heißen auch die Bilder, die man auf der Website herunterlädt (linuxtag-2026-horizont-1920x1080.png); die
# gehören dem Benutzer und werden gemerkt wie jedes andere Bild.
lt_ist_unseres() {
    case $1 in
        *"/$LT_KENNUNG/"*|*"$LT_KDE_ID"*|*/backgrounds/linuxtag-2026/*) return 0 ;;
    esac
    return 1
}

lt_installiert_lesen() {   # Schlüssel → Wert aus installiert.txt
    [ -f "$LT_INSTALLIERT" ] || return 1
    sed -n "s/^$1=//p" "$LT_INSTALLIERT" | head -n 1
}

lt_installiert_schreiben() {   # Ergebnis (0 = eingestellt)
    lt_fam=$(lt_installiert_lesen familien 2>/dev/null || true)
    case " $lt_fam " in *" $LT_DESKTOP "*) ;; *) lt_fam=${lt_fam:+$lt_fam }$LT_DESKTOP ;; esac
    # Hat das Umstellen nicht geklappt, zeigt der Desktop womöglich noch das vorige Motiv: dann das nennen
    lt_motiv_jetzt=$LT_MOTIV
    lt_abgelegt=
    if [ "$1" != 0 ]; then
        lt_vorher_motiv=$(lt_installiert_lesen motiv 2>/dev/null || true)
        lt_gezeigt=$(lt_eingestelltes_motiv)
        if [ -n "$lt_gezeigt" ] && [ "$lt_gezeigt" != "$LT_MOTIV" ]; then
            lt_motiv_jetzt=$lt_gezeigt
            lt_abgelegt=$LT_MOTIV
        elif [ -z "$lt_gezeigt" ] && [ -n "$lt_vorher_motiv" ] && [ "$lt_vorher_motiv" != "$LT_MOTIV" ]; then
            lt_motiv_jetzt=$lt_vorher_motiv
            lt_abgelegt=$LT_MOTIV
        fi
    fi
    mkdir -p "$LT_ZUSTAND" || return 1
    {
        printf 'motiv=%s\n' "$lt_motiv_jetzt"
        [ -n "$lt_abgelegt" ] && printf 'abgelegt=%s\n' "$lt_abgelegt"
        printf 'version=%s\n' "$LT_VERSION"
        printf 'art=%s\n' "${LT_ART:-nicht eingestellt}"
        printf 'groesse=%sx%s\n' "$LT_B" "$LT_H"
        printf 'groesse_quelle=%s\n' "$LT_GROESSE_QUELLE"
        [ -n "${LT_BILD_TEXT:-}" ] && printf 'bild=%s\n' "$LT_BILD_TEXT"
        if [ "$1" = 0 ]; then
            printf 'zustand=eingestellt\n'
        else
            printf 'zustand=nur teilweise – der Hintergrund ist nicht (ganz) eingestellt\n'
        fi
        printf 'familien=%s\n' "$lt_fam"
        printf 'datum=%s\n' "$(date '+%Y-%m-%d %H:%M')"
    } > "$LT_INSTALLIERT.neu" && mv -f "$LT_INSTALLIERT.neu" "$LT_INSTALLIERT"
}

# Welches Motiv zeigt der Desktop gerade (laut Einstellung)? Leer = weiß ich nicht / keins von uns
lt_eingestelltes_motiv() {
    lt_w=
    case $LT_DESKTOP in
        gnome)    lt_w=$(gsettings get org.gnome.desktop.background picture-uri 2>/dev/null) ;;
        cinnamon) lt_w=$(gsettings get org.cinnamon.desktop.background picture-uri 2>/dev/null) ;;
        mate)     lt_w=$(gsettings get org.mate.background picture-filename 2>/dev/null) ;;
        xfce)     lt_w=$(lt_xf -l 2>/dev/null | grep '/last-image$' | head -n 1) && lt_w=$(lt_xf -p "$lt_w") ;;
        *)        return 0 ;;
    esac
    case $lt_w in
        *"/$LT_KENNUNG/"*) lt_w=${lt_w#*"/$LT_KENNUNG/"}; lt_w=${lt_w%%/*}
                           case " $LT_MOTIVE " in *" $lt_w "*) printf '%s\n' "$lt_w" ;; esac ;;
    esac
}

# ---------------------------------------------------------------------------------------------------- Laden
lt_basis() {
    LT_BASIS=${LINUXTAG_HINTERGRUND_BASIS:-$LT_BASIS_STANDARD}
    case $LT_BASIS in */) ;; *) LT_BASIS=$LT_BASIS/ ;; esac
    # kein „Benutzer@Rechner“ (http://127.0.0.1:1@anderswo/ sähe sonst wie localhost aus)
    lt_rechner=${LT_BASIS#*://}
    case ${lt_rechner%%/*} in
        *@*|'') lt_fehler "LINUXTAG_HINTERGRUND_BASIS: ungültige Adresse ($LT_BASIS)"; return 1 ;;
    esac
    case $LT_BASIS in
        https://*) LT_PROTO='=https' ;;
        http://127.0.0.1/*|http://127.0.0.1:*|http://localhost/*|http://localhost:*) LT_PROTO='=http,https' ;;
        *) lt_fehler "LINUXTAG_HINTERGRUND_BASIS muss mit https:// beginnen (http:// nur für 127.0.0.1/localhost)"
           return 1 ;;
    esac
    [ "$LT_BASIS" = "$LT_BASIS_STANDARD" ] || lt_warn "Testmodus: Pakete kommen von $LT_BASIS"
    return 0
}

# curl: nur HTTPS (auch bei Weiterleitungen), mindestens TLS 1.2. wget: GNU wget folgt Weiterleitungen auch von
# https nach http (--https-only gilt nur rekursiv) – deshalb dort keine Weiterleitungen; busybox-wget prüft kein
# TLS-Zertifikat. In beiden Fällen schützt die eingebaute SHA-256-Summe das Paket.
lt_laden() {   # URL Ziel
    if lt_hat curl; then
        curl --proto "$LT_PROTO" --tlsv1.2 -fsSL --retry 2 -o "$2" "$1"
        return
    fi
    if lt_hat wget; then
        lt_wget_hilfe=$(wget --help 2>&1)
        set --  "$1" "$2"
        case $lt_wget_hilfe in *--max-redirect*) set -- "$@" --max-redirect=0 ;; esac
        case $LT_PROTO in
            =https) case $lt_wget_hilfe in *--https-only*) set -- "$@" --https-only ;; esac ;;
        esac
        lt_u=$1
        lt_z=$2
        shift 2
        wget -q "$@" -O "$lt_z" "$lt_u"
        return
    fi
    lt_fehler "weder curl noch wget gefunden – bitte eines davon installieren (z. B. sudo apt install curl)"
    return 127
}

lt_sha256() {   # Datei → Prüfsumme (Kleinbuchstaben)
    # über die Standardeingabe: Der Dateiname kommt so nie in die Ausgabe (GNU sha256sum stellt sonst bei einem \\ im
    # Pfad ein \\ vor die Summe)
    if lt_hat sha256sum; then
        sha256sum < "$1" | cut -d ' ' -f 1
    elif lt_hat shasum; then
        shasum -a 256 < "$1" | cut -d ' ' -f 1
    elif lt_hat openssl; then
        openssl dgst -sha256 < "$1" | sed 's/.*= *//'
    else
        return 1
    fi
}

# Paket des Motivs laden, prüfen, entpacken → LT_PAKET (Ordner)
lt_paket_holen() {
    if ! lt_pakete "$LT_MOTIV"; then
        lt_fehler "für das Motiv „$LT_MOTIV“ steht keine Prüfsumme in diesem Skript (Entwicklungsfassung?) – breche ab"
        return 1
    fi
    lt_basis || return 1
    # schreiben dürfen wir? (vor dem Download prüfen, ohne schon etwas anzulegen: nächster vorhandener Ordner)
    for lt_d in "$LT_DATA_HOME" "$LT_STATE_HOME"; do
        lt_e=$lt_d
        while [ ! -d "$lt_e" ] && [ -n "$lt_e" ] && [ "$lt_e" != / ]; do lt_e=${lt_e%/*}; done
        if [ ! -w "${lt_e:-/}" ]; then
            lt_fehler "kann nicht in $lt_d schreiben – nichts wurde verändert"
            return 1
        fi
    done
    lt_tmpdir=${TMPDIR:-/tmp}
    [ -d "$lt_tmpdir" ] && [ -w "$lt_tmpdir" ] || lt_tmpdir=/tmp
    case $lt_tmpdir in /*) ;; *) lt_tmpdir=$(pwd)/$lt_tmpdir ;; esac
    LT_TMP=$(mktemp -d "$lt_tmpdir/linuxtag-hintergrund.XXXXXX") || { lt_fehler "kein temporärer Ordner"; return 1; }
    lt_url=$LT_BASIS$LT_DATEI
    lt_sag "Lade $lt_url …"
    lt_laden "$lt_url" "$LT_TMP/$LT_DATEI"
    lt_rc=$?
    if [ "$lt_rc" = 127 ]; then
        return 1      # Meldung kam schon (weder curl noch wget)
    elif [ "$lt_rc" != 0 ]; then
        lt_fehler "Download fehlgeschlagen ($lt_url) – nichts wurde verändert"
        return 1
    fi
    if ! lt_ist=$(lt_sha256 "$LT_TMP/$LT_DATEI") || [ -z "$lt_ist" ]; then
        lt_fehler "kein Programm für SHA-256 gefunden (sha256sum, shasum oder openssl) – ohne Prüfung wird nichts installiert"
        return 1
    fi
    if [ "$lt_ist" != "$LT_SUMME" ]; then
        lt_fehler "Prüfsumme stimmt nicht – das Paket ist beschädigt oder verändert. Nichts wurde verändert."
        lt_fehler "  erwartet $LT_SUMME"
        lt_fehler "  erhalten $lt_ist"
        return 1
    fi
    lt_info "Prüfsumme in Ordnung (SHA-256 ${LT_SUMME%"${LT_SUMME#????????????????}"}…)"
    # über die Standardeingabe und cd statt -C: GNU tar deutet \ in Dateinamen sonst als Escape (TMPDIR mit \)
    if ! (cd "$LT_TMP" && tar -xzf -) < "$LT_TMP/$LT_DATEI"; then
        lt_fehler "Paket ließ sich nicht entpacken – nichts wurde verändert"
        return 1
    fi
    LT_PAKET=$LT_TMP/linuxtag-2026-$LT_MOTIV
    if [ ! -f "$LT_PAKET/VERSION" ] || ! grep -q "^motiv=$LT_MOTIV\$" "$LT_PAKET/VERSION"; then
        lt_fehler "Paket hat einen unerwarteten Inhalt – nichts wurde verändert"
        return 1
    fi
    return 0
}

# ---------------------------------------------------------------------------------------------------- Dateien
lt_uri() {   # Pfad → file://-URI (Prozentkodierung aller Bytes außer A–Z a–z 0–9 - . _ ~ /)
    printf 'file://'
    printf '%s' "$1" | od -An -v -tx1 | tr -s ' ' '\n' | sed '/^$/d' | while IFS= read -r lt_hex; do
        case $lt_hex in
            2d|2e|2f|3[0-9]|4[1-9a-f]|5[0-9a]|5f|6[1-9a-f]|7[0-9a]|7e)
                # shellcheck disable=SC2059 # Oktal-Escape im Format ist hier Absicht
                printf "\\$(printf '%03o' "0x$lt_hex")" ;;
            *)  printf '%%%s' "$(printf '%s' "$lt_hex" | tr 'abcdef' 'ABCDEF')" ;;
        esac
    done
}

lt_xml() { printf '%s' "$1" | sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' -e 's/>/\&gt;/g'; }

# Zuschnitt der Website (public/assets/js/hintergrund.js, MOTIVE[].zuschnitt) für Motive mit Wurzel-viewBox:
# Regel und Zahlen aus bilder/zuschnitt.txt des Pakets → viewBox „x y b h“ mit drei Nachkommastellen (toFixed(3)).
#   gitterraum: D = min(0,78·B; 0,5·H), s = D / sonne, fy = 0,575 (B/H ≤ 0,5) … 0,455 (B/H ≥ 1,3) linear,
#               viewBox = (−B/2s, −fy·H/s, B/s, H/s)
#   haelfte:    kern (x y b h), hoch (breite band0 band1), quer (hoehe breite band0 band1) aus <metadata id="rahmen">
# >>> zuschnitt (wird von test/zuschnitt-test.mjs gegen die Website geprüft)
lt_zuschnitt() {   # Regel B H Datei
    LC_ALL=C awk -v regel="$1" -v W="$2" -v H="$3" '
        { i = index($0, "="); if (i > 1) w[substr($0, 1, i - 1)] = substr($0, i + 1) }
        function r3(v) { return sprintf("%.3f", v) }
        END {
            if (W < 1 || H < 1) exit 1
            if (regel == "gitterraum") {
                sonne = w["sonne"] + 0
                if (sonne <= 0) exit 1
                D = 0.78 * W; if (0.5 * H < D) D = 0.5 * H
                s = D / sonne; r = W / H
                if (r <= 0.5) fy = 0.575; else if (r >= 1.3) fy = 0.455; else fy = 0.575 + (r - 0.5) / 0.8 * (0.455 - 0.575)
                print r3(-W / 2 / s), r3(-fy * H / s), r3(W / s), r3(H / s)
            } else if (regel == "haelfte") {
                if (split(w["kern"], k, " ") != 4 || split(w["hoch"], ho, " ") != 3 || split(w["quer"], qu, " ") != 4) exit 1
                if (W / H < 1) { b0 = ho[2]; b1 = ho[3]; s = ho[1] * W / k[3]; t = 0.96 * (b1 - b0) * H / k[4] }
                else { b0 = qu[3]; b1 = qu[4]; s = qu[1] * H / k[4]; t = qu[2] * W / k[3] }
                if (t < s) s = t
                kx = k[1] + k[3] / 2; ky = k[2] + k[4] / 2; cy = (b0 + b1) / 2 * H
                print r3(kx - W / 2 / s), r3(ky - cy / s), r3(W / s), r3(H / s)
            } else exit 1
        }' "$4"
}
# <<< zuschnitt

# Breite und Höhe einer PNG-Datei (IHDR) → „B H“
lt_png_groesse() {
    [ "$(od -An -c -j1 -N3 "$1" 2>/dev/null | tr -d ' \n')" = PNG ] || return 1
    od -An -tu1 -j16 -N8 "$1" 2>/dev/null | LC_ALL=C awk 'NF == 8 { print $1 * 16777216 + $2 * 65536 + $3 * 256 + $4, $5 * 16777216 + $6 * 65536 + $7 * 256 + $8 }'
}

# SVG → PNG in genau B × H Pixeln: rsvg-convert (librsvg, wie GNOME), Inkscape 1.x oder ImageMagick (nur mit librsvg als
# SVG-Leser – der eingebaute kann die verschachtelten <svg> der Motive nicht). Ergebnis wird nachgemessen. → LT_RASTER
lt_rastern() {   # SVG PNG B H
    LT_RASTER=
    for lt_r in rsvg-convert inkscape magick convert; do
        lt_hat "$lt_r" || continue
        rm -f "$2"
        case $lt_r in
            rsvg-convert) rsvg-convert -w "$3" -h "$4" -o "$2" "$1" >/dev/null 2>&1 ;;
            inkscape)     inkscape --export-type=png --export-filename="$2" -w "$3" -h "$4" "$1" >/dev/null 2>&1 ;;
            *)            "$lt_r" -list format 2>/dev/null | grep -i '^ *SVG ' | grep -qi rsvg || continue
                          "$lt_r" -background none "$1" -resize "${3}x${4}!" "PNG32:$2" >/dev/null 2>&1 ;;
        esac
        if [ -s "$2" ] && [ "$(lt_png_groesse "$2")" = "$3 $4" ]; then
            LT_RASTER=$lt_r
            return 0
        fi
    done
    rm -f "$2"
    return 1
}

# Nächstliegendes fertiges Bild aus bilder/fertig/<B>x<H>.jpg (Seitenverhältnis, dann Größe)
lt_fertig_waehlen() {   # Ordner B H
    for lt_f in "$1"/*x*.jpg; do [ -f "$lt_f" ] && printf '%s\n' "${lt_f##*/}"; done | LC_ALL=C awk -v W="$2" -v H="$3" '
        { g = $0; sub(/\.jpg$/, "", g); split(g, z, "x"); if (z[1] < 1 || z[2] < 1) next
          d = log(z[1] / z[2]) - log(W / H); if (d < 0) d = -d
          if (best == "" || d < bd - 1e-9 || (d < bd + 1e-9 && z[1] * z[2] > ba)) { best = $0; bd = d; ba = z[1] * z[2] } }
        END { if (best == "") exit 1; print best }'
}

# Vorlagen des Pakets für den Bildschirm zusammensetzen → Ordner $1: phasen/*.svg, statisch.svg, LIESMICH …;
# für LXDE/LXQt/sway … zusätzlich statisch.png (genau B × H) oder das nächstliegende fertige Bild (statisch.jpg) → LT_BILD
lt_zusammensetzen() {   # Ordner
    lt_zt=$LT_PAKET/bilder/zuschnitt.txt
    lt_regel=$(sed -n 's/^regel=//p' "$lt_zt" 2>/dev/null | head -n 1)
    if [ "$LT_H" -gt "$LT_B" ]; then lt_fmt=hoch; LT_FORMAT_TEXT=Hochformat; else lt_fmt=quer; LT_FORMAT_TEXT=Querformat; fi
    lt_vorlage=$LT_PAKET/bilder/$lt_fmt
    [ -d "$lt_vorlage" ] || lt_vorlage=$LT_PAKET/bilder/alle
    if [ ! -f "$lt_vorlage/statisch.svg" ]; then
        lt_fehler "Paket ohne Vorlagen ($lt_vorlage)"
        return 1
    fi
    # Zeile 1 der Vorlagen endet mit „ width="…" height="…">“ (Motive, die sich selbst anpassen) bzw.
    # „ viewBox="…" width="…" height="…">“ (Zuschnitt per viewBox) – dort kommt der Bildschirm hinein
    case $lt_regel in
        gitterraum|haelfte)
            lt_vb=$(lt_zuschnitt "$lt_regel" "$LT_B" "$LT_H" "$lt_zt") || lt_vb=
            if [ -z "$lt_vb" ]; then
                lt_fehler "Zuschnitt ging nicht ($lt_regel)"
                return 1
            fi
            lt_ende=" viewBox=\"$lt_vb\" width=\"$LT_B\" height=\"$LT_H\">"
            lt_muster=' viewBox="[^"]*" width="[0-9.]*" height="[0-9.]*">$' ;;
        selbst)
            lt_ende=" width=\"$LT_B\" height=\"$LT_H\">"
            lt_muster=' width="[0-9.]*" height="[0-9.]*">$' ;;
        *)  lt_fehler "Paket mit unbekanntem Zuschnitt ($lt_regel)"
            return 1 ;;
    esac
    for lt_f in "$lt_vorlage"/phasen/*.svg "$lt_vorlage/statisch.svg"; do
        [ -f "$lt_f" ] || continue
        case $lt_f in */phasen/*) lt_z=$1/phasen/${lt_f##*/} ;; *) lt_z=$1/statisch.svg ;; esac
        sed "1s|$lt_muster|$lt_ende|" "$lt_f" > "$lt_z" || return 1
        # nachprüfen: Zeile 1 trägt jetzt genau unsere Größe
        case $(head -n 1 "$lt_z") in
            *"$lt_ende") ;;
            *) lt_fehler "Vorlage ${lt_f##*/} ließ sich nicht anpassen"; return 1 ;;
        esac
    done
    for lt_f in LIESMICH.txt LICENSE VERSION; do
        cp "$LT_PAKET/$lt_f" "$1/$lt_f" || return 1
    done
    LT_BILD=
    LT_BILD_TEXT=
    case $LT_DESKTOP in
        lxde|lxqt|anleitung)
            if lt_rastern "$1/statisch.svg" "$1/statisch.png" "$LT_B" "$LT_H"; then
                LT_BILD=$LT_ZIEL/statisch.png
                LT_BILD_TEXT="PNG ${LT_B}×${LT_H} (mit $LT_RASTER gerastert)"
            else
                lt_fertig=$(lt_fertig_waehlen "$LT_PAKET/bilder/fertig" "$LT_B" "$LT_H") || { lt_fehler "Paket ohne fertige Bilder"; return 1; }
                cp "$LT_PAKET/bilder/fertig/$lt_fertig" "$1/statisch.jpg" || return 1
                LT_BILD=$LT_ZIEL/statisch.jpg
                LT_BILD_TEXT="fertiges Bild ${lt_fertig%.jpg} (JPEG) – nächstliegende Form zu ${LT_B}×${LT_H}"
                lt_info "kein rsvg-convert, Inkscape oder ImageMagick (mit librsvg) gefunden – nehme das fertige Bild ${lt_fertig%.jpg}."
                lt_info "Für ein Bild genau in ${LT_B}×${LT_H}: rsvg-convert installieren (Debian/Ubuntu: sudo apt install librsvg2-bin,"
                lt_info "Fedora: sudo dnf install librsvg2-tools, Arch: sudo pacman -S librsvg) und den Befehl erneut ausführen."
            fi ;;
    esac
    return 0
}

# Bilder für diesen Bildschirm nach $LT_DATEN/<motiv>/ legen. Erst alles in einen Nebenordner (.neu-<motiv>) – auch
# die Diashow, schon mit den endgültigen Pfaden –, dann den alten Ordner beiseite (.alt-<motiv>), den neuen an seinen
# Platz und erst danach den alten löschen. So zeigt eine Einstellung nie lange auf eine fehlende Datei (auch nicht bei
# demselben Motiv noch einmal); geht etwas schief, bleibt alles wie es war und kein Nebenordner liegen.
lt_dateien() {
    LT_ZIEL=$LT_DATEN/$LT_MOTIV
    lt_neu=$LT_DATEN/.neu-$LT_MOTIV
    LT_ALT_ORDNER=$LT_DATEN/.alt-$LT_MOTIV
    rm -rf "$lt_neu" "$LT_ALT_ORDNER"
    if ! mkdir -p "$lt_neu/phasen"; then
        lt_fehler "kann $LT_DATEN nicht anlegen"
        rm -rf "$lt_neu"
        return 1
    fi
    LT_NEU_ORDNER=$lt_neu
    lt_ok=0
    lt_zusammensetzen "$lt_neu" || lt_ok=1
    if [ "$lt_ok" = 0 ]; then
        case $LT_DESKTOP in
            gnome|cinnamon|mate) lt_diashow "$lt_neu" || { lt_fehler "Diashow ließ sich nicht schreiben"; lt_ok=1; } ;;
        esac
    fi
    if [ "$lt_ok" = 0 ] && [ -d "$LT_ZIEL" ]; then
        mv "$LT_ZIEL" "$LT_ALT_ORDNER" || lt_ok=1
    fi
    if [ "$lt_ok" = 0 ] && ! mv "$lt_neu" "$LT_ZIEL"; then
        [ -d "$LT_ALT_ORDNER" ] && mv "$LT_ALT_ORDNER" "$LT_ZIEL"
        lt_ok=1
    fi
    if [ "$lt_ok" != 0 ]; then
        rm -rf "$lt_neu"
        LT_NEU_ORDNER=
        return 1
    fi
    LT_NEU_ORDNER=
    rm -rf "$LT_ALT_ORDNER"
    # Kopie des Skripts für --entfernen ohne Internet (nur, wenn es als Datei gestartet wurde – nicht über die Pipe)
    if [ -f "$0" ] && grep -q '^lt_grundwerte()' "$0" 2>/dev/null; then
        cp "$0" "$LT_DATEN/hintergrund.sh.neu" 2>/dev/null && mv -f "$LT_DATEN/hintergrund.sh.neu" "$LT_DATEN/hintergrund.sh"
    fi
    lt_info "Bilder abgelegt: $LT_ZIEL"
    lt_info "zusammengesetzt für ${LT_B}×${LT_H} ($LT_FORMAT_TEXT; Größe: $LT_GROESSE_QUELLE)"
    [ -n "$LT_GROESSE_HINWEIS" ] && lt_info "$LT_GROESSE_HINWEIS"
    [ -n "$LT_BILD_TEXT" ] && lt_info "ruhendes Bild: $LT_BILD_TEXT"
    return 0
}

# Andere Motiv-Ordner löschen (nach erfolgreichem Umstellen)
lt_alte_motive_weg() {
    for lt_d in "$LT_DATEN"/*/; do
        [ -d "$lt_d" ] || continue
        lt_d=${lt_d%/}
        [ "${lt_d##*/}" = "$LT_MOTIV" ] && continue
        case " $LT_MOTIVE " in *" ${lt_d##*/} "*) rm -rf "$lt_d" ;; esac
    done
}

# UTC-Versatz zu einem Zeitpunkt in Sekunden (braucht date -d @…, GNU oder busybox)
lt_versatz() {   # Epoche
    lt_z=$(date -d "@$1" +%z 2>/dev/null) || return 1
    case $lt_z in [+-][0-9][0-9][0-9][0-9]) ;; *) return 1 ;; esac
    lt_hh=${lt_z#?}
    lt_mm=${lt_hh#??}
    lt_hh=${lt_hh%??}
    lt_s=$(( (1$lt_hh - 100) * 3600 + (1$lt_mm - 100) * 60 ))
    case $lt_z in -*) lt_s=$((0 - lt_s)) ;; esac
    echo "$lt_s"
}

# Längen der Tage ab heute (Sekunden über/unter 24 h, je Tag eine Zahl) für ein ganzes Jahr – oder „0“, wenn in
# diesem Jahr nicht umgestellt wird (oder ohne „date -d“). Tag i ist um (Versatz gestern Mittag − Versatz heute
# Mittag) länger; umgestellt wird immer nachts. Wochenweise prüfen, nur in einer Woche mit Umstellung tageweise.
lt_tageslaengen() {   # Start (Epoche, heute 00:00) Tage
    lt_v=$(lt_versatz $(($1 - 43200))) || { echo 0; return 0; }
    lt_out=
    lt_um=0
    lt_i=0
    while [ "$lt_i" -lt "$2" ]; do
        lt_w=$((lt_i + 7))
        [ "$lt_w" -gt "$2" ] && lt_w=$2
        lt_vw=$(lt_versatz $(($1 + (lt_w - 1) * 86400 + 43200))) || { echo 0; return 0; }
        if [ "$lt_vw" = "$lt_v" ]; then
            while [ "$lt_i" -lt "$lt_w" ]; do lt_out="$lt_out 0"; lt_i=$((lt_i + 1)); done
            continue
        fi
        while [ "$lt_i" -lt "$lt_w" ]; do
            lt_vn=$(lt_versatz $(($1 + lt_i * 86400 + 43200))) || { echo 0; return 0; }
            lt_d=$((lt_v - lt_vn))
            case $lt_d in 0|3600|-3600) ;; *) lt_d=0 ;; esac
            [ "$lt_d" = 0 ] || lt_um=1
            lt_out="$lt_out $lt_d"
            lt_v=$lt_vn
            lt_i=$((lt_i + 1))
        done
    done
    if [ "$lt_um" = 1 ]; then echo "$lt_out"; else echo 0; fi
}

# GNOME-Diashow → $1/tageszeit.xml (Pfade schon auf $LT_ZIEL). Phase k gilt ab 2k:00 Uhr; die letzte Stunde jeder
# Phase blendet zur nächsten über. Beginn = heute 00:00 Ortszeit. GNOME rechnet die Diashow in Sekunden ab dem Beginn
# und wiederholt sie, die Uhr springt aber bei der Zeitumstellung. Deshalb steht – wenn umgestellt wird – ein ganzes
# Jahr Tag für Tag in der Datei, die Umstellungstage mit 25 bzw. 23 Stunden: Ein Jahr enthält beide Umstellungen, die
# Wiederholung beginnt also wieder zur selben Uhrzeit. Ab dem zweiten Jahr können die Umstellungstage ein paar Tage
# anders liegen (dann bis zu etwa einer Woche 1 h daneben – erneut ausführen behebt das). Ohne Umstellung (oder ohne
# „date -d“, weder GNU noch busybox): ein einziger 24-Stunden-Tag.
lt_diashow() {   # Ordner
    lt_n=0
    for lt_f in "$1"/phasen/*.svg; do [ -f "$lt_f" ] && lt_n=$((lt_n + 1)); done
    [ "$lt_n" -gt 0 ] || { lt_fehler "keine Phasenbilder"; return 1; }
    lt_laengen=0
    if lt_start=$(date -d "$(date +%Y-%m-%d) 00:00:00" +%s 2>/dev/null); then
        # ein Jahr: 365 Tage, 366 über einen 29. Februar
        lt_tage=365
        [ "$(date -d "@$((lt_start + 365 * 86400 + 43200))" +%m-%d 2>/dev/null)" = "$(date +%m-%d)" ] || lt_tage=366
        lt_laengen=$(lt_tageslaengen "$lt_start" "$lt_tage")
    fi
    for lt_f in "$1"/phasen/*.svg; do
        [ -f "$lt_f" ] && printf '%s\n' "$LT_ZIEL/phasen/${lt_f##*/}"
    done | LC_ALL=C awk -v titel="$LT_TITEL" -v jahr="$(date +%Y)" -v monat="$(date +%m)" -v tag="$(date +%d)" \
        -v laengen="$lt_laengen" -v blende="$LT_UEBERBLENDUNG" '
        function x(s) { gsub(/&/, "\\&amp;", s); gsub(/</, "\\&lt;", s); gsub(/>/, "\\&gt;", s); return s }
        { f[n++] = x($0) }
        END {
            fest = 86400 / n - blende
            printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            printf "<!-- %s – lebendiger Hintergrund (Tageszeit). Erzeugt von hintergrund.sh. -->\n", titel
            printf "<background>\n  <starttime>\n    <year>%d</year>\n    <month>%d</month>\n    <day>%d</day>\n", jahr, monat, tag
            printf "    <hour>0</hour>\n    <minute>0</minute>\n    <second>0</second>\n  </starttime>\n"
            t = split(laengen, L, " ")
            for (i = 1; i <= t; i++) for (k = 0; k < n; k++) {
                # die Stunde der Umstellung kommt zu Phase 1 (2–4 Uhr) dazu bzw. fehlt dort
                dauer = fest + (k == 1 ? L[i] : 0)
                if (dauer > 0) printf "  <static>\n    <duration>%d.0</duration>\n    <file>%s</file>\n  </static>\n", dauer, f[k]
                printf "  <transition type=\"overlay\">\n    <duration>%d.0</duration>\n    <from>%s</from>\n    <to>%s</to>\n  </transition>\n", blende, f[k], f[(k + 1) % n]
            }
            printf "</background>\n"
        }' > "$1/tageszeit.xml"
}

# Eintrag für „Einstellungen > Darstellung“ (GNOME) bzw. die Auswahl von Cinnamon/MATE
lt_auswahl_eintrag() {
    mkdir -p "${LT_PROPS%/*}" || return 1
    {
        printf '<?xml version="1.0" encoding="UTF-8"?>\n'
        printf '<!DOCTYPE wallpapers SYSTEM "gnome-wp-list.dtd">\n<wallpapers>\n'
        for lt_e in "$LT_ZIEL/tageszeit.xml:Tageszeit" "$LT_ZIEL/statisch.svg:"; do
            lt_d=${lt_e%:*}
            lt_t=${lt_e##*:}
            printf '  <wallpaper deleted="false">\n    <name>%s – %s%s</name>\n' "$LT_TITEL" "$LT_MOTIV" "${lt_t:+ ($lt_t)}"
            printf '    <filename>%s</filename>\n    <filename-dark>%s</filename-dark>\n' "$(lt_xml "$lt_d")" "$(lt_xml "$lt_d")"
            printf '    <options>zoom</options>\n    <shade_type>solid</shade_type>\n'
            printf '    <pcolor>#0b0918</pcolor>\n    <scolor>#0b0918</scolor>\n  </wallpaper>\n'
        done
        printf '</wallpapers>\n'
    } > "$LT_PROPS"
}

# Bild der aktuellen Stunde (gleiche Einteilung wie Xfce „chronologisch“: Stunde / (24 / Anzahl))
lt_aktuelle_phase() {
    lt_n=0
    for lt_f in "$LT_ZIEL"/phasen/*.svg; do [ -f "$lt_f" ] && lt_n=$((lt_n + 1)); done
    lt_stunde=$(date +%H | sed 's/^0//')
    lt_i=$(( ${lt_stunde:-0} * lt_n / 24 ))
    lt_k=0
    for lt_f in "$LT_ZIEL"/phasen/*.svg; do
        if [ "$lt_k" = "$lt_i" ]; then
            printf '%s\n' "$lt_f"
            return 0
        fi
        lt_k=$((lt_k + 1))
    done
}

# ---------------------------------------------------------------------------------------------------- GNOME & Co.
lt_gs_schluessel() {   # Schema Schlüssel → vorhanden?
    for lt_k in $(gsettings list-keys "$1" 2>/dev/null); do
        [ "$lt_k" = "$2" ] && return 0
    done
    return 1
}

lt_gv() { printf "'%s'" "$(printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e "s/'/\\\\'/g")"; }

# dconf-Pfad eines Schemas (steht in der Schema-Datei; MATE weicht vom Namen ab: org.mate.background liegt unter
# /org/mate/desktop/background/). Unbekanntes Schema → kein Pfad, dann wird der Wert wörtlich gemerkt.
lt_gs_pfad() {
    case $1 in
        org.gnome.desktop.background)              echo /org/gnome/desktop/background/ ;;
        org.cinnamon.desktop.background)           echo /org/cinnamon/desktop/background/ ;;
        org.cinnamon.desktop.background.slideshow) echo /org/cinnamon/desktop/background/slideshow/ ;;
        org.mate.background)                       echo /org/mate/desktop/background/ ;;
        *) return 1 ;;
    esac
}

# Hat der Benutzer den Schlüssel selbst gesetzt? Nur mit dconf als Speicher feststellbar (dconf read ist leer, wenn
# der Standard gilt). Dann wird „@standard“ gemerkt und beim Entfernen zurückgesetzt statt den Standard festzuschreiben.
lt_gs_standard() {   # Schema Schlüssel → 0 = kein eigener Wert
    case ${GSETTINGS_BACKEND:-dconf} in dconf) ;; *) return 1 ;; esac
    lt_hat dconf || return 1
    lt_pfad=$(lt_gs_pfad "$1") || return 1
    lt_dw=$(dconf read "$lt_pfad$2" 2>/dev/null) || return 1
    [ -z "$lt_dw" ]
}

# setzen, merken (falls noch nicht gemerkt; nie den eigenen Wert), danach nachlesen.
# Gemerkt wird der Wert wörtlich, „@standard“ (kein eigener Wert gesetzt → beim Entfernen zurücksetzen) oder
# „@ersatz“ (vorher war schon ein Linuxtåg-Hintergrund eingestellt, z. B. der Prototyp, oder der Wert war nicht
# lesbar → beim Entfernen zurücksetzen, aber ehrlich als Standard melden).
lt_gs_setzen() {   # Schema Schlüssel Wert(GVariant-Text)
    lt_gs_schluessel "$1" "$2" || return 0
    lt_alt=$(gsettings get "$1" "$2" 2>/dev/null) || lt_alt=
    if ! lt_gemerkt "gsettings$LT_TAB$1$LT_TAB$2$LT_TAB"; then
        if lt_ist_unseres "$lt_alt" || [ -z "$lt_alt" ]; then
            lt_merken "gsettings$LT_TAB$1$LT_TAB$2$LT_TAB@ersatz" || return 1
        elif lt_gs_standard "$1" "$2"; then
            lt_merken "gsettings$LT_TAB$1$LT_TAB$2$LT_TAB@standard" || return 1
        else
            lt_merken "gsettings$LT_TAB$1$LT_TAB$2$LT_TAB$lt_alt" || return 1
        fi
    fi
    gsettings set "$1" "$2" "$3" 2>/dev/null
    lt_neu=$(gsettings get "$1" "$2" 2>/dev/null)
    if [ "$lt_neu" != "$3" ]; then
        lt_warn "$1 $2 ließ sich nicht setzen (läuft die Desktop-Sitzung? D-Bus erreichbar?)"
        return 1
    fi
    return 0
}

lt_gnome_einrichten() {   # Schema
    if ! lt_hat gsettings; then
        lt_warn "gsettings fehlt – Hintergrund bitte von Hand wählen: $LT_XML"
        return 1
    fi
    if ! gsettings list-keys "$1" >/dev/null 2>&1; then
        lt_warn "die Einstellungen $1 gibt es hier nicht"
        return 1
    fi
    if [ "$LT_STATISCH" = 1 ]; then lt_datei=$LT_ZIEL/statisch.svg; else lt_datei=$LT_XML; fi
    # Zeigt der Desktop gerade nicht auf Linuxtåg, ist das die neueste eigene Wahl: sie wird das neue „vorher“
    lt_h=$(lt_gs_haupt "$1")
    lt_jetzt=$(gsettings get "$1" "${lt_h#* }" 2>/dev/null) || lt_jetzt=
    if [ -n "$lt_jetzt" ] && ! lt_ist_unseres "$lt_jetzt"; then
        if lt_gemerkt "gsettings$LT_TAB$1$LT_TAB"; then
            lt_info "$1: dein jetziger Hintergrund wird als „vorher“ gemerkt (statt des früher gemerkten)"
        fi
        lt_vergessen "gsettings$LT_TAB$1$LT_TAB"
        [ "$1" = org.cinnamon.desktop.background ] && lt_vergessen "gsettings$LT_TAB$1.slideshow$LT_TAB"
    fi
    lt_ok=0
    case $1 in
        org.mate.background)
            lt_gs_setzen "$1" picture-filename "$(lt_gv "$lt_datei")" || lt_ok=1 ;;
        *)
            lt_u=$(lt_uri "$lt_datei")
            lt_gs_setzen "$1" picture-uri "$(lt_gv "$lt_u")" || lt_ok=1
            lt_gs_setzen "$1" picture-uri-dark "$(lt_gv "$lt_u")" || lt_ok=1    # nur GNOME ≥ 42
            ;;
    esac
    lt_gs_setzen "$1" picture-options "'zoom'" || lt_ok=1
    # Cinnamon hat eine eigene Diashow, die picture-uri nach ein paar Minuten überschreiben würde → ausschalten
    # (wird gemerkt und beim Entfernen wieder eingeschaltet)
    if [ "$1" = org.cinnamon.desktop.background ] &&
       [ "$(gsettings get org.cinnamon.desktop.background.slideshow slideshow-enabled 2>/dev/null)" = true ]; then
        if lt_gs_setzen org.cinnamon.desktop.background.slideshow slideshow-enabled false; then
            lt_info "Cinnamon-eigene Diashow ausgeschaltet (sie würde den Hintergrund sonst wechseln)"
        else
            lt_ok=1
        fi
    fi
    if [ "$LT_STATISCH" = 1 ]; then LT_ART="ruhendes Bild"; else LT_ART="Tageszeit-Diashow"; fi
    LT_ART="$LT_ART, ${LT_B}×${LT_H}"
    [ "$lt_ok" = 0 ] && lt_info "eingestellt: $1 → $lt_datei"
    return "$lt_ok"
}

# ---------------------------------------------------------------------------------------------------- Xfce
lt_xf() { xfconf-query -c xfce4-desktop "$@" 2>/dev/null; }

lt_xf_setzen() {   # Eigenschaft Typ Wert
    if ! lt_gemerkt "xfconf$LT_TAB$1$LT_TAB"; then
        if lt_alt=$(lt_xf -p "$1"); then
            if lt_ist_unseres "$lt_alt"; then
                lt_merken "xfconf$LT_TAB$1$LT_TAB-$LT_TAB" || return 1
            else
                lt_merken "xfconf$LT_TAB$1$LT_TAB$2$LT_TAB$lt_alt" || return 1
            fi
        else
            lt_merken "xfconf$LT_TAB$1$LT_TAB-$LT_TAB" || return 1
        fi
    fi
    lt_xf -p "$1" -n -t "$2" -s "$3"
    [ "$(lt_xf -p "$1")" = "$3" ]
}

lt_xfce_einrichten() {
    LT_ART="nicht eingestellt"
    if ! lt_hat xfconf-query; then
        lt_warn "xfconf-query fehlt"
        return 1
    fi
    # alle Bildschirm/Arbeitsflächen-Pfade, die xfdesktop angelegt hat (…/workspace<N>/last-image)
    lt_pfade=$(lt_xf -l | sed -n 's|^\(/backdrop/screen[0-9]*/monitor[^/]*/workspace[0-9]*\)/last-image$|\1|p')
    if [ -z "$lt_pfade" ]; then
        lt_warn "Xfce hat noch keine Hintergrund-Einstellung gespeichert (oder xfconf ist nicht erreichbar)."
        lt_warn "Bitte einmal „Einstellungen > Schreibtisch“ öffnen, ein Bild wählen und den Befehl erneut ausführen."
        return 1
    fi
    lt_ok=0
    lt_phase=$(lt_aktuelle_phase)
    # Zeile für Zeile (Monitornamen dürfen Leerzeichen enthalten)
    lt_alt_ifs=$IFS
    IFS='
'
    for lt_p in $lt_pfade; do
        IFS=$lt_alt_ifs
        # eigenes Bild des Benutzers auf dieser Arbeitsfläche → das ist ab jetzt „vorher“
        lt_jetzt=$(lt_xf -p "$lt_p/last-image") || lt_jetzt=
        if [ -n "$lt_jetzt" ] && ! lt_ist_unseres "$lt_jetzt"; then
            lt_vergessen "xfconf$LT_TAB$lt_p/"
        fi
        if [ "$LT_STATISCH" = 1 ]; then
            lt_xf_setzen "$lt_p/last-image" string "$LT_ZIEL/statisch.svg" || lt_ok=1
            lt_xf_setzen "$lt_p/backdrop-cycle-enable" bool false || lt_ok=1
        else
            # Bild aus dem Phasen-Ordner; „chronologisch“ (6) wählt danach stündlich nach der Uhrzeit
            lt_xf_setzen "$lt_p/last-image" string "$lt_phase" || lt_ok=1
            lt_xf_setzen "$lt_p/backdrop-cycle-enable" bool true || lt_ok=1
            lt_xf_setzen "$lt_p/backdrop-cycle-period" int 6 || lt_ok=1
            lt_xf_setzen "$lt_p/backdrop-cycle-random-order" bool false || lt_ok=1
        fi
        lt_xf_setzen "$lt_p/image-style" int 5 || lt_ok=1      # 5 = gezoomt
    done
    IFS=$lt_alt_ifs
    if [ "$LT_STATISCH" = 1 ]; then LT_ART="ruhendes Bild"; else LT_ART="Tageszeit (Wechsel alle 2 Stunden)"; fi
    LT_ART="$LT_ART, ${LT_B}×${LT_H}"
    if [ "$lt_ok" = 0 ]; then
        lt_info "eingestellt: Xfce ($(printf '%s\n' "$lt_pfade" | wc -l | tr -d ' ') Bildschirm/Arbeitsfläche(n))"
    else
        lt_warn "Xfce: nicht alle Einstellungen haben gegriffen"
    fi
    return "$lt_ok"
}

# ---------------------------------------------------------------------------------------------------- LXDE / LXQt
# Ini-Schlüssel lesen/setzen (nur in der angegebenen [Gruppe]; leere Gruppe = ganze Datei)
lt_ini_lesen() {   # Datei Gruppe Schlüssel
    awk -v g="$2" -v k="$3" '
        /^\[/ { drin = (g == "" || $0 == "[" g "]"); next }
        drin && index($0, k "=") == 1 { print substr($0, length(k) + 2); exit }
    ' "$1" 2>/dev/null
}

# Schreibt durch einen symbolischen Link hindurch (cat > Datei statt mv), damit z. B. eine Datei aus einem
# dotfiles-Repository ein Link bleibt.
lt_ini_setzen() {   # Datei Gruppe Schlüssel Wert (leerer Wert + „-“ als 5. Argument = Zeile löschen)
    awk -v g="$2" -v k="$3" -v w="$4" -v weg="${5:-}" '
        function raus() { if (drin && !fertig && weg != "-") { print k "=" w; fertig = 1 } }
        /^\[/ { raus(); drin = (g == "" || $0 == "[" g "]"); if (drin) gesehen = 1; print; next }
        drin && index($0, k "=") == 1 { if (!fertig && weg != "-") { print k "=" w; fertig = 1 } ; next }
        { print }
        END { if (!gesehen && g != "") { print "[" g "]"; drin = 1 } ; if (g == "") drin = 1; raus() }
    ' "$1" > "$1.lt-neu" && cat "$1.lt-neu" > "$1"
    lt_rc=$?
    rm -f "$1.lt-neu"
    return "$lt_rc"
}

lt_laeuft() { lt_hat pgrep && pgrep -u "$(id -u)" -x "$1" >/dev/null 2>&1; }

# pcmanfm-Profil (Ordner unter ~/.config/pcmanfm/ und /etc/xdg/pcmanfm/): Raspberry Pi OS nutzt „LXDE-pi“
lt_lxde_profil() {
    case ${XDG_CURRENT_DESKTOP:-}:${DESKTOP_SESSION:-} in
        *[Ll][Xx][Dd][Ee]-[Pp][Ii]*) echo LXDE-pi ;;
        *) echo LXDE ;;
    esac
}

# Einstellungsdateien von pcmanfm, eine je Zeile (Pfade dürfen Leerzeichen enthalten)
lt_lxde_dateien() {
    for lt_c in "$LT_CONFIG_HOME"/pcmanfm/*/desktop-items-*.conf; do
        [ -f "$lt_c" ] && printf '%s\n' "$lt_c"
    done
    return 0
}

# Bild, das pcmanfm aus dieser Datei zeigt: wallpaper= oder – bei wallpaper_common=0 (Bild je Bildschirm) – wallpaper0=
lt_lxde_bild() {   # Datei
    if [ "$(lt_ini_lesen "$1" '*' wallpaper_common)" = 0 ]; then
        lt_ini_lesen "$1" '*' wallpaper0
    else
        lt_ini_lesen "$1" '*' wallpaper
    fi
}

# Zeigt irgendein wallpaper…= der Datei auf unsere Bilder?
lt_lxde_unseres() {   # Datei
    lt_werte=$(sed -n 's/^wallpaper[0-9]*=//p' "$1" 2>/dev/null)
    while IFS= read -r lt_w; do
        lt_ist_unseres "$lt_w" && return 0
    done <<LT_ENDE
$lt_werte
LT_ENDE
    return 1
}

# alle wallpaper…=-Zeilen, die auf uns zeigen, entfernen und einfarbig stellen (Notlösung ohne Sicherung)
lt_lxde_einfarbig() {   # Datei
    # shellcheck disable=SC2013 # Schlüsselnamen (wallpaper, wallpaper0 …) enthalten keine Leerzeichen
    for lt_k in $(sed -n 's/^\(wallpaper[0-9]*\)=.*/\1/p' "$1"); do
        lt_ist_unseres "$(lt_ini_lesen "$1" '*' "$lt_k")" && lt_ini_setzen "$1" '*' "$lt_k" '' -
    done
    lt_ini_setzen "$1" '*' wallpaper_mode color
}

# gehört die Datei zum gerade laufenden Profil? (nur dann darf pcmanfm --set-wallpaper sie betreffen)
lt_lxde_laufendes_profil() {   # Datei
    case $1 in "$LT_CONFIG_HOME/pcmanfm/$(lt_lxde_profil)/"*) return 0 ;; esac
    return 1
}

lt_lxde_einrichten() {
    lt_bild=$LT_BILD
    LT_ART="ruhendes Bild ($LT_BILD_TEXT)"
    lt_dateien_lx=$(lt_lxde_dateien)
    lt_pcm=0
    lt_laeuft pcmanfm && lt_pcm=1
    if [ -z "$lt_dateien_lx" ] && [ "$lt_pcm" = 0 ]; then
        lt_warn "pcmanfm (Schreibtisch von LXDE) läuft nicht und hat keine Einstellungen – Bild bitte selbst wählen:"
        lt_warn "  $lt_bild"
        return 1
    fi
    # Merken (nur beim ersten Mal): je Datei eine Sicherungskopie im Zustandsordner. Gab es keine eigene Datei,
    # „-“ + Profil: Beim Entfernen werden die Dateien, die erst durch uns entstanden sind, wieder gelöscht – dann
    # gilt wieder der Standard der Distribution (z. B. das Bild von Raspberry Pi OS).
    if ! lt_gemerkt "lxde$LT_TAB"; then
        mkdir -p "$LT_ZUSTAND" || return 1
        if [ -z "$lt_dateien_lx" ]; then
            lt_merken "lxde$LT_TAB-$LT_TAB$(lt_lxde_profil)" || return 1
        else
            lt_nr=0
            while IFS= read -r lt_c; do
                [ -n "$lt_c" ] || continue
                lt_nr=$((lt_nr + 1))
                lt_kopie=$LT_ZUSTAND/lxde-$lt_nr.conf
                cat "$lt_c" > "$lt_kopie" || return 1
                # Rest eines älteren Linuxtåg-Hintergrunds in der Sicherung: einfarbig statt eines gelöschten Bilds
                lt_lxde_unseres "$lt_kopie" && lt_lxde_einfarbig "$lt_kopie"
                lt_merken "lxde$LT_TAB$lt_c$LT_TAB${lt_kopie##*/}" || return 1
            done <<LT_ENDE
$lt_dateien_lx
LT_ENDE
        fi
    fi
    # Dateien setzen. wallpaper_common=0: pcmanfm nimmt wallpaper0, wallpaper1 … (je Bildschirm)
    lt_einzeln=0
    while IFS= read -r lt_c; do
        [ -n "$lt_c" ] || continue
        if [ "$(lt_ini_lesen "$lt_c" '*' wallpaper_common)" = 0 ]; then
            lt_lxde_laufendes_profil "$lt_c" && lt_einzeln=1
            for lt_k in $(sed -n 's/^\(wallpaper[0-9][0-9]*\)=.*/\1/p' "$lt_c") wallpaper0; do
                lt_ini_setzen "$lt_c" '*' "$lt_k" "$lt_bild" || return 1
            done
        fi
        lt_ini_setzen "$lt_c" '*' wallpaper "$lt_bild" || return 1
        lt_ini_setzen "$lt_c" '*' wallpaper_mode crop || return 1
    done <<LT_ENDE
$lt_dateien_lx
LT_ENDE
    lt_spaeter=0
    if [ "$lt_pcm" = 1 ]; then
        if [ "$lt_einzeln" = 1 ]; then
            # pcmanfm 1.3 stürzt beim zweiten --set-wallpaper mit wallpaper_common=0 ab und schreibt seine eigene
            # Sicht in die Datei – deshalb hier nur die Datei
            lt_spaeter=1
        elif pcmanfm --set-wallpaper="$lt_bild" --wallpaper-mode=crop >/dev/null 2>&1; then
            sleep 1      # pcmanfm schreibt seine Datei selbst (bei einem frischen Profil legt es sie erst an)
        else
            lt_warn "pcmanfm hat das Bild nicht übernommen – es gilt nach dem nächsten Anmelden"
            lt_spaeter=1
        fi
    else
        lt_spaeter=1
    fi
    lt_ok=0
    lt_dateien_lx=$(lt_lxde_dateien)
    [ -n "$lt_dateien_lx" ] || lt_ok=1
    while IFS= read -r lt_c; do
        [ -n "$lt_c" ] || continue
        if [ "$(lt_lxde_bild "$lt_c")" != "$lt_bild" ]; then
            lt_warn "LXDE: $lt_c zeigt nicht auf das Bild"
            lt_ok=1
        fi
    done <<LT_ENDE
$lt_dateien_lx
LT_ENDE
    if [ "$lt_ok" = 0 ]; then
        lt_info "eingestellt: LXDE (pcmanfm) → $lt_bild"
        [ "$lt_spaeter" = 1 ] && lt_info "pcmanfm zeigt es ab dem nächsten Anmelden (im laufenden Betrieb nicht sicher umstellbar)"
    fi
    return "$lt_ok"
}

lt_lxqt_datei() { printf '%s\n' "$LT_CONFIG_HOME/pcmanfm-qt/lxqt/settings.conf"; }

lt_lxqt_einrichten() {
    lt_bild=$LT_BILD
    LT_ART="ruhendes Bild ($LT_BILD_TEXT)"
    lt_c=$(lt_lxqt_datei)
    if ! lt_gemerkt "lxqt$LT_TAB"; then
        lt_w=
        lt_m=
        if [ -f "$lt_c" ]; then
            lt_w=$(lt_ini_lesen "$lt_c" Desktop Wallpaper)
            lt_m=$(lt_ini_lesen "$lt_c" Desktop WallpaperMode)
        fi
        lt_ist_unseres "$lt_w" && lt_w=
        if [ -n "$lt_w" ]; then
            lt_merken "lxqt$LT_TAB$lt_w$LT_TAB$lt_m" || return 1
        else
            lt_merken "lxqt$LT_TAB-$LT_TAB" || return 1
        fi
    fi
    if lt_laeuft pcmanfm-qt && lt_hat pcmanfm-qt; then
        pcmanfm-qt --set-wallpaper="$lt_bild" --wallpaper-mode=zoom >/dev/null 2>&1
    fi
    # Datei immer selbst nachziehen (gilt auch, wenn pcmanfm-qt gerade nicht läuft)
    mkdir -p "${lt_c%/*}" || return 1
    [ -f "$lt_c" ] || : > "$lt_c"
    lt_ini_setzen "$lt_c" Desktop Wallpaper "$lt_bild"
    lt_ini_setzen "$lt_c" Desktop WallpaperMode zoom
    if [ "$(lt_ini_lesen "$lt_c" Desktop Wallpaper)" = "$lt_bild" ]; then
        lt_info "eingestellt: LXQt (pcmanfm-qt) → $lt_bild"
        lt_laeuft pcmanfm-qt || lt_info "pcmanfm-qt läuft gerade nicht – das Bild erscheint beim nächsten Anmelden"
        return 0
    fi
    lt_warn "LXQt: Einstellung ließ sich nicht schreiben ($lt_c)"
    return 1
}

# ---------------------------------------------------------------------------------------------------- KDE Plasma
lt_plasma_version() {
    if [ -n "$LT_PLASMA_VORGABE" ]; then echo "$LT_PLASMA_VORGABE"; return; fi
    case ${KDE_SESSION_VERSION:-} in 5|6) echo "$KDE_SESSION_VERSION"; return ;; esac
    lt_v=$(plasmashell --version 2>/dev/null | sed -n 's/[^0-9]*\([0-9][0-9]*\).*/\1/p' | head -n 1)
    case $lt_v in 5|6) echo "$lt_v"; return ;; esac
    if lt_hat kpackagetool6; then echo 6; return; fi
    if lt_hat kpackagetool5; then echo 5; return; fi
    echo 6
}

# Kandidaten für qdbus (Debian/Ubuntu: /usr/lib/qt6/bin/qdbus ohne qdbus6 im PATH)
lt_qdbus_liste() {
    for lt_b in qdbus6 qdbus-qt6; do command -v "$lt_b" 2>/dev/null; done
    lt_b=$(qtpaths6 --query QT_INSTALL_BINS 2>/dev/null) && [ -n "$lt_b" ] && echo "$lt_b/qdbus"
    for lt_b in /usr/lib/qt6/bin/qdbus /usr/lib64/qt6/bin/qdbus /usr/lib/x86_64-linux-gnu/qt6/bin/qdbus \
                /usr/lib/aarch64-linux-gnu/qt6/bin/qdbus; do echo "$lt_b"; done
    for lt_b in qdbus qdbus-qt5; do command -v "$lt_b" 2>/dev/null; done
    for lt_b in /usr/lib/qt5/bin/qdbus /usr/lib64/qt5/bin/qdbus /usr/lib/x86_64-linux-gnu/qt5/bin/qdbus; do echo "$lt_b"; done
}

# JavaScript an plasmashell (org.kde.PlasmaShell.evaluateScript); Ausgabe von print() → LT_ANTWORT.
# Die Skripte enthalten nur geprüfte Werte (Plugin-Namen, Zahlen, Motiv) – siehe lt_js_text.
lt_plasma() {
    LT_ANTWORT=
    LT_PLASMA_FEHLER=
    LT_PLASMA_ABGELEHNT=0
    lt_gesehen=' '
    for lt_q in $(lt_qdbus_liste); do
        case $lt_gesehen in *" $lt_q "*) continue ;; esac
        lt_gesehen="$lt_gesehen$lt_q "
        [ -x "$lt_q" ] || continue
        if LT_ANTWORT=$("$lt_q" org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell.evaluateScript "$1" 2>&1); then
            return 0
        fi
        lt_plasma_fehler "$lt_q: $LT_ANTWORT"
    done
    if lt_hat busctl; then
        if LT_ANTWORT=$(busctl --user call org.kde.plasmashell /PlasmaShell org.kde.PlasmaShell evaluateScript s "$1" 2>&1); then
            return 0
        fi
        lt_plasma_fehler "busctl: $LT_ANTWORT"
    fi
    if lt_hat dbus-send; then
        if LT_ANTWORT=$(dbus-send --session --print-reply=literal --dest=org.kde.plasmashell /PlasmaShell \
                org.kde.PlasmaShell.evaluateScript "string:$1" 2>&1); then
            return 0
        fi
        lt_plasma_fehler "dbus-send: $LT_ANTWORT"
    fi
    if lt_hat gdbus; then
        if LT_ANTWORT=$(gdbus call --session --dest org.kde.plasmashell --object-path /PlasmaShell \
                --method org.kde.PlasmaShell.evaluateScript "$(lt_gv "$1")" 2>&1); then
            return 0
        fi
        lt_plasma_fehler "gdbus: $LT_ANTWORT"
    fi
    LT_PLASMA_FEHLER=${LT_PLASMA_FEHLER:-"kein D-Bus-Programm gefunden (qdbus, busctl, dbus-send oder gdbus)"}
    return 1
}

# Fehler merken (der erste ist der aussagekräftige). Antwortet Plasma selbst mit einem Fehler (org.kde.PlasmaShell.Error,
# z. B. „Widgets are locked“ bei gesperrten Widgets oder Kiosk-Richtlinien), ist es erreichbar, lehnt das Skript aber ab.
lt_plasma_fehler() {
    LT_PLASMA_FEHLER=${LT_PLASMA_FEHLER:-$1}
    case $1 in
        *PlasmaShell.Error*|*[Ll]ocked*|*[Gg]esperrt*|*[Kk]iosk*|*immutable*) LT_PLASMA_ABGELEHNT=1 ;;
    esac
}

# Text als JavaScript-Zeichenkette (\ und " maskiert, Steuerzeichen entfernt)
lt_js_text() { printf '"%s"' "$(printf '%s' "$1" | tr -d '\000-\037' | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')"; }

# Arbeitsflächen und ihr Plugin → LT_FLAECHEN („id=plugin id=plugin …“)
lt_plasma_lesen() {
    lt_plasma 'var ds = desktops(); var a = []; for (var i = 0; i < ds.length; i++) a.push(ds[i].id + "=" + ds[i].wallpaperPlugin); print("FLAECHEN " + a.join(" ") + " ENDE");' || return 1
    case $LT_ANTWORT in *FLAECHEN*ENDE*) ;; *) LT_PLASMA_FEHLER="unerwartete Antwort: $LT_ANTWORT"; return 1 ;; esac
    LT_FLAECHEN=$(printf '%s' "$LT_ANTWORT" | tr '\n' ' ' | sed -n 's/.*FLAECHEN \(.*\) ENDE.*/\1/p')
    return 0
}

lt_kde_hand() {
    [ "${LT_PLASMA_ABGELEHNT:-0}" = 1 ] && lt_warn "Plasma lehnt Skripte ab – meist sind die Widgets gesperrt oder eine Richtlinie des Administrators verbietet es."
    lt_warn "Von Hand: Rechtsklick auf die Arbeitsfläche → „Arbeitsfläche und Hintergrund einrichten …“ →"
    lt_warn "Hintergrundbildtyp „${1:-Linuxtåg 2026}“ wählen → Anwenden. (Sind die Widgets gesperrt, vorher entsperren.)"
}

# Plugin-Paket für diese Plasma-Version vorbereiten und installieren → 0 = installiert/aktuell
lt_kde_plugin() {
    lt_pv=$1
    lt_quelle=$LT_TMP/plugin/$LT_KDE_ID
    mkdir -p "$LT_TMP/plugin" && cp -R "$LT_PAKET/kde/$LT_KDE_ID" "$LT_TMP/plugin/" || return 1
    if [ "$lt_pv" = 5 ]; then
        # Plasma 5: Wurzel Item statt WallpaperItem, Kirigami-2-Importe, ServiceTypes statt KPackageStructure
        cp "$lt_quelle/plasma5/metadata.json" "$lt_quelle/metadata.json" || return 1
        cp "$lt_quelle/plasma5/main.qml" "$lt_quelle/plasma5/config.qml" "$lt_quelle/plasma5/Akkuwaechter.qml" \
           "$lt_quelle/contents/ui/" || return 1
    fi
    rm -rf "$lt_quelle/plasma5"
    lt_kennzeichen="version=$LT_VERSION motiv=$LT_MOTIV plasma=$lt_pv"
    printf '%s\n' "$lt_kennzeichen" > "$lt_quelle/contents/linuxtag-paket.txt"
    if [ -f "$LT_KDE_ZIEL/contents/linuxtag-paket.txt" ] && [ "$(cat "$LT_KDE_ZIEL/contents/linuxtag-paket.txt")" = "$lt_kennzeichen" ]; then
        lt_info "Plasma-Plugin ist schon aktuell ($lt_kennzeichen)"
        LT_KDE_NEU=0
        return 0
    fi
    LT_KDE_NEU=1
    [ -f "$LT_KDE_ZIEL/metadata.json" ] && LT_KDE_NEU=2
    lt_kpt=$(command -v "kpackagetool$lt_pv" 2>/dev/null || true)
    if [ -n "$lt_kpt" ]; then
        if [ -f "$LT_KDE_ZIEL/metadata.json" ]; then
            "$lt_kpt" --type Plasma/Wallpaper --upgrade "$lt_quelle" >/dev/null 2>&1
        else
            "$lt_kpt" --type Plasma/Wallpaper --install "$lt_quelle" >/dev/null 2>&1
        fi
    fi
    # kpackagetool meldet Fehler nicht immer im Rückgabewert → Ergebnis prüfen; sonst selbst kopieren
    # (Plasma findet Hintergrund-Plugins auch einfach in diesem Ordner)
    if [ ! -f "$LT_KDE_ZIEL/contents/linuxtag-paket.txt" ] || [ "$(cat "$LT_KDE_ZIEL/contents/linuxtag-paket.txt")" != "$lt_kennzeichen" ]; then
        rm -rf "$LT_KDE_ZIEL.lt-neu"
        mkdir -p "${LT_KDE_ZIEL%/*}" && cp -R "$lt_quelle" "$LT_KDE_ZIEL.lt-neu" || return 1
        rm -rf "$LT_KDE_ZIEL"
        mv "$LT_KDE_ZIEL.lt-neu" "$LT_KDE_ZIEL" || return 1
    fi
    [ "$(cat "$LT_KDE_ZIEL/contents/linuxtag-paket.txt" 2>/dev/null)" = "$lt_kennzeichen" ] || return 1
    lt_info "Plasma-Plugin installiert: $LT_KDE_ZIEL (Plasma $lt_pv)"
    return 0
}

# Ohne Grafikkarte (oder mit Software-OpenGL wie llvmpipe) kostet die Drehung viel Rechenzeit → ruhend
lt_ohne_grafikkarte() {
    if lt_hat glxinfo; then
        if glxinfo -B 2>/dev/null | grep -qi 'renderer string:.*\(llvmpipe\|softpipe\|swrast\|software\)'; then
            return 0
        fi
        glxinfo -B >/dev/null 2>&1 && return 1
    fi
    for lt_r in /dev/dri/renderD*; do
        [ -e "$lt_r" ] && return 1
    done
    return 0
}

lt_kde_einrichten() {
    lt_pv=$(lt_plasma_version)
    LT_ART="Plasma-Plugin, nicht eingeschaltet"
    lt_kde_plugin "$lt_pv" || { lt_fehler "Plasma-Plugin ließ sich nicht installieren ($LT_KDE_ZIEL)"; return 1; }
    lt_animation=true
    if [ "$LT_STATISCH" = 1 ]; then
        lt_animation=false
    elif [ "$LT_BEWEGT" = 0 ] && lt_ohne_grafikkarte; then
        lt_animation=false
        lt_info "keine Grafikkarte erkannt (oder nur Software-OpenGL) – der Drahtgitter-Tux steht still, das spart Strom."
        lt_info "Trotzdem drehen lassen: denselben Befehl mit --bewegt"
    fi
    if ! lt_plasma_lesen; then
        if [ "$LT_PLASMA_ABGELEHNT" = 1 ]; then
            lt_warn "Plasma lehnt das Skript ab (${LT_PLASMA_FEHLER:-?}) – das Plugin ist installiert, aber nicht eingeschaltet."
        else
            lt_warn "Plasma ist nicht erreichbar (${LT_PLASMA_FEHLER:-?}) – das Plugin ist installiert, aber nicht eingeschaltet."
            lt_warn "Bitte in der laufenden Plasma-Sitzung noch einmal ausführen, oder:"
        fi
        lt_kde_hand
        return 1
    fi
    # bisherige Plugins merken, nie das eigene. Nutzt eine Arbeitsfläche gerade ein anderes Plugin, ist das die
    # neueste Wahl – sie ersetzt das Gemerkte. Steht sie schon auf unserem Plugin und ist nichts gemerkt (z. B. vom
    # Prototyp eingerichtet), kommt das Plugin aus dessen Merkliste; sonst bleibt es offen (beim Entfernen: Standard).
    lt_alt_datei=$LT_STATE_HOME/linuxtog-hintergrund/kde-vorher.txt
    for lt_paar in $LT_FLAECHEN; do
        lt_id=${lt_paar%%=*}
        lt_pl=${lt_paar#*=}
        case $lt_id in ''|*[!0-9]*) continue ;; esac
        case $lt_pl in ''|*[!A-Za-z0-9._-]*) continue ;; esac
        if [ "$lt_pl" != "$LT_KDE_ID" ]; then
            lt_vergessen "kde$LT_TAB$lt_id$LT_TAB"
            lt_merken "kde$LT_TAB$lt_id$LT_TAB$lt_pl" || return 1
            continue
        fi
        lt_gemerkt "kde$LT_TAB$lt_id$LT_TAB" && continue
        [ -f "$lt_alt_datei" ] || continue
        lt_pl=$(sed -n "s/^$lt_id=\\([A-Za-z0-9._-]*\\)\$/\\1/p" "$lt_alt_datei" | head -n 1)
        if [ -n "$lt_pl" ] && [ "$lt_pl" != "$LT_KDE_ID" ]; then
            lt_merken "kde$LT_TAB$lt_id$LT_TAB$lt_pl" || return 1
        fi
    done
    lt_js="var id = \"$LT_KDE_ID\"; var ds = desktops(); var n = 0;
for (var i = 0; i < ds.length; i++) {
    var d = ds[i];
    d.wallpaperPlugin = id;
    d.currentConfigGroup = [\"Wallpaper\", id, \"General\"];
    d.writeConfig(\"Motiv\", $(lt_js_text "$LT_MOTIV"));
    d.writeConfig(\"Animation\", $lt_animation);
    n++;
}
print(\"GESETZT \" + n + \" ENDE\");"
    if ! lt_plasma "$lt_js"; then
        lt_warn "Einschalten über D-Bus ging nicht: ${LT_PLASMA_FEHLER:-?}"
        lt_kde_hand
        return 1
    fi
    case $LT_ANTWORT in
        *GESETZT*ENDE*) ;;
        *) lt_warn "Plasma: unerwartete Antwort beim Einschalten: $LT_ANTWORT"; lt_kde_hand; return 1 ;;
    esac
    # nachprüfen: alle Arbeitsflächen auf dem Plugin?
    lt_plasma_lesen || { lt_warn "Plasma antwortet nicht mehr"; return 1; }
    lt_ok=0
    lt_anzahl=0
    for lt_paar in $LT_FLAECHEN; do
        lt_anzahl=$((lt_anzahl + 1))
        [ "${lt_paar#*=}" = "$LT_KDE_ID" ] || lt_ok=1
    done
    if [ "$lt_ok" != 0 ] || [ "$lt_anzahl" = 0 ]; then
        lt_warn "Plasma hat das Plugin nicht auf allen Arbeitsflächen übernommen ($LT_FLAECHEN)"
        lt_kde_hand
        return 1
    fi
    if [ "$lt_animation" = true ]; then
        LT_ART="bewegt"
    elif [ "$LT_STATISCH" = 1 ]; then
        LT_ART="ruhend (--statisch)"
    else
        LT_ART="ruhend (keine Grafikkarte erkannt; mit --bewegt einschaltbar)"
    fi
    LT_ART="$LT_ART, Plasma $lt_pv"
    lt_info "eingeschaltet: Plasma $lt_pv, $lt_anzahl Arbeitsfläche(n), Motiv $LT_MOTIV$([ "$lt_animation" = false ] && echo ', ruhend')"
    if [ "${LT_KDE_NEU:-0}" = 2 ]; then
        lt_info "Plugin wurde aktualisiert. Zeigt Plasma noch die alte Fassung, hilft ein Neustart von Plasma:"
        lt_info "  systemctl --user restart plasma-plasmashell.service   (oder ab- und wieder anmelden)"
    fi
    return 0
}

# ---------------------------------------------------------------------------------------------------- Andere
lt_anleitung() {
    lt_bild=$LT_BILD
    LT_ART="nur Bilder + Anleitung"
    cat <<EOF

Diese Umgebung (${LT_DESKTOP_NAME:-unbekannt}) stelle ich nicht selbst um – an deiner Einstellung ändert sich nichts.
Die Bilder liegen hier:
  ruhendes Bild ($LT_BILD_TEXT):
    $lt_bild
  12 Tageszeit-Bilder als SVG (00–11 = 0–24 Uhr, für ${LT_B}×${LT_H}):
    $LT_ZIEL/phasen/

  sway      in ~/.config/sway/config:        output * bg "$lt_bild" fill
  Hyprland  in ~/.config/hypr/hyprpaper.conf:
              preload = $lt_bild
              wallpaper = ,$lt_bild
  i3 / X11  feh --bg-fill "$lt_bild"   (z. B. in ~/.config/i3/config: exec --no-startup-id feh --bg-fill …)
  COSMIC    Einstellungen > Desktop > Hintergrund > Bild hinzufügen: $lt_bild
EOF
}

# ---------------------------------------------------------------------------------------------------- Einrichten
lt_einrichten() {
    [ -n "$LT_MOTIV" ] || LT_MOTIV=gitterraum
    if ! lt_desktop_erkennen; then
        lt_fehler "Desktop nicht erkannt (XDG_CURRENT_DESKTOP=${XDG_CURRENT_DESKTOP:-leer}). Es wurde nichts verändert."
        lt_sag "Bitte in der grafischen Sitzung ausführen oder den Desktop vorgeben, z. B. --desktop=gnome"
        lt_sag "(kde, gnome, cinnamon, mate, xfce, lxde, lxqt, andere – „andere“ legt nur die Bilder ab)."
        return 3
    fi
    lt_sag "$LT_TITEL – lebendiger Hintergrund (BETA $LT_VERSION): Motiv $LT_MOTIV, Desktop $(lt_desktop_text "$LT_DESKTOP")"
    lt_bildschirm
    lt_paket_holen || return 1
    lt_dateien || { lt_fehler "Bilder ließen sich nicht ablegen – nichts wurde verändert"; return 1; }
    LT_XML=$LT_ZIEL/tageszeit.xml
    # Eintrag für die Hintergrund-Auswahl nur für GNOME, Cinnamon und MATE
    case $LT_DESKTOP in
        gnome|cinnamon|mate) lt_auswahl_eintrag || lt_warn "Eintrag für die Hintergrund-Auswahl ließ sich nicht schreiben ($LT_PROPS)" ;;
    esac
    [ "$LT_DESKTOP" = kde ] && lt_info "Plasma setzt das Motiv selbst für jede Bildschirmform zusammen (auch nach dem Drehen)."
    LT_ART=
    lt_erg=0
    case $LT_DESKTOP in
        gnome)    lt_gnome_einrichten org.gnome.desktop.background || lt_erg=4 ;;
        cinnamon) lt_gnome_einrichten org.cinnamon.desktop.background || lt_erg=4 ;;
        mate)     lt_gnome_einrichten org.mate.background || lt_erg=4 ;;
        xfce)     lt_xfce_einrichten || lt_erg=4 ;;
        kde)      lt_kde_einrichten || lt_erg=4 ;;
        lxde)     lt_lxde_einrichten || lt_erg=4 ;;
        lxqt)     lt_lxqt_einrichten || lt_erg=4 ;;
        anleitung) lt_anleitung ;;
    esac
    lt_installiert_schreiben "$lt_erg" || lt_warn "Merkliste ließ sich nicht schreiben ($LT_INSTALLIERT)"
    lt_entfernen_hinweis=
    if [ -f "$LT_DATEN/hintergrund.sh" ]; then
        lt_entfernen_hinweis="sh $(lt_zitat "$LT_DATEN/hintergrund.sh") --entfernen   oder"
    fi
    if [ "$lt_erg" = 0 ]; then
        # anderes Motiv vorher? Dessen Bilder werden nicht mehr gebraucht (nur, wenn kein anderer Desktop sie nutzt)
        case $(lt_installiert_lesen familien) in
            "$LT_DESKTOP") lt_alte_motive_weg ;;
        esac
        lt_sag ""
        lt_sag "Neuer Bildschirm oder gedreht? Denselben Befehl noch einmal ausführen – das Motiv wird neu zusammengesetzt."
        lt_sag "Fertig. Wieder entfernen:"
        [ -n "$lt_entfernen_hinweis" ] && lt_sag "  $lt_entfernen_hinweis"
        lt_sag "  curl -fsSL https://carinthianlinuxday.at/hintergrund.sh | sh -s -- --entfernen"
        return 0
    fi
    lt_sag ""
    lt_sag "Die Bilder sind abgelegt ($LT_ZIEL), aber der Hintergrund ist nicht (vollständig) eingestellt – siehe oben."
    lt_sag "Das ruhende Bild kannst du auch selbst wählen: ${LT_BILD:-$LT_ZIEL/statisch.svg}"
    return 4
}

# ---------------------------------------------------------------------------------------------------- Entfernen
# Grundsatz: Eine Einstellung wird nur zurückgestellt, solange sie noch auf unsere Dateien zeigt. Hat jemand nach dem
# Einrichten selbst einen anderen Hintergrund gewählt, bleibt der. Ergebnis der *_zurueck-Funktionen:
#   0 zurückgestellt (nachgeprüft) · 1 ging nicht · 2 war schon so / unverändert · 3 inzwischen anders gewählt –
#   gelassen · 5 auf Standard gesetzt (das Vorherige war unbekannt) · 6 Nebeneinstellung zurück, eigenes Bild bleibt
# Zähler: LT_WIEDER (zurückgestellt), LT_GELASSEN (anders gewählt), LT_ERSATZ (Notlösung: Standard/einfarbig),
# LT_SPAETER (zurückgestellt, sichtbar erst nach dem nächsten Anmelden). Gelöscht wird erst, wenn nichts mehr auf
# unsere Dateien zeigen kann (nachgeprüft) – sonst bleibt alles, Rückgabe 4.

# Hauptschlüssel eines Schemas (zeigt aufs Bild)
lt_gs_haupt() {   # Schema → Schema Schlüssel
    case $1 in
        org.mate.background)                      echo "org.mate.background picture-filename" ;;
        org.cinnamon.desktop.background.slideshow) echo "org.cinnamon.desktop.background picture-uri" ;;
        *)                                        echo "$1 picture-uri" ;;
    esac
}

lt_gs_zurueck() {   # Schema Schlüssel Wert   (Rückgabe wie oben, dazu 5 = auf Standard gesetzt, Vorheriges unbekannt)
    lt_hat gsettings || return 1
    lt_gs_schluessel "$1" "$2" || return 2
    lt_jetzt=$(gsettings get "$1" "$2" 2>/dev/null) || return 1
    lt_unser=1
    case $2 in
        picture-uri|picture-uri-dark|picture-filename)
            lt_ist_unseres "$lt_jetzt" || lt_unser=0 ;;
        *)  # Nebenschlüssel (Zoom, Cinnamon-Diashow): nur, wenn das Bild vor dem Entfernen noch unseres war
            lt_haupt=$(lt_gs_haupt "$1")
            case $LT_GS_UNSER in *" ${lt_haupt%% *} "*) ;; *) lt_unser=0 ;; esac ;;
    esac
    if [ "$lt_unser" = 0 ]; then
        # nicht (mehr) unseres: unverändert, wenn es noch so ist wie gemerkt (z. B. weil das Einrichten nie etwas
        # setzen konnte) – sonst hat der Benutzer selbst gewählt
        [ "$lt_jetzt" = "$3" ] && return 2
        case $3 in @standard|@ersatz) lt_gs_standard "$1" "$2" && return 2 ;; esac
        return 3
    fi
    if [ "$3" = @standard ] || [ "$3" = @ersatz ]; then
        gsettings reset "$1" "$2" 2>/dev/null || return 1
        lt_neu=$(gsettings get "$1" "$2" 2>/dev/null) || return 1
        lt_ist_unseres "$lt_neu" && return 1
        [ "$3" = @ersatz ] && return 5
        [ "$lt_neu" = "$lt_jetzt" ] && return 2
        return 0
    fi
    [ "$lt_jetzt" = "$3" ] && return 2
    gsettings set "$1" "$2" "$3" 2>/dev/null || return 1
    [ "$(gsettings get "$1" "$2" 2>/dev/null)" = "$3" ]
}

lt_xf_erreichbar() { lt_hat xfconf-query && xfconf-query -c xfce4-desktop -l >/dev/null 2>&1; }

# Betrifft das Entfernen Xfce? Nur dann xfconf fragen – sonst startet xfconf-query über D-Bus den xfconfd und legt
# ~/.config/xfce4/xfconf/ an, auch wo Xfce nie benutzt wurde. Ohne beide Merklisten: wenn Xfce läuft.
lt_xf_relevant() {
    lt_hat xfconf-query || return 1
    case " $(lt_installiert_lesen familien 2>/dev/null) " in *" xfce "*) return 0 ;; esac
    [ -f "$LT_VORHER" ] && grep -q "^xfconf$LT_TAB" "$LT_VORHER" && return 0
    if [ ! -f "$LT_INSTALLIERT" ] && [ ! -f "$LT_VORHER" ]; then
        case ${XDG_CURRENT_DESKTOP:-} in *[Xx][Ff][Cc][Ee]*) return 0 ;; esac
        lt_laeuft xfconfd && return 0
    fi
    return 1
}

# Vor dem Zurückstellen festhalten, wo das Bild noch unseres ist (danach ist es das ja nicht mehr):
# LT_GS_UNSER = „ Schema Schema … “, LT_XF_UNSER = Xfce-Pfade …/workspaceN, je Zeile
lt_unsere_merken() {
    LT_GS_UNSER=' '
    if lt_hat gsettings; then
        for lt_s in org.gnome.desktop.background org.cinnamon.desktop.background org.mate.background; do
            lt_h=$(lt_gs_haupt "$lt_s")
            lt_gs_schluessel "$lt_s" "${lt_h#* }" || continue
            lt_jetzt=$(gsettings get "$lt_s" "${lt_h#* }" 2>/dev/null) || continue
            lt_ist_unseres "$lt_jetzt" && LT_GS_UNSER="$LT_GS_UNSER$lt_s "
        done
    fi
    LT_XF_UNSER='
'
    # Arbeitsflächen mit eigenem Bild, auf denen aber noch unser Bildwechsel („chronologisch“, 2 h) eingeschaltet ist
    LT_XF_ZYKLUS='
'
    if lt_xf_relevant && lt_xf_erreichbar; then
        lt_liste=$(lt_xf -l | grep '/last-image$')
        while IFS= read -r lt_p; do
            [ -n "$lt_p" ] || continue
            lt_w=${lt_p%/*}
            if lt_ist_unseres "$(lt_xf -p "$lt_p")"; then
                LT_XF_UNSER="$LT_XF_UNSER$lt_w
"
            elif [ "$(lt_xf -p "$lt_w/backdrop-cycle-enable")" = true ] && [ "$(lt_xf -p "$lt_w/backdrop-cycle-period")" = 6 ] &&
                 [ "$(lt_xf -p "$lt_w/backdrop-cycle-random-order")" = false ]; then
                LT_XF_ZYKLUS="$LT_XF_ZYKLUS$lt_w
"
            fi
        done <<LT_ENDE
$lt_liste
LT_ENDE
    fi
}

lt_xf_zurueck() {   # Eigenschaft Typ Wert   (Rückgabe wie oben, dazu 6 = Bildwechsel zurückgestellt, Bild bleibt)
    lt_xf_erreichbar || return 1
    # gehört zu einem Bildschirm, auf dem inzwischen ein anderes Bild gewählt wurde? Dann bleibt das Bild – aber unser
    # Bildwechsel (chronologisch alle 2 h) muss weg, sonst wechselte xfdesktop weiter durch den Ordner des neuen Bilds
    case $LT_XF_UNSER in *"
${1%/*}
"*) ;; *)
        case ${1##*/} in
            backdrop-cycle-enable|backdrop-cycle-period|backdrop-cycle-random-order) ;;
            *) return 3 ;;
        esac
        case $LT_XF_ZYKLUS in *"
${1%/*}
"*) ;; *) return 3 ;; esac
        if [ "$2" = - ]; then
            lt_xf -p "$1" -r
            lt_xf -p "$1" >/dev/null && return 1
        else
            lt_xf -p "$1" -n -t "$2" -s "$3"
            [ "$(lt_xf -p "$1")" = "$3" ] || return 1
        fi
        return 6 ;;
    esac
    if [ "$2" = - ]; then
        lt_xf -p "$1" >/dev/null || return 2
        lt_xf -p "$1" -r
        lt_xf_erreichbar && ! lt_xf -p "$1" >/dev/null
    else
        [ "$(lt_xf -p "$1")" = "$3" ] && return 2
        lt_xf -p "$1" -n -t "$2" -s "$3"
        [ "$(lt_xf -p "$1")" = "$3" ]
    fi
}

# Plasma zurückstellen: jede Arbeitsfläche mit unserem Plugin bekommt ihr gemerktes Plugin (sonst org.kde.image)
lt_kde_zurueck() {
    lt_zuordnung=
    if [ -f "$LT_VORHER" ]; then
        while IFS= read -r lt_z; do
            lt_felder "$lt_z"
            [ "$LT_F1" = kde ] || continue
            case $LT_F2 in ''|*[!0-9]*) continue ;; esac
            case $LT_F3 in ''|*[!A-Za-z0-9._-]*) continue ;; esac
            [ "$LT_F3" = "$LT_KDE_ID" ] && continue
            lt_zuordnung="$lt_zuordnung\"$LT_F2\": \"$LT_F3\", "
        done < "$LT_VORHER"
    fi
    # Merkliste des Prototyps (linuxtog-hintergrund/kde-vorher.txt: id=plugin), falls vorhanden
    lt_alt_datei=$LT_STATE_HOME/linuxtog-hintergrund/kde-vorher.txt
    if [ -z "$lt_zuordnung" ] && [ -f "$lt_alt_datei" ]; then
        while IFS= read -r lt_paar; do
            lt_a=${lt_paar%%=*}
            lt_b=${lt_paar#*=}
            case $lt_a in ''|*[!0-9]*) continue ;; esac
            case $lt_b in ''|*[!A-Za-z0-9._-]*) continue ;; esac
            [ "$lt_b" = "$LT_KDE_ID" ] && continue
            lt_zuordnung="$lt_zuordnung\"$lt_a\": \"$lt_b\", "
        done < "$lt_alt_datei"
    fi
    lt_appletsrc=$LT_CONFIG_HOME/plasma-org.kde.plasma.desktop-appletsrc
    # Plasma nicht erreichbar – oder erreichbar, meldet aber keine Arbeitsfläche (z. B. ohne kactivitymanagerd):
    # dann nur weitermachen, wenn auch laut Datei keine Arbeitsfläche mehr das Plugin nutzt
    if ! lt_plasma_lesen || [ -z "$LT_FLAECHEN" ]; then
        [ -n "${LT_PLASMA_FEHLER:-}" ] || LT_PLASMA_FEHLER="Plasma antwortet, meldet aber keine Arbeitsfläche"
        if [ "${LT_PLASMA_ABGELEHNT:-0}" = 1 ]; then
            lt_warn "Plasma lehnt das Skript ab ($LT_PLASMA_FEHLER) – meist sind die Widgets gesperrt oder eine"
            lt_warn "Richtlinie des Administrators verbietet es. Das Plugin bleibt installiert (sonst bliebe der Bildschirm schwarz)."
            lt_warn "Von Hand: Rechtsklick auf die Arbeitsfläche → „Arbeitsfläche und Hintergrund einrichten …“ →"
            lt_warn "Hintergrundbildtyp „Bild“ (oder deinen früheren) wählen → Anwenden, dann --entfernen noch einmal ausführen."
            return 1
        fi
        if [ -f "$lt_appletsrc" ] && grep -q "^wallpaperplugin=$LT_KDE_ID\$" "$lt_appletsrc"; then
            lt_warn "Plasma ist nicht erreichbar ($LT_PLASMA_FEHLER), aber Arbeitsflächen nutzen noch den"
            lt_warn "Linuxtåg-Hintergrund. Ohne Plasma kann ich sie nicht sicher zurückstellen – das Plugin bleibt"
            lt_warn "deshalb installiert (sonst bliebe der Bildschirm schwarz). Bitte in der Plasma-Sitzung ausführen."
            return 1
        fi
        lt_info "Plasma: keine Arbeitsfläche nutzt das Plugin – es kann gefahrlos weg"
        return 2
    fi
    # Die Einstellungen des Plugins (Gruppe Wallpaper/at.linuxtog.kv26/General: Motiv, Animation) bleiben in
    # plasma-org.kde.plasma.desktop-appletsrc stehen – die Skript-Schnittstelle von Plasma kann Gruppen nicht löschen.
    # Sie sind harmlos (nur dieses Plugin liest sie).
    lt_js="var id = \"$LT_KDE_ID\"; var alt = { ${lt_zuordnung%, } }; var ds = desktops(); var n = 0, e = 0;
for (var i = 0; i < ds.length; i++) {
    var d = ds[i];
    if (d.wallpaperPlugin == id) { var p = alt[String(d.id)]; if (!p || p == id) { p = \"org.kde.image\"; e++; } d.wallpaperPlugin = p; n++; }
}
print(\"ZURUECK \" + n + \" ERSATZ \" + e + \" ENDE\");"
    if ! lt_plasma "$lt_js"; then
        lt_warn "Plasma: Zurückstellen ging nicht: ${LT_PLASMA_FEHLER:-?}"
        [ "$LT_PLASMA_ABGELEHNT" = 1 ] && lt_kde_hand Bild
        return 1
    fi
    lt_n=$(printf '%s' "$LT_ANTWORT" | tr '\n' ' ' | sed -n 's/.*ZURUECK \([0-9]*\) ERSATZ.*/\1/p')
    lt_e=$(printf '%s' "$LT_ANTWORT" | tr '\n' ' ' | sed -n 's/.*ERSATZ \([0-9]*\) ENDE.*/\1/p')
    lt_plasma_lesen || return 1
    for lt_paar in $LT_FLAECHEN; do
        if [ "${lt_paar#*=}" = "$LT_KDE_ID" ]; then
            lt_warn "Plasma: Arbeitsfläche ${lt_paar%%=*} nutzt noch das Plugin – es bleibt installiert"
            return 1
        fi
    done
    if [ "${lt_e:-0}" -gt 0 ]; then
        LT_ERSATZ=$((LT_ERSATZ + lt_e))
        lt_info "Plasma: $lt_e Arbeitsfläche(n) auf den Standard-Bildhintergrund (org.kde.image) gestellt – den vorherigen kannte ich nicht"
    fi
    if [ "${lt_n:-0}" -gt "${lt_e:-0}" ]; then
        lt_info "wiederhergestellt: Plasma, $((lt_n - ${lt_e:-0})) Arbeitsfläche(n) ($LT_FLAECHEN)"
        return 0
    fi
    [ "${lt_n:-0}" -gt 0 ] && return 5
    lt_info "Plasma: keine Arbeitsfläche nutzte noch das Plugin – unverändert ($LT_FLAECHEN)"
    return 3
}

lt_kde_plugin_weg() {
    [ -d "$LT_KDE_ZIEL" ] || return 0
    for lt_pv in 6 5; do
        if lt_hat "kpackagetool$lt_pv"; then
            "kpackagetool$lt_pv" --type Plasma/Wallpaper --remove "$LT_KDE_ID" >/dev/null 2>&1 || true
        fi
    done
    rm -rf "$LT_KDE_ZIEL"
    lt_info "entfernt: Plasma-Plugin $LT_KDE_ID"
}

lt_lxde_zurueck() {   # Datei Sicherung (Name im Zustandsordner)   |   - Profil
    if [ "$1" = - ]; then
        # Vorher gab es keine eigene Einstellung: Die Dateien sind erst durch uns entstanden und werden gelöscht –
        # ab dann gilt wieder der Standard der Distribution. Den zeigt auch pcmanfm sofort, wenn es läuft.
        lt_std=/etc/xdg/pcmanfm/$2/desktop-items-0.conf
        lt_sw=
        lt_sm=
        if [ -f "$lt_std" ]; then
            lt_sw=$(lt_ini_lesen "$lt_std" '*' wallpaper)
            lt_sm=$(lt_ini_lesen "$lt_std" '*' wallpaper_mode)
        fi
        [ -n "$lt_sw" ] && [ ! -f "$lt_sw" ] && lt_sw=
        lt_dateien_lx=$(lt_lxde_dateien)
        lt_erg=2
        while IFS= read -r lt_c; do
            [ -n "$lt_c" ] || continue
            if ! lt_lxde_unseres "$lt_c"; then
                lt_info "LXDE: $lt_c zeigt inzwischen auf ein anderes Bild – bleibt, wie es ist"
                [ "$lt_erg" = 2 ] && lt_erg=3
                continue
            fi
            if lt_lxde_laufendes_profil "$lt_c" && lt_laeuft pcmanfm; then
                if [ -n "$lt_sw" ]; then
                    pcmanfm --set-wallpaper="$lt_sw" --wallpaper-mode="${lt_sm:-crop}" >/dev/null 2>&1
                else
                    pcmanfm --wallpaper-mode=color >/dev/null 2>&1
                    LT_ERSATZ=$((LT_ERSATZ + 1))
                    lt_info "LXDE: kein Standardbild gefunden – bis zum nächsten Anmelden einfarbig"
                fi
                sleep 1
            fi
            rm -f "$lt_c"
            lt_erg=0
        done <<LT_ENDE
$lt_dateien_lx
LT_ENDE
        [ "$lt_erg" = 0 ] && lt_info "LXDE: vorher gab es keine eigene Einstellung – der Standard-Hintergrund gilt wieder"
        return "$lt_erg"
    fi
    [ -f "$1" ] || return 2
    if ! lt_lxde_unseres "$1"; then
        lt_info "LXDE: $1 zeigt inzwischen auf ein anderes Bild – bleibt, wie es ist"
        return 3
    fi
    lt_kopie=$LT_ZUSTAND/$2
    case $2 in */*|'') lt_kopie= ;; esac
    if [ -z "$lt_kopie" ] || [ ! -f "$lt_kopie" ]; then
        lt_lxde_einfarbig "$1" || return 1
        LT_ERSATZ=$((LT_ERSATZ + 1))
        lt_info "LXDE: Sicherung fehlt – $1 jetzt einfarbig; bitte bei Bedarf ein Bild wählen"
        ! lt_lxde_unseres "$1"
        return
    fi
    cat "$lt_kopie" > "$1" || return 1       # durch einen Link hindurch schreiben
    if lt_lxde_laufendes_profil "$1" && lt_laeuft pcmanfm; then
        if [ "$(lt_ini_lesen "$1" '*' wallpaper_common)" = 0 ]; then
            lt_info "LXDE: Einstellung zurückgestellt – pcmanfm zeigt das vorherige Bild aber erst ab dem nächsten Anmelden"
            lt_info "      (Bild je Bildschirm). Bis dahin bitte nichts an Schreibtisch-Einstellungen oder -Symbolen ändern:"
            lt_info "      pcmanfm könnte sonst seinen alten Stand zurückschreiben."
            LT_SPAETER=$((LT_SPAETER + 1))
            ! lt_lxde_unseres "$1"
            return
        else
            lt_w=$(lt_ini_lesen "$1" '*' wallpaper)
            lt_m=$(lt_ini_lesen "$1" '*' wallpaper_mode)
            if [ -n "$lt_w" ]; then
                pcmanfm --set-wallpaper="$lt_w" --wallpaper-mode="${lt_m:-crop}" >/dev/null 2>&1
            else
                pcmanfm --wallpaper-mode="${lt_m:-color}" >/dev/null 2>&1
            fi
            sleep 1
            cat "$lt_kopie" > "$1" || return 1   # pcmanfm schreibt seine Sicht in die Datei – das Original gewinnt
        fi
    fi
    lt_info "wiederhergestellt: LXDE $1"
    ! lt_lxde_unseres "$1"
}

lt_lxqt_modus() {   # Modus aus settings.conf → Wert für pcmanfm-qt --wallpaper-mode
    case $1 in none|'') echo color ;; *) echo "$1" ;; esac
}

# Zeigt LXQt noch auf unser Bild? Mit WallpaperMode=none (einfarbig) nicht – pcmanfm-qt behält dann zwar den Pfad in
# der Datei (es schreibt ihn beim Abmelden zurück), benutzt ihn aber nicht.
lt_lxqt_unseres() {
    lt_c=$(lt_lxqt_datei)
    [ -f "$lt_c" ] && lt_ist_unseres "$(lt_ini_lesen "$lt_c" Desktop Wallpaper)" &&
        [ "$(lt_ini_lesen "$lt_c" Desktop WallpaperMode)" != none ]
}

lt_lxqt_zurueck() {   # Bild Modus   (Bild „-“ = vorher keins)
    lt_c=$(lt_lxqt_datei)
    lt_jetzt=
    [ -f "$lt_c" ] && lt_jetzt=$(lt_ini_lesen "$lt_c" Desktop Wallpaper)
    if [ -n "$lt_jetzt" ] && ! lt_ist_unseres "$lt_jetzt"; then
        lt_info "LXQt: inzwischen ist ein anderes Bild gewählt – bleibt, wie es ist"
        return 3
    fi
    lt_w=$1
    lt_m=$2
    lt_std=0
    if [ "$lt_w" = - ]; then
        # vorher kein eigenes Bild: Standard der Distribution
        lt_w=
        lt_m=
        lt_std=1
        for lt_d in /etc/xdg/pcmanfm-qt/lxqt/settings.conf /usr/share/pcmanfm-qt/lxqt/settings.conf; do
            [ -f "$lt_d" ] || continue
            lt_w=$(lt_ini_lesen "$lt_d" Desktop Wallpaper)
            lt_m=$(lt_ini_lesen "$lt_d" Desktop WallpaperMode)
            [ -n "$lt_w" ] && break
        done
        [ -n "$lt_w" ] && [ ! -f "$lt_w" ] && lt_w=
    fi
    lt_qt=0
    lt_laeuft pcmanfm-qt && lt_hat pcmanfm-qt && lt_qt=1
    if [ -n "$lt_w" ]; then
        if [ -f "$lt_c" ]; then
            lt_ini_setzen "$lt_c" Desktop Wallpaper "$lt_w"
            lt_ini_setzen "$lt_c" Desktop WallpaperMode "${lt_m:-zoom}"
        fi
        # das laufende pcmanfm-qt umstellen – sonst schreibt es beim Abmelden unser (gelöschtes) Bild zurück
        [ "$lt_qt" = 1 ] && pcmanfm-qt --set-wallpaper="$lt_w" --wallpaper-mode="$(lt_lxqt_modus "${lt_m:-zoom}")" >/dev/null 2>&1
        if [ "$lt_std" = 1 ]; then
            lt_info "LXQt: Standard-Hintergrund wieder eingestellt ($lt_w)"
        else
            lt_info "wiederhergestellt: LXQt"
        fi
    else
        if [ -f "$lt_c" ]; then
            lt_ini_setzen "$lt_c" Desktop Wallpaper '' -
            lt_ini_setzen "$lt_c" Desktop WallpaperMode none
        fi
        [ "$lt_qt" = 1 ] && pcmanfm-qt --wallpaper-mode=color >/dev/null 2>&1
        LT_ERSATZ=$((LT_ERSATZ + 1))
        lt_info "LXQt: vorher war kein Bild bekannt und kein Standardbild zu finden – jetzt einfarbig"
    fi
    [ "$lt_qt" = 1 ] && sleep 1
    ! lt_lxqt_unseres
}

# Sicherheitsnetz vor dem Löschen: Zeigt noch etwas auf unsere Dateien, für das nichts (Brauchbares) gemerkt war –
# etwa weil die Merkliste fehlt? Dann auf den Standard zurücksetzen; geht das nicht, nicht löschen (Rückgabe 1).
lt_reste_zuruecksetzen() {
    lt_rz=0
    if lt_hat gsettings; then
        for lt_e in org.gnome.desktop.background:picture-uri org.gnome.desktop.background:picture-uri-dark \
                    org.cinnamon.desktop.background:picture-uri org.mate.background:picture-filename; do
            lt_s=${lt_e%%:*}
            lt_k=${lt_e#*:}
            lt_gs_schluessel "$lt_s" "$lt_k" || continue
            lt_jetzt=$(gsettings get "$lt_s" "$lt_k" 2>/dev/null) || continue
            lt_ist_unseres "$lt_jetzt" || continue
            gsettings reset "$lt_s" "$lt_k" 2>/dev/null
            gsettings reset "$lt_s" picture-options 2>/dev/null
            if lt_ist_unseres "$(gsettings get "$lt_s" "$lt_k" 2>/dev/null)"; then
                lt_warn "$lt_s $lt_k zeigt noch auf Linuxtåg und ließ sich nicht zurücksetzen (D-Bus erreichbar?)"
                lt_rz=1
            else
                lt_info "auf Standard zurückgesetzt: $lt_s $lt_k (nichts gemerkt)"
                LT_ERSATZ=$((LT_ERSATZ + 1))
            fi
        done
    fi
    if lt_xf_relevant && ! lt_xf_erreichbar; then
        lt_warn "Xfce: xfconf ist nicht erreichbar – ich kann nicht prüfen, ob Xfce noch auf die Linuxtåg-Bilder zeigt."
        lt_rz=1
    elif lt_xf_relevant; then
        lt_liste=$(lt_xf -l | grep '/last-image$')
        while IFS= read -r lt_p; do
            # shellcheck disable=SC2015 # gewollt: weiter, wenn leer ODER nicht unseres
            [ -n "$lt_p" ] && lt_ist_unseres "$(lt_xf -p "$lt_p")" || continue
            for lt_k in last-image backdrop-cycle-enable backdrop-cycle-period backdrop-cycle-random-order image-style; do
                lt_xf -p "${lt_p%/*}/$lt_k" -r
            done
            if lt_ist_unseres "$(lt_xf -p "$lt_p")"; then
                lt_warn "Xfce $lt_p zeigt noch auf Linuxtåg und ließ sich nicht zurücksetzen"
                lt_rz=1
            else
                lt_info "auf Standard zurückgesetzt: Xfce $lt_p (nichts gemerkt)"
                LT_ERSATZ=$((LT_ERSATZ + 1))
            fi
        done <<LT_ENDE
$lt_liste
LT_ENDE
    fi
    lt_dateien_lx=$(lt_lxde_dateien)
    while IFS= read -r lt_c; do
        # shellcheck disable=SC2015 # gewollt: weiter, wenn leer ODER nicht unseres
        [ -n "$lt_c" ] && lt_lxde_unseres "$lt_c" || continue
        lt_lxde_einfarbig "$lt_c"
        if lt_lxde_laufendes_profil "$lt_c" && lt_laeuft pcmanfm; then
            pcmanfm --wallpaper-mode=color >/dev/null 2>&1
        fi
        if lt_lxde_unseres "$lt_c"; then
            lt_rz=1
        else
            lt_info "LXDE: $lt_c jetzt einfarbig (nichts gemerkt) – bitte bei Bedarf ein Bild wählen"
            LT_ERSATZ=$((LT_ERSATZ + 1))
        fi
    done <<LT_ENDE
$lt_dateien_lx
LT_ENDE
    if lt_lxqt_unseres; then
        lt_lxqt_zurueck - '' >/dev/null || lt_rz=1
        lt_info "LXQt: Hintergrund zurückgesetzt (nichts gemerkt)"
    fi
    return "$lt_rz"
}

lt_ergebnis() {   # Rückgabe Beschreibung → Zähler, Meldung
    case $1 in
        0) LT_WIEDER=$((LT_WIEDER + 1)) ;;
        2) ;;
        3|6) LT_GELASSEN=$((LT_GELASSEN + 1)) ;;
        5) ;;     # schon als LT_ERSATZ gezählt
        *) lt_warn "nicht wiederhergestellt: $2"
           LT_FEHLT=1 ;;
    esac
}

lt_entfernen() {
    lt_sag "$LT_TITEL – Linuxtåg-Hintergrund entfernen"
    if [ ! -f "$LT_VORHER" ] && [ ! -f "$LT_INSTALLIERT" ] && [ ! -d "$LT_DATEN" ] && [ ! -d "$LT_KDE_ZIEL" ] && [ ! -f "$LT_PROPS" ]; then
        lt_sag "Es ist kein Linuxtåg-Hintergrund eingerichtet – nichts zu tun."
        return 0
    fi
    LT_FEHLT=0
    LT_WIEDER=0
    LT_GELASSEN=0
    LT_ERSATZ=0
    LT_SPAETER=0
    lt_familien=$(lt_installiert_lesen familien 2>/dev/null || true)
    lt_unsere_merken
    # KDE zuerst (Plugin erst entfernen, wenn keine Arbeitsfläche mehr darauf zeigt)
    if [ -d "$LT_KDE_ZIEL" ] || lt_gemerkt "kde$LT_TAB"; then
        lt_kde_zurueck
        lt_ergebnis $? "Plasma"
    fi
    if [ -f "$LT_VORHER" ]; then
        while IFS= read -r lt_z; do
            lt_felder "$lt_z"
            case $LT_F1 in
                gsettings)
                    lt_gs_zurueck "$LT_F2" "$LT_F3" "$LT_F4"
                    lt_r=$?
                    case $lt_r in
                        0) lt_info "wiederhergestellt: $LT_F2 $LT_F3" ;;
                        2) lt_info "$LT_F2 $LT_F3: unverändert (zeigte nicht auf Linuxtåg)" ;;
                        3) lt_info "$LT_F2 $LT_F3: inzwischen selbst gewählt – bleibt, wie es ist" ;;
                        5) lt_info "auf Standard zurückgesetzt: $LT_F2 $LT_F3 (vorher war ein älterer Linuxtåg-Hintergrund eingestellt)"
                           LT_ERSATZ=$((LT_ERSATZ + 1)) ;;
                    esac
                    lt_ergebnis "$lt_r" "$LT_F2 $LT_F3 (Desktop-Sitzung/D-Bus erreichbar?)" ;;
                xfconf)
                    lt_xf_zurueck "$LT_F2" "$LT_F3" "$LT_F4"
                    lt_r=$?
                    [ "$lt_r" = 3 ] && [ "${LT_F2##*/}" = last-image ] && lt_info "Xfce ${LT_F2%/*}: inzwischen selbst gewähltes Bild – bleibt"
                    [ "$lt_r" = 6 ] && lt_info "Xfce ${LT_F2%/*}: ${LT_F2##*/} wie vorher (der Linuxtåg-Bildwechsel ist aus)"
                    lt_ergebnis "$lt_r" "Xfce $LT_F2 (xfconf erreichbar?)" ;;
                lxde)
                    lt_lxde_zurueck "$LT_F2" "$LT_F3"
                    lt_ergebnis $? "LXDE $LT_F2" ;;
                lxqt)
                    lt_lxqt_zurueck "$LT_F2" "$LT_F3"
                    lt_ergebnis $? "LXQt" ;;
            esac
        done < "$LT_VORHER"
    fi
    [ "$LT_FEHLT" = 0 ] && { lt_reste_zuruecksetzen || LT_FEHLT=1; }
    # Ein Desktop war eingerichtet, aber es gibt keine Merkliste und nichts ließ sich prüfen? Dann nicht löschen.
    if [ "$LT_FEHLT" != 0 ]; then
        lt_behalten="die Bilder ($LT_DATEN)"
        [ -d "$LT_KDE_ZIEL" ] && lt_behalten="$lt_behalten, das Plasma-Plugin"
        lt_sag ""
        lt_sag "Nicht alles ließ sich wiederherstellen (siehe oben). Damit nichts ins Leere zeigt, bleiben $lt_behalten"
        lt_sag "und die Merkliste ($LT_ZUSTAND) erhalten. Bitte in der laufenden Desktop-Sitzung erneut:"
        lt_sag "  curl -fsSL https://carinthianlinuxday.at/hintergrund.sh | sh -s -- --entfernen"
        return 4
    fi
    # erst jetzt löschen: Kein Desktop zeigt mehr auf unsere Dateien
    lt_kde_plugin_weg
    rm -rf "$LT_DATEN" "$LT_ZUSTAND"
    rm -f "$LT_PROPS"
    rm -f "$LT_STATE_HOME/linuxtog-hintergrund/kde-vorher.txt"
    for lt_d in "${LT_PROPS%/*}" "$LT_STATE_HOME/linuxtog-hintergrund" "${LT_KDE_ZIEL%/*}"; do
        [ -d "$lt_d" ] && rmdir "$lt_d" 2>/dev/null
    done
    lt_sag ""
    if [ "$LT_ERSATZ" -gt 0 ]; then
        lt_sag "Fertig. Alle Linuxtåg-Dateien sind gelöscht. Den vorherigen Hintergrund kannte ich nicht überall –"
        lt_sag "wo oben „einfarbig“ oder „Standard“ steht, bitte bei Bedarf selbst ein Bild wählen."
    elif [ "$LT_SPAETER" -gt 0 ]; then
        lt_sag "Fertig. Alle Linuxtåg-Dateien sind gelöscht, die Einstellungen zurückgestellt. LXDE zeigt den vorherigen"
        lt_sag "Hintergrund erst ab dem nächsten Anmelden (bis dahin bleibt das Linuxtåg-Bild im Speicher von pcmanfm)."
    elif [ "$LT_GELASSEN" -gt 0 ]; then
        lt_sag "Fertig. Alle Linuxtåg-Dateien sind gelöscht. Wo du inzwischen selbst einen Hintergrund gewählt hast,"
        lt_sag "bleibt er; sonst ist dein vorheriger Hintergrund wieder eingestellt."
    elif [ "$LT_WIEDER" -gt 0 ]; then
        lt_sag "Fertig. Dein vorheriger Hintergrund ist wieder eingestellt, alle Linuxtåg-Dateien sind gelöscht."
    else
        lt_sag "Fertig. Alle Linuxtåg-Dateien sind gelöscht (es gab nichts zurückzustellen)."
    fi
    case " $lt_familien " in
        *" anleitung "*)
            lt_sag "Hast du das Bild selbst eingetragen (sway, Hyprland, i3/feh …)? Diese Zeile bitte wieder entfernen –"
            lt_sag "die Datei gibt es nicht mehr." ;;
    esac
    return 0
}

# ---------------------------------------------------------------------------------------------------- Status
lt_status() {
    lt_sag "$LT_TITEL – lebendiger Hintergrund, Skript-Version $LT_VERSION (BETA)"
    if lt_desktop_erkennen; then
        lt_sag "Desktop:          $(lt_desktop_text "$LT_DESKTOP") (${LT_DESKTOP_NAME:-?})"
    else
        lt_sag "Desktop:          nicht erkannt (XDG_CURRENT_DESKTOP=${XDG_CURRENT_DESKTOP:-leer})"
    fi
    if [ -f "$LT_INSTALLIERT" ]; then
        lt_ab=$(lt_installiert_lesen abgelegt)
        lt_sag "Eingerichtet:     Motiv $(lt_installiert_lesen motiv)${lt_ab:+ (abgelegt, aber nicht eingestellt: $lt_ab)}, Version $(lt_installiert_lesen version), $(lt_installiert_lesen art), für: $(lt_installiert_lesen familien) (am $(lt_installiert_lesen datum))"
        lt_z=$(lt_installiert_lesen zustand)
        [ -n "$lt_z" ] && lt_sag "Zustand:          $lt_z"
        lt_g=$(lt_installiert_lesen groesse)
        if [ -n "$lt_g" ]; then
            lt_sag "Zusammengesetzt:  für $(printf '%s' "$lt_g" | sed 's/x/×/') ($(lt_installiert_lesen groesse_quelle))"
            lt_b=$(lt_installiert_lesen bild)
            [ -n "$lt_b" ] && lt_sag "Ruhendes Bild:    $lt_b"
        fi
    else
        lt_sag "Eingerichtet:     nichts"
    fi
    # Bildschirm jetzt – passt das Zusammengesetzte noch?
    lt_bildschirm
    lt_sag "Bildschirm jetzt: ${LT_B}×${LT_H} ($LT_GROESSE_QUELLE)"
    [ -n "$LT_GROESSE_HINWEIS" ] && lt_sag "                  $LT_GROESSE_HINWEIS"
    if [ -n "${lt_g:-}" ] && [ "$lt_g" != "${LT_B}x$LT_H" ]; then
        case " $(lt_installiert_lesen familien) " in
            " kde ") lt_sag "                  (KDE setzt das Motiv selbst für jede Größe zusammen)" ;;
            *) lt_sag "Hinweis:          andere Größe als beim Einrichten – den Befehl noch einmal ausführen, dann passt es wieder." ;;
        esac
    fi
    if [ -f "$LT_VORHER" ]; then
        lt_sag "Gemerkt (vorher): $(wc -l < "$LT_VORHER" | tr -d ' ') Einstellung(en) in $LT_VORHER"
    else
        lt_sag "Gemerkt (vorher): nichts"
    fi
    lt_ordner=
    for lt_d in "$LT_DATEN"/*/; do
        [ -d "$lt_d" ] && lt_d=${lt_d%/} && lt_ordner="$lt_ordner ${lt_d##*/}"
    done
    lt_sag "Bilder:          ${lt_ordner:- –} ($LT_DATEN)"
    if [ -f "$LT_KDE_ZIEL/metadata.json" ]; then
        lt_kz=$(cat "$LT_KDE_ZIEL/contents/linuxtag-paket.txt" 2>/dev/null || echo '?')
        lt_sag "Plasma-Plugin:    installiert ($lt_kz)"
        # nach einem Umstieg von Plasma 5 auf 6 lädt Plasma die Plasma-5-Fassung nicht (schwarzer Hintergrund)
        case $lt_kz in
            *plasma=5*) [ "$(lt_plasma_version)" = 6 ] &&
                lt_sag "Hinweis:          Plugin ist für Plasma 5, hier läuft Plasma 6 – bitte den Befehl noch einmal ausführen." ;;
        esac
    else
        lt_sag "Plasma-Plugin:    nicht installiert"
    fi
    for lt_alt in "$LT_DATA_HOME/backgrounds/linuxtag-2026" "$LT_STATE_HOME/linuxtag-2026" "$LT_STATE_HOME/linuxtog-hintergrund"; do
        [ -e "$lt_alt" ] && lt_sag "Hinweis:          Reste eines älteren Prototyps: $lt_alt"
    done
    return 0
}

# ---------------------------------------------------------------------------------------------------- Start
main() {
    # native zsh („curl … | zsh“) wie sh verhalten lassen (Wortaufteilung, keine Fehler bei leeren Mustern)
    [ -n "${ZSH_VERSION:-}" ] && emulate sh 2>/dev/null
    set -u
    lt_grundwerte
    lt_pakete gitterraum >/dev/null 2>&1 || true      # setzt LT_VERSION
    trap 'lt_aufraeumen' EXIT
    # „trap - EXIT“ vor exit: mksh ließe sonst den Rückgabewert der EXIT-Falle (0) gewinnen
    # dash, mksh und busybox führen die EXIT-Falle bei einem Signal ohne eigene Falle nicht aus → alle abfangen
    trap 'lt_aufraeumen; trap - EXIT; exit 129' HUP
    trap 'lt_aufraeumen; trap - EXIT; exit 130' INT
    trap 'lt_aufraeumen; trap - EXIT; exit 141' PIPE
    trap 'lt_aufraeumen; trap - EXIT; exit 143' TERM
    lt_argumente "$@" || lt_ende 2
    case $LT_MODUS in
        hilfe)   lt_hilfe; lt_ende 0 ;;
        version) lt_sag "hintergrund.sh $LT_VERSION (BETA) – $LT_TITEL"; lt_ende 0 ;;
    esac
    if [ -z "${HOME:-}" ]; then
        lt_fehler "HOME ist nicht gesetzt"
        lt_ende 1
    fi
    case $HOME in
        /*) ;;
        *) lt_fehler "HOME muss ein absoluter Pfad sein (ist: $HOME) – sonst entstünden ungültige Pfade"
           lt_ende 1 ;;
    esac
    if [ "$LT_MODUS" = status ]; then
        lt_status
        lt_ende 0
    fi
    if [ "$(id -u)" = 0 ]; then
        lt_fehler "bitte ohne sudo/root ausführen – der Hintergrund gehört zu deinem Benutzer, nicht zum System"
        lt_ende 1
    fi
    if [ "$LT_MODUS" = entfernen ]; then
        lt_entfernen
        lt_ende $?
    fi
    lt_einrichten
    lt_ende $?
}

{ main "$@"; }
