a73x

f743ae41

Decouple rendering from visibility; fix v5 compositor bootstrap

a73x   2026-04-17 06:20

Always render when there is pending work — only gate the frame-callback
commit (flush) on canRender(), so the surface gets its first buffer
before wl_surface.enter arrives. Fixes the bootstrap deadlock where
visible() required enteredCount > 0 but the compositor won't send enter
until a buffer is attached.

Also drops xdg_wm_base bind from v6 to v5 for compositors (e.g. sway)
that don't yet advertise v6.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

diff --git a/src/main.zig b/src/main.zig
index cac9e5a..083552b 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -270,7 +270,7 @@ fn runTerminal(alloc: std.mem.Allocator) !void {

    while (!window.should_close and p.isChildAlive()) {
        const repeat_timeout_ms = remainingRepeatTimeoutMs(keyboard.nextRepeatDeadlineNs());
        const timeout = computePollTimeoutMs(repeat_timeout_ms, render_pending and frame_loop.canRender());
        const timeout = computePollTimeoutMs(repeat_timeout_ms, render_pending);
        try frame_loop.waitForWork(&pollfds_extra, timeout);

        // PTY output
@@ -350,7 +350,6 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
        }

        if (!shouldRenderFrame(render_pending, false, false)) continue;
        if (!bench_unthrottled and !frame_loop.canRender()) continue; // hidden — no Vulkan at all

        // applyPendingScale — Vulkan work, gated on canRender().
        if (scale_pending) {
@@ -625,7 +624,7 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
        frame_ring.push(frame_timing);

        clearConsumedDirtyFlags(&term.render_state.dirty, dirty_rows, refresh_plan);
        if (!bench_unthrottled) try frame_loop.commitRender();
        if (!bench_unthrottled and frame_loop.canRender()) try frame_loop.commitRender();
        render_pending = false;
    }

diff --git a/src/wayland.zig b/src/wayland.zig
index 7afebf7..fef2858 100644
--- a/src/wayland.zig
+++ b/src/wayland.zig
@@ -1220,7 +1220,7 @@ fn registryListener(
            } else if (std.mem.eql(u8, iface, std.mem.span(wl.DataDeviceManager.interface.name))) {
                conn.globals.data_device_manager = registry.bind(g.name, wl.DataDeviceManager, 3) catch return;
            } else if (std.mem.eql(u8, iface, std.mem.span(xdg.WmBase.interface.name))) {
                conn.globals.wm_base = registry.bind(g.name, xdg.WmBase, 6) catch return;
                conn.globals.wm_base = registry.bind(g.name, xdg.WmBase, 5) catch return;
            } else if (std.mem.eql(u8, iface, std.mem.span(wl.Seat.interface.name))) {
                conn.globals.seat = registry.bind(g.name, wl.Seat, 9) catch return;
            } else if (std.mem.eql(u8, iface, std.mem.span(wl.Output.interface.name))) {