Hyprland on Kandelo - a dwindle tiling desktop with workspaces, keybinds, and hyprctl-style control - #976
Open
mho22 wants to merge 6 commits into
Open
Hyprland on Kandelo - a dwindle tiling desktop with workspaces, keybinds, and hyprctl-style control#976mho22 wants to merge 6 commits into
mho22 wants to merge 6 commits into
Conversation
Contributor
Phase B-1 matrix build status —
|
| Package | Arch | Status | Sha |
|---|---|---|---|
| alsa-lib | wasm32 | built | 543cb376 |
| libcurl | wasm32 | built | b4d20311 |
| libcxx | wasm32 | built | d46e071d |
| libcxx | wasm64 | built | 55409df4 |
| libdrm | wasm32 | built | c5a0b0dc |
| libevdev | wasm32 | built | 50d21500 |
| libffi | wasm32 | built | d042a8c3 |
| libinput-lite | wasm32 | built | e3060a10 |
| libinput | wasm32 | built | 71518e16 |
| libpng | wasm32 | built | 29bd2fa8 |
| libudev | wasm32 | built | 08d0d1fe |
| libwayland | wasm32 | built | 664823ce |
| libxkbcommon | wasm32 | built | d4833e99 |
| libxml2 | wasm32 | built | 1b0e159e |
| libxml2 | wasm64 | built | 8a166364 |
| mtdev | wasm32 | built | 0adba22d |
| openssl | wasm32 | built | 4744fc1a |
| openssl | wasm64 | built | 867ed8f7 |
| sdl2 | wasm32 | built | 8329d055 |
| sqlite | wasm32 | built | c7fbdcfc |
| sqlite | wasm64 | built | 8a761d10 |
| zlib | wasm32 | built | 3e5696ca |
| zlib | wasm64 | built | c0691082 |
| bc | wasm32 | built | 64150f08 |
| bzip2 | wasm32 | built | cf2d3bc2 |
| coreutils | wasm32 | built | c63c2cf7 |
| curl | wasm32 | built | ae07bfd5 |
| dash | wasm32 | built | 9c9fdf54 |
| diffutils | wasm32 | built | 70f96266 |
| dinit | wasm32 | built | 1071644d |
| fbdoom | wasm32 | built | 685bf5b1 |
| file | wasm32 | built | 6120a6b2 |
| findutils | wasm32 | built | 315afbdb |
| gawk | wasm32 | built | 3a47b550 |
| git | wasm32 | built | c3e3a422 |
| grep | wasm32 | built | fea66afb |
| gzip | wasm32 | built | ca83da7c |
| kandelo-sdk | wasm32 | built | 4b815009 |
| kernel | wasm32 | built | e14cd2e1 |
| less | wasm32 | built | 732f2606 |
| lsof | wasm32 | built | c4141dcb |
| m4 | wasm32 | built | bf234e77 |
| make | wasm32 | built | 82a016b2 |
| mariadb | wasm32 | built | 36587f54 |
| mariadb | wasm64 | built | 7ccde5d1 |
| msmtpd | wasm32 | built | 6ae1debf |
| nano | wasm32 | built | ae92d650 |
| ncurses | wasm32 | built | 9662fe5a |
| netcat | wasm32 | built | 09531db9 |
| nginx | wasm32 | built | 997ba1c5 |
| php | wasm32 | built | 6aac20de |
| posix-utils-lite | wasm32 | built | 4c90f623 |
| sed | wasm32 | built | 8eba8c39 |
| spidermonkey | wasm32 | built | ab8b4de8 |
| tar | wasm32 | built | 8eb86d45 |
| tcl | wasm32 | built | c445e96a |
| unzip | wasm32 | built | d24b3134 |
| userspace | wasm32 | built | a420e097 |
| vim | wasm32 | built | f5a07ef3 |
| wget | wasm32 | built | a1e2342e |
| xz | wasm32 | built | fc99016f |
| zip | wasm32 | built | 39cd06e4 |
| zstd | wasm32 | built | d3274e03 |
| bash | wasm32 | built | 27abbe01 |
| mariadb-test | wasm32 | built | 3f563124 |
| mariadb-vfs | wasm32 | built | a3e3e958 |
| mariadb-vfs | wasm64 | built | 607d4651 |
| nethack | wasm32 | built | cc88c382 |
| node | wasm32 | built | 995190fe |
| spidermonkey-node | wasm32 | built | 6860ec20 |
| vim-browser-bundle | wasm32 | built | e3161b28 |
| nethack-browser-bundle | wasm32 | built | d7b61a73 |
| rootfs | wasm32 | built | 4cbb9ee7 |
| shell | wasm32 | built | b18f57be |
| lamp | wasm32 | built | e286a798 |
| node-vfs | wasm32 | built | 4fd5df7b |
| wordpress | wasm32 | built | f16deacd |
Auto-generated; replaced on each push. Raw data in the publish-status workflow artifact.
mho22
force-pushed
the
explore-dri-hyprland
branch
from
July 18, 2026 16:26
457d76e to
a01ef50
Compare
mho22
marked this pull request as ready for review
July 23, 2026 18:27
mho22
force-pushed
the
explore-dri-wayland
branch
from
August 21, 2026 10:02
e9ca2d3 to
1d4b00b
Compare
mho22
force-pushed
the
explore-dri-hyprland
branch
from
August 21, 2026 10:03
3104fbc to
66c47da
Compare
mho22
force-pushed
the
explore-dri-wayland
branch
from
August 24, 2026 19:08
1d4b00b to
a3ccc13
Compare
mho22
force-pushed
the
explore-dri-hyprland
branch
from
August 24, 2026 19:08
66c47da to
050f429
Compare
mho22
force-pushed
the
explore-dri-wayland
branch
from
August 26, 2026 14:37
a3ccc13 to
af3e6c7
Compare
mho22
force-pushed
the
explore-dri-hyprland
branch
from
August 26, 2026 14:37
050f429 to
df918dd
Compare
This was referenced Aug 26, 2026
mho22
force-pushed
the
explore-dri-wayland
branch
from
August 28, 2026 20:14
af3e6c7 to
539230f
Compare
mho22
force-pushed
the
explore-dri-hyprland
branch
from
August 28, 2026 20:14
df918dd to
916f226
Compare
Compositing three clients by copying their pixels through the CPU is what limits the desktop. A client can now render into a GPU buffer object and the compositor binds it as a foreign texture, so a frame reaches the screen without a readback. Several GL clients share one host context, and each non-master client is routed to its own FBO — a producer draws into the target the compositor later samples, which is what makes the handoff zero-copy.
The protocol a stock client uses to hand the compositor a GPU buffer instead of shared memory. Import reuses the existing shm_buffer path once the descriptor is resolved, so a dmabuf surface composites through the same code as everything else; LINEAR modifiers and version 3 are what current clients ask for.
Two clients that were written against real Wayland, not against this compositor. SDL2's own Wayland+GLES2 backend runs end-to-end, and wlcube drives libwayland-egl directly. They matter because they fail differently from in-tree clients: an in-tree client can be written around a gap in the compositor, while upstream code either finds what the protocol promises or breaks.
The compositor gains what makes a tiling desktop rather than a surface host: a dwindle layout that splits the output as windows arrive, N workspaces per output with SUPER+digit to switch and move, a config-file keybind engine, and server-side decorations so window frames are drawn by the compositor rather than by each client. `kwlctl` is the control channel — a newline-delimited command and event socket at /tmp/kwlctl-0, the analog of hyprctl, which is how a bar or a script reads desktop state and drives it. Resize is client-side: the layout tells a client its new box and the client redraws, so a drag does not block on the compositor. `/?demo=hyprland` boots the result in the browser.
Three problems that only appear once real clients start and stop under a window manager. A spawned client could freeze because its DRI buffer object kept a reference that was never dropped. Launch keybinds bound to the wrong target. A foreground wlterm was started through the forking spawn path, which is wrong for a client that should own the terminal it was launched from.
`scripts/ci-vitest-evidence-classes.tsv` must exactly cover the live Vitest file inventory, so `ci-run-test-suite.sh vitest exact-abi-source` refuses to enumerate while the two drift. This branch raises ABI_VERSION, which is exactly when that group runs. Classify the test files this branch adds, and drop the rows for files it no longer carries. A file is `source-only` only when its whole import closure stays clear of the binary resolver; the runner enforces that separately from the cover check. The smokes exec staged wasm, so they are `prepared-product`; the remaining unit tests import only `host/src/`.
mho22
force-pushed
the
explore-dri-wayland
branch
from
August 30, 2026 09:10
539230f to
b5d3c7a
Compare
mho22
force-pushed
the
explore-dri-hyprland
branch
from
August 30, 2026 09:10
916f226 to
ab82ed9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
explore-dri-wayland(#948) composites floating windows onto a real KMS scanout surface, but it stops at "windows on a screen." It has no window manager: no tiling, no workspaces, no keyboard-driven window control — the things that make a Wayland compositor usable as a desktop rather than a demo canvas. To show that Kandelo's DRI/KMS + Wayland stack can host a full desktop environment, it needs the window-management layer compositors like Hyprland provide.This branch builds a Hyprland-class tiling window manager into
wlcompositorand ships a/?demo=hyprlandbrowser demo: a clock and two terminals tiled into gapped, decorated slots and driven entirely from the keyboard.Fourth layer of the six-PR DRI stack (#698 → #709 → #948 → #976 → #1318 → #1241). It stacks on
explore-dri-wayland.Terms used below: dwindle = Hyprland's default recursive binary-split tiling layout; hyprctl = Hyprland's control CLI/IPC; SSD = server-side decorations, where the compositor draws the title bar, border and focus ring instead of the client; bo = graphics buffer object; killactive = the "close the focused window" action.
What changed
GPU rendering and buffer import
zwp_linux_dmabuf_v1buffer import, reusing the existingshm_bufferimport path. Addslinux-dmabuf-v1.xmlandxdg-decoration-unstable-v1.xmltowayland-protocols.The tiling window manager (
programs/wlcompositor/wlcompositor.c)WLC_LAYOUTflag: recursive binary splits into gapped slots.SUPER+digit to switch andSUPER+SHIFT+digit to move the focused window.kwlctl, the hyprctl analog (programs/wlcompositor/kwlctl.c): a Hyprlandsocket2-formatactivewindow>>/workspace>>event stream, plus a control socket for querying and commanding the compositor.bind = MOD, key, action, paramlines from/etc/kandelo/wlcompositor.conf.xdg-decoration: the compositor draws window borders and a focus ring.xdgconfigure rather than drawing fixed-size islands.Demo and clients
/?demo=hyprland: a dwindle-tiled clock and two terminals, with app-launch keybinds (CTRL+Return→wlterm,CTRL+K→wlclock,CTRL+P→wlpaint) andCTRL+W→ killactive.wlterm,wlclockandwlpaintresize to their dictated tile and tear down cleanly on close.wltermSIGHUPs its shell so a window close does not wedge onwaitpid.The fixes a running desktop exposed
posix_spawnover-decremented the inherited scanout bos' channel refcount, tombstoning the compositor's own buffer and freezing every subsequent composite. Fixed by scoping the inherited-bo refcount bump to spawn (crates/kernel/src/process_table.rs), with guard tests.CLIENT_CONNECTED. The compositor now emits an authoritativeKBD_FOCUS app_id=…marker, consistent with its existingTILEandWORKSPACEmarkers, and the gate waits for focus to reach the fresh terminal before killactive. No compositor semantics change.Notes
ABI_VERSIONbump. This layer is user-space C plus host TypeScript plus additive kernel changes. Toolkit on Kandelo — the C/C++ library stack behind foot, Waybar and mako #1318 up-stack makes the 43 → 44 bump.Both hosts
The GPU-compositing path exists only in the browser — the headless Node GL stub has no readback — so the compositor's GPU renderer and the
/?demo=hyprlandgate are browser-only, while the Node smokes assert the inverse (WLC_RENDERER cpu). The shared compositor and kernel code takes effect on both. Coverage lands on the side it exercises:host/test/wlcompositor-*-smoke(Node) for tiling, keybinds,kwlctl, decoration and resize;apps/browser-demos/test/kandelo-hyprland.spec.ts(Chromium) for the tiled desktop, the launch/workspace/killactive keybinds, and the SCM_RIGHTS launch-storm regression.Rebased and rebuilt
This branch sits on
explore-dri-waylandat539230f18. The history was rebuilt from 18 commits to 6.Against the previous tip, 18 files differ outside those
mainitself moved. Seventeen are comment-only — plan labels (PR6,PR10,PR14a–PR14f,step 11–13) replaced by the fact each stood for. The eighteenth is a deletion:apps/browser-demos/test/scratch-hyprland-crash-repro.spec.ts, 164 lines, whose own header readSCRATCH observational repro (uncommitted). No code changed.The earlier description of this PR was marked draft pending the series merge order. That order is now settled: #1318 sits between this branch and #1241.
Verification
Run at the stack tip
ab7ab2b63, which contains all 6 commits here:cargo test -p kandelo --target aarch64-apple-darwin --lib→ 1665 passed, 0 failedbash scripts/check-abi-version.sh→ exit 0scripts/run-libc-tests.sh→ 302 passed, 20 XFAIL, 0 build failures, and 1 unexpected failure:regression/raise-race. That test forks 100 children inside a signal handler; 5 waits returnECHILD, reproducibly.scripts/run-libc-tests.sh:163skips it wheneverCI=true, so it does not gate this PR, and whether it regressed or predates the stack is not yet established.scripts/run-posix-tests.sh→ 174 passed, 0 FAIL, 3 XFAIL, 2 SKIPBoth suites need
WASM_POSIX_RESOLUTION_POLICY=source-only-v1andWASM_POSIX_SOURCE_ONLY_BINARY_ROOT=<repo>/local-binaries/source-only-v1.binaries-abi-v44/index.tomldoes not exist until the toolkit tier merges, so thebinaries/provenance tier cannot be materialized locally. The full host vitest suite needs both provenance tiers resolvable at once, which only CI's prepared workspace provides — it is the gate for that suite and for the browser demos.The stack has since been rebased onto
mainat888e628d5. Two gates were re-run at the new stack tipccc7c6214(explore-dri-omarchy):bash scripts/check-abi-version.sh→ exit 0, snapshot in sync and the 43 → 44 bump consistent;scripts/ci-run-test-suite.sh vitest exact-abi-source→ 3049 passed, 0 failed, with two files failing to collect on paths #1321 moved tocrates/runtime-core/. That collection failure is amaindefect and #1337 fixes it.