Dos piezas para mirar la distro sin QEMU, que es lo que hacía falta para cazar el puntero
invisible: ese defecto no lo ve ninguna métrica de clausura Y TAMPOCO una captura headless — el
cursor no está en el framebuffer que devuelve screencopy. Hay que mirar la ventana.
`hydrate-profile.py <perfil>`: proyecta el cierre ENTERO de un perfil de `targets.toml`. Los
`hydrate-*.sh` por escritorio traen la lista de raíces escrita a mano dentro del script, o sea DOS
fuentes de verdad: hoy mismo se añadió `adwaita-cursors` a cosmic y sway y esos scripts —que no la
conocen— habrían seguido armando un rootfs sin cursores mientras el perfil decía que los lleva.
Acá el cierre sale de `yupana.membresia()`, la misma función que usan build-state y vigia-imagen.
Y trae la sonda que costó dos intentos: `hydrate` ENLAZA, y `linkat()` no cruza un punto de
MONTAJE aunque sea el mismo disco. El store y `work/out` son dos binds del mismo /dev/sdb ⇒
`st_dev` COINCIDE y el hardlink falla igual. La primera versión comparaba `st_dev` y no disparó:
salieron 174 «artefactos que no proyectaron» y un rootfs de 272 ficheros con pinta de problema de
recetas. Ahora la sonda es FUNCIONAL —se intenta un enlace de verdad— y el error nombra el montaje
del store.
`sway-nested.sh`: arranca `escritorio-sway` como ventana del compositor que ya tenés delante.
Evidencia de esta corrida, con el rootfs hidratado del perfil:
[wlr] [xcursor] Loaded cursor theme 'default' at size 24 (62 available cursors)
o sea el tema llamado literalmente `default` —el alias que fabrica `adwaita-cursors`— resolviendo
a los 62 cursores de Adwaita. Antes de hoy esa línea no existía.
Tres cosas que sólo salen corriéndolo:
· **Ningún perfil incluye `musl`.** Ni `base`. El cierre de escritorio-sway no trae UN `ld-musl` y
sway es `link=dynamic` con intérprete `/lib/ld-musl-x86_64.so.1`: la libc sale del bootstrap, no
de una receta del perfil. Por eso el arnés monta DOS overlays. No es un bug, pero no estaba
escrito en ningún lado y un rootfs de perfil solo no arranca.
· **`yambar` no va en `bar { status_command … }`**: es una barra completa de layer-shell, no un
productor de estado para swaybar. Puesta ahí, sway rechaza la config ENTERA y arranca pelado —
se lee como «el escritorio está roto» cuando lo único mal es una línea.
· **`grim` hay que apuntarlo al socket de NUESTRO sway.** Adentro `WAYLAND_DISPLAY` es el del HOST
(es lo que sway necesita para nestear), así que un `grim` a secas devuelve una captura perfecta…
del escritorio de al lado. La primera captura fue exactamente eso.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGyBj4QyeCZiwLMkP9GJp6
132 lines
8.1 KiB
Bash
Executable File
132 lines
8.1 KiB
Bash
Executable File
#!/bin/sh
|
|
# sway-nested.sh — arranca el escritorio `escritorio-sway` como una VENTANA del compositor que ya
|
|
# tenés delante, sin QEMU, sin kernel y sin imagen de disco. Hermano de `sway-headless.sh` (que
|
|
# dibuja contra un backend headless y captura con grim) y de `sway-start.sh` (que arranca dentro de
|
|
# la VM).
|
|
#
|
|
# ══ PARA QUÉ, SI YA ESTÁ EL DE QEMU ════════════════════════════════════════════════════════════
|
|
# Porque el ciclo de QEMU es de decenas de minutos —armar rootfs, imagen EFI, arrancar— y el de acá
|
|
# es de segundos, así que «¿esto se ve bien?» deja de costar una tanda. Y porque hay un tipo de
|
|
# defecto que SÓLO se ve mirando: el puntero invisible por falta de tema de cursor (arreglado el
|
|
# 2026-09-04 con `adwaita-cursors`) no lo caza ninguna métrica de clausura, y en una captura
|
|
# headless tampoco aparece — el cursor no está en el framebuffer que devuelve `grim`.
|
|
#
|
|
# NO sustituye al arranque en QEMU: acá no hay kernel nuestro, ni initramfs, ni DRM, ni PID 1.
|
|
# Prueba el compositor y sus clientes, que es justo lo que la VM tapa detrás de una pantalla negra.
|
|
#
|
|
# ══ LAS DOS CAPAS, Y POR QUÉ SON DOS ═══════════════════════════════════════════════════════════
|
|
# `targets.toml` describe lo que la IMAGEN añade, no un sistema entero: ningún perfil —ni `base`—
|
|
# incluye `musl`, porque la libc, busybox y PID 1 salen del bootstrap (`work/metal-rootfs`), no de
|
|
# una receta del perfil. Medido: el cierre de `escritorio-sway` no trae UN solo `ld-musl`, y sway
|
|
# es `link = dynamic` con intérprete `/lib/ld-musl-x86_64.so.1`. Por eso acá van dos overlays: la
|
|
# capa base (por defecto el dev-fs de Alpine, que es lo que ya usan los `nested-*` de KDE) y encima
|
|
# el rootfs del perfil. Si algún día el perfil declarara su propia base, esto se queda en uno.
|
|
#
|
|
# ══ QUÉ MIRAR ═════════════════════════════════════════════════════════════════════════════════
|
|
# Se abre una ventana con el fondo azul de la config, la barra de `yambar` y una terminal `foot`.
|
|
# Lo que hay que comprobar A OJO y ninguna captura headless muestra: **que el puntero se vea** al
|
|
# entrar el mouse en la ventana.
|
|
#
|
|
# uso: scripts/wlr/sway-nested.sh
|
|
# env: RFS (def /mnt/cosecha/escritorios/sway-rootfs) rootfs del perfil, ya hidratado con
|
|
# scripts/hydrate-profile.py
|
|
# BASE (def .dev-fs/alpine) capa con la libc
|
|
# W/H (def 1280x800) tamaño de la ventana
|
|
# APP (def foot) cliente que se lanza dentro
|
|
# OUT (def /mnt/cosecha/escritorios) dónde deja `sway-nested.png`
|
|
# SECS (def 0 = quedarse abierto) segundos antes de cerrar solo
|
|
set -u
|
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
|
|
RFS="${RFS:-/mnt/cosecha/escritorios/sway-rootfs}"
|
|
BASE="${BASE:-$ROOT/.dev-fs/alpine}"
|
|
W="${W:-1280}"; H="${H:-800}"; APP="${APP:-foot}"
|
|
OUT="${OUT:-/mnt/cosecha/escritorios}"; SECS="${SECS:-0}"
|
|
mkdir -p "$OUT"
|
|
|
|
[ -d "$RFS" ] || { echo "falta el rootfs del perfil: $RFS" >&2
|
|
echo " scripts/hydrate-profile.py escritorio-sway --store /mnt/cosecha/store --into $RFS" >&2; exit 1; }
|
|
[ -d "$BASE" ] || { echo "falta la capa base con la libc: $BASE" >&2; exit 1; }
|
|
|
|
# El socket del compositor del HOST. Es lo único del host que cruza: un socket, no una librería.
|
|
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"
|
|
|
|
exec bwrap \
|
|
--overlay-src "$BASE" --overlay-src "$RFS" --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 sway-nested \
|
|
--uid 0 --gid 0 --die-with-parent \
|
|
--setenv PATH /usr/bin:/bin:/usr/sbin:/sbin \
|
|
--setenv HOME /root --setenv SHELL /bin/sh --setenv TERM xterm-256color \
|
|
--setenv XDG_RUNTIME_DIR /run/user/0 \
|
|
--setenv WAYLAND_DISPLAY /run/wl-host \
|
|
--setenv WLR_BACKENDS wayland \
|
|
--setenv WLR_RENDERER pixman \
|
|
--setenv WLR_WL_OUTPUTS 1 \
|
|
--setenv XDG_DATA_DIRS /usr/share \
|
|
--setenv FONTCONFIG_PATH /etc/fonts \
|
|
/bin/sh -c '
|
|
set -u
|
|
mkdir -p /run/user/0 /root/.config/sway /etc; chmod 700 /run/user/0
|
|
# /etc/passwd: sin él, cualquier getpwuid() falla y yambar no arranca (cicatriz de headless).
|
|
[ -s /etc/passwd ] || echo "root:x:0:0:root:/root:/bin/sh" > /etc/passwd
|
|
cat > /root/.config/sway/config <<EOF
|
|
output * bg #1a4b8c solid_color
|
|
default_border pixel 2
|
|
EOF
|
|
echo "-- sway (backend wayland, '"$W"'x'"$H"')…"
|
|
# `-d`: la línea que dice QUÉ tema de cursor cargó wlroots es de nivel DEBUG. Sin `-d` el log
|
|
# queda mudo justo sobre lo que este arnés existe para comprobar.
|
|
WLR_WL_OUTPUT_WIDTH='"$W"' WLR_WL_OUTPUT_HEIGHT='"$H"' \
|
|
sway -d -c /root/.config/sway/config >/tmp/sway.log 2>&1 &
|
|
SWAY=$!
|
|
i=0
|
|
while [ $i -lt 60 ]; do
|
|
S=$(ls /run/user/0/sway-ipc.* 2>/dev/null | head -1)
|
|
[ -n "${S:-}" ] && break
|
|
kill -0 $SWAY 2>/dev/null || { echo " !! sway murió:"; tail -20 /tmp/sway.log; exit 1; }
|
|
i=$((i+1)); sleep 0.5
|
|
done
|
|
[ -n "${S:-}" ] || { echo " !! sway no abrió su IPC en 30 s:"; tail -20 /tmp/sway.log; exit 1; }
|
|
echo " sway OK — ventana en tu pantalla"
|
|
export SWAYSOCK="$S"
|
|
# El cliente se lanza DESPUÉS del socket: los `exec` de la config disparan antes de que exista
|
|
# el workspace y mueren con «Failed to create launch context».
|
|
#
|
|
# ⚠ `yambar` NO va en un bloque `bar { status_command … }`: es una barra COMPLETA de layer-shell,
|
|
# no un productor de estado para swaybar. Puesta ahí, sway rechaza la config ENTERA («Error(s)
|
|
# loading config!») y arranca sin fondo ni bordes — un fallo que se lee como «el escritorio está
|
|
# roto» cuando lo único mal es una línea. Se lanza como cliente, igual que foot.
|
|
swaymsg exec '"$APP"' >/dev/null 2>&1 || '"$APP"' &
|
|
sleep 4
|
|
echo "== clientes =="; swaymsg -t get_tree 2>/dev/null | tr "," "\n" | grep "\"app_id\"" | grep -v null | sort -u
|
|
# La línea que PRUEBA el tema de cursor: sin `adwaita-cursors` wlroots no encuentra el tema
|
|
# `default` y el puntero no se dibuja. Se reintenta porque el tema se carga cuando el puntero
|
|
# entra por primera vez, no al arrancar — mirarlo una sola vez daba un ⚠ falso.
|
|
echo "== cursores =="
|
|
j=0; while [ $j -lt 10 ]; do
|
|
grep -i "cursor theme" /tmp/sway.log && break
|
|
j=$((j+1)); sleep 1
|
|
[ $j -eq 10 ] && echo " ⚠ wlroots NO cargó ningún tema de cursor"
|
|
done
|
|
# La captura. ⚠ `grim` hay que apuntarlo al socket de NUESTRO sway: adentro `WAYLAND_DISPLAY`
|
|
# es el del HOST (es lo que sway necesita para nestear), así que un `grim` a secas captura la
|
|
# pantalla del host entera — sale una foto perfecta… del escritorio de al lado. Medido.
|
|
# El cursor NO sale en la captura (no está en el framebuffer de screencopy): para verlo hay que
|
|
# mirar la ventana. Esto prueba lo otro — que los clientes dibujaron.
|
|
WLSWAY=$(basename "$(ls /run/user/0/wayland-* 2>/dev/null | grep -v lock | head -1)")
|
|
if command -v grim >/dev/null 2>&1 && [ -n "${WLSWAY:-}" ]; then
|
|
WAYLAND_DISPLAY="$WLSWAY" grim /salida/sway-nested.png 2>/tmp/grim.log \
|
|
&& echo "== captura (por $WLSWAY): '"$OUT"'/sway-nested.png" \
|
|
|| { echo "== captura FALLÓ:"; tail -3 /tmp/grim.log; }
|
|
fi
|
|
echo "== sway.log (cola) =="; grep -vi "Basic output test" /tmp/sway.log | tail -4
|
|
if [ '"$SECS"' -gt 0 ]; then sleep '"$SECS"'; kill $SWAY 2>/dev/null; else wait $SWAY; fi
|
|
'
|