From 1645e251bc84923e34b41b24e7065a5c6a798426 Mon Sep 17 00:00:00 2001 From: Sergio Date: Fri, 4 Sep 2026 02:35:24 +0000 Subject: [PATCH] =?UTF-8?q?cosmic=20anidado:=20el=20panel=20dibuja=20en=20?= =?UTF-8?q?una=20ventana=20=E2=80=94=20y=20el=20cierre=20del=20perfil=20NO?= =?UTF-8?q?=20puede=20hacer=20GL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hermano de `sway-nested.sh` para el cuarto escritorio. Levanta cosmic-comp nesteado y sus clientes; sale con el panel entero: app-library, app-list, siete applets, pop-launcher, cosmic-toplevel y los dos procesos del portal. **El hallazgo, que es de la IMAGEN y no del arnés**: `/usr/lib/dri` del rootfs hidratado trae `iris_dri.so` y NADA MÁS — el driver de Intel real. Sin `swrast_dri.so`, EGL no inicializa y cosmic-comp muere con `Egl(InitFailed(NotInitialized))` detrás de dos `MESA-LOADER: failed to open {zink,swrast}`. O sea que el cierre 133/133 de `escritorio-cosmic` **no puede componer en ninguna máquina que no sea Intel** — ni en una VM, ni nesteado. No es nuevo, es un hueco de DECLARACIÓN: `scripts/gnome/qemu-desktop-image.sh` ya lo dice en su cabecera y copia `mesa-llvmpipe` encima con `--remove-destination`. Cada script de imagen inyecta a mano algo que `targets.toml` no declara — justo la divergencia que `hydrate-profile.py` hace visible. Y no se arregla declarándolo: `mesa` y `mesa-llvmpipe` instalan los MISMOS `.so` (libEGL/libgbm/libGLESv2), así que las dos en un perfil colisionan fichero a fichero — la figura de las dos poppler. Los scripts lo resuelven PISANDO, que es decisión de imagen y no arista de grafo. Acá se hace lo mismo y se dice: `mesa-llvmpipe` entra como TERCER overlay, el último, o sea el de mayor prioridad. El artefacto se elige por `hammer hash`, no por el más reciente del store. Y `cosmic-session` no sirve para nestear: no le pasa `WAYLAND_DISPLAY` a cosmic-comp —para ella el compositor ES el display server— y su stderr lo captura `launch_pad`, que sólo repite «cosmic-comp exited with error code 1» y lo reinicia en bucle, así que la causa no aparece en ningún log. Por eso el modo por defecto es `bare`: compositor a mano y clientes apuntados a SU socket. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CGyBj4QyeCZiwLMkP9GJp6 --- scripts/cosmic/cosmic-nested.sh | 142 ++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100755 scripts/cosmic/cosmic-nested.sh diff --git a/scripts/cosmic/cosmic-nested.sh b/scripts/cosmic/cosmic-nested.sh new file mode 100755 index 00000000..f711b1d9 --- /dev/null +++ b/scripts/cosmic/cosmic-nested.sh @@ -0,0 +1,142 @@ +#!/bin/sh +# cosmic-nested.sh — arranca `escritorio-cosmic` como una VENTANA del compositor que ya tenés +# delante, sin QEMU y sin imagen de disco. Hermano de `scripts/wlr/sway-nested.sh`; comparte con él +# el porqué (ciclo de segundos en vez de una tanda, y defectos que sólo se ven MIRANDO) y las dos +# capas de overlay, porque ningún perfil de `targets.toml` incluye la libc. +# +# ══ LO QUE COSMIC HACE DISTINTO ════════════════════════════════════════════════════════════════ +# · `cosmic-comp` elige backend solo. Con `WAYLAND_DISPLAY` puesto usa winit sobre Wayland; ANTES +# intenta X11 y falla ruidosamente («$DISPLAY variable not set»). Ese ERROR es normal acá y no +# significa que no haya arrancado: lo que manda es si aparece su socket en `$XDG_RUNTIME_DIR`. +# · **`cosmic-session` no sirve para nestear**: no le pasa `WAYLAND_DISPLAY` a `cosmic-comp` —para +# ella el compositor ES el display server—, así que el comp intenta X11 y DRM/udev y muere antes. +# Y su stderr lo captura `launch_pad`, que sólo reporta «cosmic-comp exited with error code 1» y +# lo reinicia en bucle: la CAUSA no aparece en ningún log. Medido, con todo lo demás igual: +# con WAYLAND_DISPLAY → socket /run/user/0/wayland-1, comp vivo hasta el backend +# sin WAYLAND_DISPLAY → comp muerto antes +# Por eso el modo por defecto es `bare`: el compositor a mano y los clientes apuntados a SU socket, +# igual que hace `cosmic-start.sh` sin sesión. `MODE=session` reproduce el fallo, no lo arregla. +# +# ══ ⚠ EL CIERRE DEL PERFIL NO PUEDE HACER GL, Y ESO NO ESTÁ EN `targets.toml` ═══════════════════ +# Medido el 2026-09-04: `/usr/lib/dri` del rootfs hidratado trae **`iris_dri.so` y nada más** — el +# driver de Intel REAL. Sin `swrast_dri.so`, EGL no inicializa y cosmic-comp muere con +# `Egl(InitFailed(NotInitialized))` después de dos `MESA-LOADER: failed to open {zink,swrast}`. +# +# No es un descubrimiento nuevo, es un hueco de DECLARACIÓN: `scripts/gnome/qemu-desktop-image.sh` +# ya dice «el rootfs GNOME sólo trae iris_dri, que es Intel real» y copia `mesa-llvmpipe` ENCIMA con +# `--remove-destination`. O sea que cada script de imagen inyecta a mano algo que el perfil no +# declara — la misma divergencia que `hydrate-profile.py` existe para hacer visible. +# +# **Por qué no se arregla declarándolo y ya:** `mesa` y `mesa-llvmpipe` instalan los MISMOS `.so` +# (`libEGL`, `libgbm`, `libGLESv2`), así que declarar las dos en un perfil colisiona fichero a +# fichero — la figura de las dos poppler que dejó a zathura fuera de KDE. Los scripts lo resuelven +# PISANDO, que es una decisión de imagen, no una arista de grafo. Acá se hace lo mismo y se dice: +# `mesa-llvmpipe` entra como TERCER overlay, el último, o sea el de mayor prioridad. +# · **No hay `grim`**: COSMIC no implementa `wlr-screencopy` sino su `zcosmic_screencopy`, así que +# la captura sale por `cosmic-screenshot` (cadena del portal). Si el portal no está, no hay foto +# y hay que mirar la ventana — se dice, no se falsea con una captura del host. +# +# uso: scripts/cosmic/cosmic-nested.sh +# env: RFS (def /mnt/cosecha/escritorios/cosmic-rootfs) hidratado con hydrate-profile.py +# BASE (def .dev-fs/alpine) capa con la libc +# MODE (def session | bare) sesión completa o sólo el compositor +# OUT (def /mnt/cosecha/escritorios) dónde deja la captura +# SECS (def 0 = quedarse abierto) +# MESA (def el artefacto vigente de mesa-llvmpipe) GL por software; "" para no inyectar +set -u +ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT" +RFS="${RFS:-/mnt/cosecha/escritorios/cosmic-rootfs}" +BASE="${BASE:-$ROOT/.dev-fs/alpine}" +MODE="${MODE:-bare}"; OUT="${OUT:-/mnt/cosecha/escritorios}"; SECS="${SECS:-0}" +mkdir -p "$OUT" + +# GL por software. Se resuelve por HASH VIGENTE (`hammer hash`), no por el más reciente del store: +# con dos artefactos del mismo paquete conviviendo, la fecha miente. +if [ -z "${MESA+x}" ]; then + MH=$(./target/release/hammer --store ./store hash recipes/mesa-llvmpipe.toml 2>/dev/null | tr -d "\n" | sed "s/b3://") + MESA=$(ls -d store/"$MH"-mesa-llvmpipe 2>/dev/null || true) + [ -n "${MESA:-}" ] || echo " ⚠ sin mesa-llvmpipe sellado: el compositor NO va a poder iniciar EGL" >&2 +fi + +[ -d "$RFS" ] || { echo "falta el rootfs del perfil: $RFS" >&2 + echo " scripts/hydrate-profile.py escritorio-cosmic --store /mnt/cosecha/store --into $RFS" >&2; exit 1; } +[ -d "$BASE" ] || { echo "falta la capa base con la libc: $BASE" >&2; exit 1; } + +HOST_XDG="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" +HOST_WL="${WAYLAND_DISPLAY:-wayland-0}" +case "$HOST_WL" in /*) SOCK="$HOST_WL" ;; *) SOCK="$HOST_XDG/$HOST_WL" ;; esac +[ -S "$SOCK" ] || { echo "no hay socket Wayland del host en $SOCK" >&2; exit 1; } +echo "== host: $SOCK rootfs: $RFS modo: $MODE" + +# El ORDEN importa: el último `--overlay-src` es el de mayor prioridad, así que mesa-llvmpipe pisa +# los `.so` de la mesa iris del cierre — que es exactamente lo que hacen los scripts de imagen. +exec bwrap \ + --overlay-src "$BASE" --overlay-src "$RFS" ${MESA:+--overlay-src "$MESA"} --tmp-overlay / \ + --dev /dev --proc /proc --tmpfs /tmp --tmpfs /run \ + --dev-bind-try /dev/dri /dev/dri \ + --ro-bind "$SOCK" /run/wl-host \ + --bind "$OUT" /salida \ + --unshare-pid --unshare-uts --hostname cosmic-nested \ + --uid 0 --gid 0 --die-with-parent \ + --setenv PATH /usr/bin:/bin:/usr/sbin:/sbin \ + --setenv HOME /root --setenv SHELL /bin/bash --setenv TERM xterm-256color \ + --setenv XDG_RUNTIME_DIR /run/user/0 \ + --setenv WAYLAND_DISPLAY /run/wl-host \ + --setenv XDG_DATA_DIRS /usr/share \ + --setenv XDG_CURRENT_DESKTOP COSMIC \ + --setenv XDG_SESSION_TYPE wayland \ + --setenv RUST_BACKTRACE 1 \ + /bin/sh -c ' + set -u + mkdir -p /run/user/0 /run/dbus /root/.config /etc; chmod 700 /run/user/0 + [ -s /etc/passwd ] || echo "root:x:0:0:root:/root:/bin/sh" > /etc/passwd + [ -s /etc/machine-id ] || tr -d - < /proc/sys/kernel/random/uuid > /etc/machine-id + mkdir -p /dev/shm 2>/dev/null || true + + # El bus de SESIÓN: el panel, el osd y las notificaciones hablan por él. En `session` lo abre + # `dbus-run-session`; en `bare` no hay quien lo abra, y sin él los clientes arrancan mudos. + export DBUS_SESSION_BUS_ADDRESS=$(dbus-daemon --session --fork --print-address 2>/dev/null) + echo " dbus=${DBUS_SESSION_BUS_ADDRESS:-VACIO}" + + if [ "'"$MODE"'" = session ] && [ -x /usr/bin/start-cosmic ]; then + echo "-- start-cosmic (sesión completa) — ⚠ NO NESTEA, ver la cabecera del script" + /bin/bash /usr/bin/start-cosmic --in-login-shell >/tmp/cosmic.log 2>&1 & + else + echo "-- cosmic-comp nesteado (winit sobre el Wayland del host)…" + cosmic-comp >/tmp/cosmic.log 2>&1 & + fi + CS=$! + i=0 + while [ $i -lt 80 ]; do + WD=$(ls /run/user/0/wayland-* 2>/dev/null | grep -v lock | head -1) + [ -n "${WD:-}" ] && break + kill -0 $CS 2>/dev/null || { echo " !! la sesión murió antes del socket:"; tail -25 /tmp/cosmic.log; exit 1; } + i=$((i+1)); sleep 0.5 + done + [ -n "${WD:-}" ] || { echo " !! sin socket en 40 s:"; tail -25 /tmp/cosmic.log; exit 1; } + echo " compositor OK ($WD) — ventana en tu pantalla" + export WAYLAND_DISPLAY=$(basename "$WD") + + # Los clientes, contra el socket que el compositor eligió. Cada uno con `[ -x ]` porque la cola + # se construye por partes y un arranque perdido cuesta más que una comprobación de más. + if [ "'"$MODE"'" != session ]; then + for c in cosmic-bg cosmic-panel cosmic-osd cosmic-notifications cosmic-app-library cosmic-launcher; do + [ -x "/usr/bin/$c" ] && { "/usr/bin/$c" >"/tmp/$c.log" 2>&1 & sleep 1; } + done + fi + + sleep 8 + echo "== procesos de la sesión ==" + ps -o comm 2>/dev/null | grep -E "cosmic|pop-launcher|xdg-desktop" | sort | uniq -c + # `Initializing X11 Backend failed` es NORMAL acá: cosmic-comp prueba X11 antes de winit. Lo que + # importa es el backend que SÍ entró. + echo "== backend =="; grep -iE "winit|backend" /tmp/cosmic.log | grep -viE "X11|DISPLAY variable" | head -4 + if command -v cosmic-screenshot >/dev/null 2>&1; then + cosmic-screenshot --interactive=false --save-dir /salida >/tmp/shot.log 2>&1 \ + && echo "== captura en '"$OUT"'" || { echo "== sin captura (portal):"; tail -2 /tmp/shot.log; } + else + echo "== sin cosmic-screenshot en la imagen — mirá la ventana" + fi + echo "== cosmic.log (cola) =="; tail -6 /tmp/cosmic.log; cp /tmp/cosmic.log /salida/cosmic-nested.log 2>/dev/null + if [ '"$SECS"' -gt 0 ]; then sleep '"$SECS"'; kill $CS 2>/dev/null; else wait $CS; fi + '