4f3b2926
Track wl_surface enter/leave on Window
a73x 2026-04-09 10:18
Wires a wl_surface listener that routes enter/leave events into the Connection's ScaleTracker, so Window.bufferScale() reflects the current max scale across outputs the surface is mapped to. Also wires up a dedicated wayland_tests module in build.zig — previously the 3 tests in wayland.zig were not being picked up by any test binary. The new test "Window.bufferScale reflects ScaleTracker entered outputs" plus the 3 existing ones now actually run. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
diff --git a/build.zig b/build.zig index 8e236e9..cfab411 100644 --- a/build.zig +++ b/build.zig @@ -120,6 +120,22 @@ pub fn build(b: *std.Build) void { }); test_step.dependOn(&b.addRunArtifact(scale_tracker_tests).step); // Test wayland.zig const wayland_test_mod = b.createModule(.{ .root_source_file = b.path("src/wayland.zig"), .target = target, .optimize = optimize, .link_libc = true, }); wayland_test_mod.addImport("wayland", wayland_generated_mod); wayland_test_mod.addImport("scale_tracker", scale_tracker_mod); wayland_test_mod.linkSystemLibrary("wayland-client", .{}); wayland_test_mod.linkSystemLibrary("xkbcommon", .{}); const wayland_tests = b.addTest(.{ .root_module = wayland_test_mod, }); test_step.dependOn(&b.addRunArtifact(wayland_tests).step); // Test main.zig (and transitively vt.zig via its import) const main_test_mod = b.createModule(.{ .root_source_file = b.path("src/main.zig"), diff --git a/src/wayland.zig b/src/wayland.zig index f19aa7a..476ec45 100644 --- a/src/wayland.zig +++ b/src/wayland.zig @@ -241,6 +241,10 @@ pub const Window = struct { surface: *wl.Surface, xdg_surface: *xdg.Surface, xdg_toplevel: *xdg.Toplevel, tracker: *ScaleTracker, outputs: *std.ArrayListUnmanaged(*Output), scale_generation: u64 = 0, applied_buffer_scale: i32 = 1, configured: bool = false, should_close: bool = false, width: u32 = 800, @@ -256,6 +260,28 @@ pub const Window = struct { pub fn setTitle(self: *Window, title: ?[:0]const u8) void { self.xdg_toplevel.setTitle((title orelse "waystty")); } pub fn bufferScale(self: *const Window) i32 { return self.tracker.bufferScale(); } pub fn handleSurfaceEnter(self: *Window, wl_out: *wl.Output) void { for (self.outputs.items) |out| { if (out.wl_output == wl_out) { self.tracker.enterOutput(out.name) catch {}; return; } } } pub fn handleSurfaceLeave(self: *Window, wl_out: *wl.Output) void { for (self.outputs.items) |out| { if (out.wl_output == wl_out) { self.tracker.leaveOutput(out.name); return; } } } }; pub const Connection = struct { @@ -335,9 +361,13 @@ pub const Connection = struct { .surface = try compositor.createSurface(), .xdg_surface = undefined, .xdg_toplevel = undefined, .tracker = &self.scale_tracker, .outputs = &self.outputs, }; errdefer window.surface.destroy(); window.surface.setListener(*Window, surfaceListener, window); window.xdg_surface = try wm_base.getXdgSurface(window.surface); errdefer window.xdg_surface.destroy(); @@ -519,6 +549,23 @@ fn xdgSurfaceListener(surface: *xdg.Surface, event: xdg.Surface.Event, window: * } } fn surfaceListener(_: *wl.Surface, event: wl.Surface.Event, window: *Window) void { switch (event) { .enter => |e| { const wl_out = e.output orelse return; window.handleSurfaceEnter(wl_out); window.scale_generation += 1; }, .leave => |e| { const wl_out = e.output orelse return; window.handleSurfaceLeave(wl_out); window.scale_generation += 1; }, .preferred_buffer_scale => {}, .preferred_buffer_transform => {}, } } fn xdgToplevelListener(_: *xdg.Toplevel, event: xdg.Toplevel.Event, window: *Window) void { switch (event) { .configure => |cfg| { @@ -655,3 +702,20 @@ test "drainSelectionPipeThenRoundtrip drains large payload before roundtrip" { try std.testing.expect(roundtrip_called); try std.testing.expectEqualStrings(payload, text); } test "Window.bufferScale reflects ScaleTracker entered outputs" { var tracker = ScaleTracker.init(std.testing.allocator); defer tracker.deinit(); try tracker.addOutput(1); try tracker.addOutput(2); tracker.setOutputScale(1, 1); tracker.setOutputScale(2, 2); // Simulate the bits Window.bufferScale delegates to. try tracker.enterOutput(2); try std.testing.expectEqual(@as(i32, 2), tracker.bufferScale()); tracker.leaveOutput(2); try std.testing.expectEqual(@as(i32, 1), tracker.bufferScale()); }