Skip to content

Quickshell on Kandelo — Qt 6.10 on wasm32: QtCore, QtGui, QML, and a QtQuick bar on the desktop - #1354

Draft
mho22 wants to merge 13 commits into
explore-dri-omarchyfrom
explore-dri-quattro
Draft

Quickshell on Kandelo — Qt 6.10 on wasm32: QtCore, QtGui, QML, and a QtQuick bar on the desktop#1354
mho22 wants to merge 13 commits into
explore-dri-omarchyfrom
explore-dri-quattro

Conversation

@mho22

@mho22 mho22 commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Why

Omarchy v4 folds Waybar, Walker, Mako, SwayOSD, hyprlock, hypridle, swaybg and polkit-gnome into a single Quickshell QML process, and Quickshell is a QtQuick client. Nothing Qt existed in the registry, so this PR is the floor of that stack: Qt 6.10.2 QtCore, QtConcurrent, QtXml, QtGui and the Wayland platform plugin, static on wasm32, running on the kernel.

It stacks on explore-dri-omarchy (#1241), extending the DRI stack (#698#709#948#976#1318#1241this). The staging plan lands whole: stage 0 is the Qt6 host toolchain, stage 1 is QtCore, stage 2 is QtGui plus the Wayland plugin, stage 3 is QtDeclarative running QML on the kernel, stage 4 is Quickshell 0.3.1, and stage 5 puts Quickshell on the Omarchy desktop as a launcher entry.

What changed

QtCore on wasm32 (stage 1). Qt is the first dependency that cannot use the meson bypass — moc, rcc and uic codegen is woven through qtbase, so it drives its own CMake with host generators from the flake's pinned Qt through QT_HOST_PATH. Three target adaptations, each for a reason the port exposed: -D__linux__=1 because qsystemdetection.h has no wasm branch and reads preprocessor macros, not CMAKE_SYSTEM_NAME; QT_LINUXBASE plus qmutex-honour-qt-linuxbase.patch because Qt 6.10.2 honours that switch in qfutex_p.h but ignores it in qmutex.h, so the configuration static-asserts without the patch; and an empty <linux/fs.h> because Qt defines the one symbol it wants (FICLONE) when the header does not. QProcess starts off at this stage: its forkfd references _Fork, and musl's _Fork.o also carries __post_Fork, which channel_syscall.c does not override, so linking duplicates _Fork. The QProcess paragraph below settles this before stage 4. Qt also baked its configure-time prefix into libQt6Core.a as qt_prfxpath, writing the builder's PID into every downstream program; the recipe now configures against the guest path, relocates at install time, and fails if the staging path survives.

The host qtwaylandscanner (stage 2's build prerequisite). Every Qt Wayland cross-build runs a host qtwaylandscanner. qtbase builds it only if(LINUX), so nixpkgs' darwin qtbase ships neither the generator nor its Qt6WaylandScannerTools CMake package — stage 2 would build on Linux CI and fail on every Mac. flake.nix now builds the generator from qtbase's own src and version, joined into QT_HOST_PATH only where nixpkgs' qtbase declines wayland, so Linux keeps qtbase's own copy and receives no duplicate. The binary stays out of every package recipe on purpose: a package archive is content-hashed and published, so a Mach-O binary inside one makes an arm64 Mac and an x86_64 runner produce different wasm32 archives for the same source.

QtGui and the Wayland platform plugin (stage 2). Qt 6.10 moved the Wayland client platform plugin out of qtwayland and into qtbase, at src/plugins/platforms/wayland. No qtwayland package is needed — the one qtbase recipe now produces libQt6WaylandClient.a, the wayland QPA plugin and the xdg-shell integration, driven by the host scanner above. QtGui's dependencies come from the registry: freetype, fontconfig, harfbuzz, libpng and libxkbcommon. OpenGL stays off, so the client runs on wl_shm — QtQuick will need a graphics API; that is stage 3. One cross-build trap fixed on the way: write_basic_package_version_file bakes the pointer width of the machine that built the host tool into a bitness check, so the wasm32 consumer found the package and refused it ("version: 6.10.2 (64bit)"); clearing CMAKE_SIZEOF_VOID_P omits the check, as Qt's own tools packages do.

The gate is a program, not a recipe assertion. qt_gui_smoke.cpp imports the offscreen, wayland and xdg-shell plugins, asserts both Wayland keys reach the static plugin registry, fills a rect through the raster engine and typesets a string through fontconfig, FreeType and HarfBuzz, on the kernel:

QT_VERSION=6.10.2
PLATFORM=offscreen
WAYLAND_PLUGIN=yes
XDG_SHELL_PLUGIN=yes
CORNER=ff000000  CENTRE=ffff0000
GLYPH_PIXELS=228
QT_GUI_SMOKE_OK

The build script also rejects any env. import outside the runtime's own three — the SDK link does not fail on an undefined symbol, it leaves a host import that traps only if that path runs, which is how a missing libxml2 surfaced as Unimplemented import: env.xmlCreatePushParserCtxt at runtime rather than at link. Every archive on the link line was then removed in turn: what remains is what the check or the run demands.

Font enumeration is not claimed. fontconfig matches the staged font and FreeType rasterises it (GLYPH_PIXELS=228), but QFontDatabase reports only Qt's three generic families, never the staged name, so the gate asserts ink and says so in its comment.

qtdemo — the first Qt window on the desktop. The stack above proves itself only offscreen; programs/qtdemo.cpp puts its pixels on the Omarchy desktop. A QRasterWindow draws an animated wave field, gradient-filled type and a live clock through QtGui's raster engine, the wayland QPA plugin and xdg-shell onto wl_shm — antialiasing the C clients' wpkdraw does not have. The desktop wires it in as a launcher entry ("Qt Demo"), and the omarchy fonts.conf gains a sans-serif alias to the staged Inconsolata, because Qt asks for sans-serif where the wpkdraw clients ask for monospace. Two findings from the first run: Qt's wayland plugin resolves the socket through XDG_RUNTIME_DIR and refuses to start without it, and the compositor's COMPOSITE_SAMPLE is one-shot — it fires on the first composite with a mapped surface.

Both hosts gate it. host/test/qtdemo-smoke.test.ts boots wlcompositor and qtdemo under one NodeKernelHost and reads the program's markers — QTDEMO_PLATFORM=wayland, the first paint, QTDEMO_FRAME at 30 and 60 (the frame-callback loop keeps granting frames), a non-black composite sample — then a host-injected Escape closes the window through Qt's xkb state and both processes exit 0. The browser spec (kandelo-omarchy.spec.ts) launches it the way a user does — Ctrl+Space, "qt", Enter — and asserts the same markers plus the seventh tile; the launcher-count gate moves from eight entries to nine.

Qt paints through gbm pools — the invisible-window bug and its gate. The first browser run of qtdemo passed every one of those markers and drew nothing: pure wallpaper where the seventh tile focused. On this kernel a wl_shm pool fd must be a DRI prime fd — the browser compositor composites with its GL renderer, which imports client pools with gbm_bo_import(GBM_BO_IMPORT_FD); Qt's stock backing store allocates a memfd, the import fails EINVAL, and repaint_gl skips the surface while map, focus, tile and the frame-callback loop all keep reporting success. The Node smoke never sees it because the Node compositor is on the CPU renderer, which reads any fd. wayland-shm-gbm-pool.patch backs QWaylandShmBuffer with a renderD128 gbm bo — allocate, gbm_bo_map persistently into the QImage at bo stride, hand gbm_bo_get_fd() to wl_shm_create_pool — the same adaptation foot and GTK already carry.

The class now has its own gate, because every existing one is protocol, not pixels. wlcompositor prints a one-shot GLDRAW app_id= the first time the GL renderer draws a window's own texture, and the browser spec polls it for foot and qtdemo: a window that maps, focuses, tiles and pumps frames but never draws now fails the spec, and the fix was verified by screenshot — the animated Qt card on the canvas, not wallpaper.

QML runs on the kernel (stage 3). qtshadertools cross-builds first — qtdeclarative's CMake hard-requires it even though the software adaptation never compiles a shader at runtime — and qtdeclarative builds QtQml, QtQmlModels and QtQuick with the software scenegraph selected via QT_QUICK_BACKEND=software. One patch carries the stage: qv4-stack-bounds-on-wasm.patch bounds the QV4 engine's stack probes, because the engine derives its native stack base from platform heuristics that do not hold on wasm32 and unpatched it walks past the linear-memory stack into the heap. The qt-qml-smoke gate loads a QML scene on the offscreen platform and asserts rendered non-background pixels through QQuickWindow::grabWindow. Quickshell later widened the stage: qtbase adds QtWidgets (QuickControls2 styles link it) and QtNetwork (src/ipc links Qt::Network unconditionally), and qtdeclarative re-enables qml-network and qml-debug because Quickshell's launcher calls QQmlDebuggingEnabler unguarded. QtNetwork builds with brotli forced off — qtbase's configure auto-detected brotli from the nix host closure and emitted -lbrotlidec with no wasm32 bytes behind it, the host-leak class PR #406 diagnosed.

A MAP_FIXED map inside a mapping carves, not evicts — a kernel fix QML forced. The MAP_FIXED branch of mmap dropped every mapping that overlapped the requested range, including the parts outside it, so a fixed map placed inside a larger mapping erased the whole mapping from the manager's records and a later first-fit search could hand out addresses the program still used. QtQml hit exactly this: its guard-page mprotect path re-maps a page inside the QML stack area, and the stack then got reallocated under the running interpreter. The branch now routes through munmap, which already splits a mapping and keeps the remainder recorded; test_map_fixed_inside_mapping_splits_it pins the carve.

QProcess through forkfd's generic fork fallback. Quickshell needs QProcess, and stage 1 had switched it off. Qt is compiled with __linux__ defined, which routes its bundled forkfd to forkfd_linux.c, whose clone(2) calls cannot exist on this kernel — and whose libc clone() reference pulls musl's _Fork.o through __post_Fork, duplicating the glue's _Fork at link. forkfd-generic-on-wasm.patch keeps wasm off that path with one condition (__linux__ && !__wasm__); forkfd then takes its generic fork() fallback — the same instrumented fork every shell pipeline uses — and reaps through waitid(WNOWAIT) and SIGCHLD, both of which the kernel carries. libc/glue stays untouched. The gui smoke gains a QProcess pass: the program re-execs itself with --child through QProcess::start and asserts the child's exit code and marker.

Quickshell 0.3.1 on wasm32 (stage 4). Quickshell is the QtQuick shell toolkit Omarchy v4 writes its bar and launcher in. The build keeps WAYLAND with WLR_LAYERSHELL and turns off every feature whose dependency this kernel does not carry (DBus, PipeWire, PAM, greetd, X11, Hyprland, screencopy, session-lock, toplevel-management, jemalloc, the crash handler). cli11 2.5.0 ships as a new header-only package for the launcher's CLI parsing. no-wl-proxy-interpose-on-wasm.patch removes upstream's wl_proxy_get_listener interposition — a dynamic-linking mechanism (dlsym RTLD_NEXT plus --export-dynamic-symbol, which wasm-ld lacks) that collides with libwayland-client.a's definition in a static link. Support commits carry the surrounding surface: libdrm installs a relocatable .pc and the linux/asm UAPI shims a __linux__-defining consumer needs, wayland-protocols stages upstream 1.45's canonical share/wayland-protocols/ layout for CMake's pkg_get_variable, and the executable link closes over libffi, libxml2, libiconv, libcharset and the sysroot gbm — the recipe had declared them without linking them, and the resulting env.ffi_prep_cif trap killed quickshell inside libwayland's closure marshalling before the QML engine started. After the fix the only env imports are the three the platform owns.

Every spawn compiled its program twice — the fix that let Quickshell start on Firefox. The SYS_SPAWN preflight resolver (handlePosixSpawnResolve, both hosts) compiled a module that the shared worker's resolveSpawnProgram always discarded, then compileSpawnCandidateSnapshot compiled the same bytes again. The snapshot compile already carries every check the resolver compile provided. On Firefox the duplicate is what broke the desktop: SpiderMonkey reserves one fixed 2 GiB executable-code region per content process for all workers (verified with vmmap — a single 2.0G rwx VM_ALLOCATE region), compiled wasm code is several times the module size (the 93 MB quickshell.wasm costs ~620 MB of arena, measured), and with the desktop's live code at ~1.2 GB the second quickshell compile could not get code memory — InternalError: out of memory, mapped to EIO, surfaced as posix_spawnp: I/O error. The resolver contract narrows to ResolvedSpawnCandidate — bytes and argv, no module — so the duplicate cannot come back. Both host entries drop their WebAssembly.compile; the candidate-binding tests assert byte-identical commits reuse the snapshot module and diverging commits recompile from the committed bytes.

Quickshell joins the desktop (stage 5). The launcher gains a Quickshell entry: Quickshell runs the staged /usr/share/kandelo/quickshell/shell.qml, the compositor's environment carries QT_QUICK_BACKEND=software for every client it spawns, and the PanelWindow maps as a wlr-layer-shell clock bar along the bottom edge, where Waybar does not own the exclusive zone. Two infrastructure fixes made the boot survive: the rootfs superblock capacity doubles to 512 MiB (the omarchy demo stages ~200 MB of desktop binaries; the 256 MiB cap died with ENOSPC at exec-time materialization of /usr/bin/dash), and the local-build engine now exports WASM_POSIX_SOURCE_ONLY_BINARY_ROOT to recipes, so a recipe that boots the kernel host — coreutils-docs runs the real coreutils.wasm — resolves under the source-only policy; ./run.sh local-build completes 150/150 nodes from cold.

The spec grows Gate 5e: launch Quickshell through the launcher and take the LAYER ns=quickshell line as the mapping proof — layer surfaces never emit GLDRAW. The gate runs on Chromium and WebKit. Firefox is excluded with a pointer to the new docs/browser-support.md section: after the double-compile fix Quickshell spawns and runs QML on Firefox, but its first pthread_create needs the thread-patched module — a second legitimate full compile — and ~1.9 GB of live desktop code plus another ~620 MB cannot fit the 2 GiB arena, so QThread::start fails. Disabling the optimizing JIT does not reduce the arena below the cap. That is an engine limit, not host waste — every byte of that code belongs to a running desktop program — so the section records the measured numbers and the spec gates on it.

Verification

At the branch head, inside scripts/dev-shell.sh with the source-only resolution env:

  • apps/browser-demos/test/kandelo-omarchy.spec.ts3 passed on chromium, firefox and webkit, with the Qt gate, both GLDRAW gates, and Gate 5e (Quickshell; documented firefox exclusion)
  • Pixel verification: on the dev server, launcher → Quickshell renders the clock bar along the bottom edge, its time string matching Waybar's clock; a Playwright screenshot of the qtdemo tile shows the animated Qt card, not wallpaper, and the syslog carries no gbm_bo_import error
  • cargo test --workspace --target aarch64-apple-darwin --lib1784 passed, 0 failed (includes test_map_fixed_inside_mapping_splits_it)
  • host/test/posix-spawn.test.ts, spawn-blob-transport.test.ts, spawn-pid-authority.test.tspassed on the narrowed resolver contract
  • bash scripts/check-abi-version.shexit 0, snapshot in sync. The one kernel change (the MAP_FIXED carve) fixes mapping bookkeeping; it moves no ABI surface.
  • cd host && npx vitest run383 files passed, 14 failed. 13 of the 14 fail only because the source-only env changes fixture and package-system expectations; each passes under the default env. The 14th is one test in fork-from-thread.test.ts (see the known defect below).
  • bash scripts/run-libc-tests.sh605 PASS, 20 XFAIL, 1 FAIL: regression/raise-race (known defect below).
  • bash scripts/run-posix-tests.sh174 PASS, 3 XFAIL, 2 SKIP, 0 FAIL.

Known defect, inherited from the base branch: raise-race. regression/raise-race — fork from a caught signal handler on a thread; 100 children, ~14 lost, wait returns ECHILD — fails deterministically on this stack and passes on the pre-rebase line. The cause sits below this PR: the rebased stack's commit 9b79d73b4 redesigned signal/park handling (kandelo_caught_handler_depth plus host-owned SA_RESTART records) and dropped the original line's CH_SIG_RESTART channel-word protocol (ea97a4261). Both runtime commits of this PR (1c1db5e20, e40269649) were revert-tested; the failure persists without them. The failing concurrent fork-from-thread test (errno 12) plausibly shares the same machinery. The fix belongs to the stack stage that owns libc/glue and the host signal records, not to this PR.

Per-stage gates, each verified green at its commit:

  • host/test/qt-gui-smoke.test.ts1 passed (QT_GUI_SMOKE_OK on the kernel, plus the QProcess child pass; the undefined-import check stays green)
  • host/test/qt-qml-smoke.test.tspassed (a QML scene renders non-background pixels through the software scenegraph)
  • host/test/qtdemo-smoke.test.ts1 passed (Qt maps on wlcompositor, animates, composites, closes on Escape)
  • host/test/quickshell-smoke.test.ts1 passed (quickshell.wasm boots, CLI11 parses argv, --version prints build metadata)
  • host/test/qtwaylandscanner-host-tool.test.ts2 passed; host/test/wayland-protocols-scanner.test.ts1 passed; tests/package-system/qtbase-package.test.ts9 passed
  • ./run.sh local-build150/150 nodes, 7/7 products with quickshell and cli11 in the registry roots

mho22 added 13 commits September 1, 2026 16:24
…e scanner nixpkgs declines to build

Qt cross-builds run host generators (moc, rcc, uic, qmltyperegistrar, qmlcachegen) and resolve them through QT_HOST_PATH, refusing a host/target version mismatch, so the flake's pinned Qt 6.10.2 fixes the version the recipes may declare. symlinkJoin folds qtbase, qtdeclarative and qtshadertools into the one prefix Qt's CMake requires; ninja and spirv-opt join the dev shell because Qt configures against them.

qtbase builds its qtwaylandscanner only if(LINUX), so nixpkgs' darwin qtbase ships neither the generator nor its Qt6WaylandScannerTools CMake package — a Qt Wayland cross-build on a Mac stops at the missing host tool. The flake builds the generator from qtbase's own src and version, joined into the host tree only where qtbase declines wayland, so Linux keeps its own copy. host/test/qtwaylandscanner-host-tool.test.ts gates both the tool and the generated xdg-shell glue.
…tform plugin

Qt is the first dependency that cannot use the meson bypass — moc/rcc/uic codegen is woven through qtbase — so the recipe drives Qt's own CMake against the flake's host tools. Three target adaptations, each stated in the script: -D__linux__=1 (qsystemdetection.h has no wasm branch), QT_LINUXBASE plus the qmutex patch (Qt honours the switch in qfutex_p.h but not qmutex.h), and an empty <linux/fs.h>. The baked qt_prfxpath is relocated to the guest prefix at install.

Qt 6.10 moved the Wayland client platform plugin into qtbase, so this one package delivers libQt6WaylandClient.a, the wayland QPA plugin and the xdg-shell integration on wl_shm. wayland-shm-gbm-pool.patch backs QWaylandShmBuffer with a renderD128 gbm bo, the pool contract the browser compositor's GL importer requires. forkfd-generic-on-wasm.patch keeps QProcess on forkfd's generic fork() fallback — the __linux__ define would otherwise route it to clone(2), which this kernel does not have, and musl's _Fork.o would duplicate the glue's _Fork at link. The markdown reader pins Qt's bundled md4c so configure cannot link the build machine's dylib. QtWidgets and QtNetwork build too (Quickshell's QuickControls2 styles and src/ipc link them); brotli is forced off because configure detected the nix host copy with no wasm32 bytes behind it.

qt_gui_smoke.cpp gates the stage on the kernel: plugin registry, raster fill, fontconfig/FreeType/HarfBuzz typesetting, and a QProcess re-exec child. The build script rejects any env. import outside the runtime's three. tests/package-system/qtbase-package.test.ts pins the recipe contract; docs/porting-guide.md records the host-generator technique.
…face CMake consumers resolve

libdrm installs a relocatable libdrm.pc plus the linux/asm UAPI shims a __linux__-defining consumer needs, so Qt clients that include drm.h down its Linux branch compile against the installed headers alone. wayland-protocols stages its vendored XML a second time at upstream 1.45's share/wayland-protocols layout and announces it through wayland-protocols.pc, the shape CMake's pkg_get_variable resolves; ext-background-effect, ext-idle-notify and ext-workspace join the vendored set for Quickshell's wlr modules. Both revisions bump.
The MAP_FIXED branch of mmap dropped every mapping that overlapped the requested range, including the parts outside it, so a fixed map placed inside a larger mapping erased the whole mapping from the manager's records and a later first-fit search could hand out addresses the program still used. QtQml hit exactly this: its guard-page mprotect path re-maps a page inside the QML stack area, and the stack got reallocated under the running interpreter.

The branch now routes through munmap, which already splits a mapping and keeps the remainder recorded. test_map_fixed_inside_mapping_splits_it pins the carve.
…gate

qtshadertools cross-builds first because qtdeclarative's CMake hard-requires it, even though the software adaptation never compiles a shader at runtime. qtdeclarative builds QtQml, QtQmlModels and QtQuick with the software scenegraph; qml-network and qml-debug stay on because Quickshell's launcher links QtNetwork unconditionally and calls QQmlDebuggingEnabler unguarded.

qv4-stack-bounds-on-wasm.patch bounds the QV4 engine's stack probes: the engine derives its native stack base from platform heuristics that do not hold on wasm32, and unpatched it walks past the linear-memory stack into the heap. The qt-qml-smoke gate loads a QML scene on the offscreen platform and asserts rendered non-background pixels through QQuickWindow::grabWindow.
…licy

Two source-only gaps. `build-deps path` computed its cache key and cache root under the default policy regardless of the active one, so the printed path pointed at a tier the source-only engine never fills. And the local-build engine did not hand its output root to recipe children: a recipe that boots the kernel host (coreutils-docs runs the real coreutils.wasm) needs WASM_POSIX_SOURCE_ONLY_BINARY_ROOT under the env-scrubbed dev-shell entry, or the resolver refuses the policy env. The engine now exports the root to source-build children; standalone resolve callers keep exporting it themselves. source_only_recipe_receives_engine_binary_root pins the passthrough.
… exactly once

Every SYS_SPAWN preflight compiled its program twice. The resolver (handlePosixSpawnResolve on both hosts) compiled a module that resolveSpawnProgram in the shared worker always discarded, then compileSpawnCandidateSnapshot compiled the same bytes again from its isolated copy. The snapshot compile already carries every check the resolver compile provided.

On Firefox the duplicate is what broke the omarchy desktop: SpiderMonkey reserves one fixed 2 GiB executable-code region per content process for all workers, compiled wasm code is several times the module size (the 93 MB quickshell.wasm costs ~620 MB), and with the desktop's live code at ~1.2 GB the second quickshell compile could not get code memory — InternalError: out of memory, mapped to EIO, surfaced as posix_spawnp: I/O error.

The resolver contract narrows to ResolvedSpawnCandidate — programBytes and argv, no module — on both hosts, so the duplicate cannot come back. The candidate-binding tests now assert byte-identical commits reuse the snapshot module and diverging commits recompile from the committed bytes.
programs/qtdemo/qtdemo.cpp draws an animated wave field, gradient-filled type and a live clock through QtGui's raster engine, the wayland QPA plugin and xdg-shell onto wl_shm — antialiasing the C clients' wpkdraw does not have. Qt's wayland plugin resolves the socket through XDG_RUNTIME_DIR and refuses to start without it.

host/test/qtdemo-smoke.test.ts boots wlcompositor and qtdemo under one NodeKernelHost and reads the program's markers — QTDEMO_PLATFORM=wayland, the first paint, QTDEMO_FRAME at 30 and 60, a non-black composite sample — then a host-injected Escape closes the window through Qt's xkb state and both processes exit 0.
Quickshell is the QtQuick shell toolkit Omarchy v4 writes its bar and launcher in. The build keeps WAYLAND with WLR_LAYERSHELL and turns off every feature whose dependency this kernel does not carry (DBus, PipeWire, PAM, greetd, X11, Hyprland, screencopy, session-lock, toplevel-management, jemalloc, the crash handler). cli11 2.5.0 ships as a header-only package for the launcher's CLI parsing.

no-wl-proxy-interpose-on-wasm.patch removes upstream's wl_proxy_get_listener interposition — a dynamic-linking mechanism (dlsym RTLD_NEXT plus --export-dynamic-symbol, which wasm-ld lacks) that collides with libwayland-client.a's definition in a static link. The executable link closes over libffi, libxml2, libiconv, libcharset and the sysroot gbm — the recipe had declared them without linking them, and the resulting env.ffi_prep_cif trap killed quickshell inside libwayland's closure marshalling before the QML engine started. After the fix the only env imports are the three the platform owns. The quickshell-smoke gate boots the binary on the kernel and asserts --version.
The launcher gains two entries. Qt Demo runs qtdemo — the seventh tile, fontconfig's new sans-serif alias resolving Qt's default family. Quickshell runs the staged /usr/share/kandelo/quickshell/shell.qml; the compositor's environment carries QT_QUICK_BACKEND=software for every client it spawns, and the PanelWindow maps as a wlr-layer-shell clock bar along the bottom edge, where Waybar does not own the exclusive zone. The rootfs superblock capacity doubles to 512 MiB (the demo stages ~200 MB of desktop binaries; the 256 MiB cap died with ENOSPC at exec-time materialization of /usr/bin/dash) and the source-only Vite asset ceiling rises to 1 GiB so the 93 MB quickshell module fits the retained snapshot set.

wlcompositor prints a one-shot GLDRAW app_id= the first time the GL renderer draws a window's own texture, and the spec polls it for foot and qtdemo: every protocol marker (map, focus, tile, frame callback) still fires for a window whose wl_shm pool the GPU cannot import, which is exactly how an invisible qtdemo first shipped. Gate 5e launches Quickshell through the launcher and takes the LAYER ns=quickshell line as the mapping proof — layer surfaces never emit GLDRAW. Firefox is excluded with a pointer to the new browser-support section: the running desktop's compiled wasm plus Quickshell's main and thread-patched modules exceeds SpiderMonkey's fixed 2 GiB per-process executable-code arena, so its first QThread::start fails. The section records the measured numbers.
perl is a multi-output package, so its binary lands at programs/perl/perl.wasm; run-example.ts still probed the flat programs/perl.wasm and silently skipped the perl examples.
Upstream libdrm's drmHandleEvent does a single read and assumes Linux's blocking read on /dev/dri/cardN parks the caller until the vblank pump delivers an event. This kernel returns 0 immediately on an empty event ring, so a bare drmHandleEvent races the vblank tick: it returns without dispatching, the queued flip stays pending, and the next drmModePageFlip hits EBUSY. Real consumers (SDL2 KMSDRM, weston, mutter) poll first; the fixture now does the same.
… runtime file

The shell package's build.toml moved to revision 32 and shell-lazy-archives grew NCURSES_TERMINFO_RUNTIME_FILE, but the bridge test still asserted revision 30 and staged no terminfo member, so it failed against the tree it verifies. The fixture now writes the terminfo archive the resolver contract names and the revision assertion follows the manifest.
@mho22
mho22 force-pushed the explore-dri-quattro branch from 36d9da7 to 076a470 Compare September 1, 2026 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant