4f3b2926
Track wl_surface enter/leave on Window
a73x 2026-04-09 10:18
Commit message
build.zig
| Old | New | ||
|---|---|---|---|
| @@ -120,6 +120,22 @@ pub fn build(b: *std.Build) void { | |||
| 120 | }); | 120 | }); |
| 121 | test_step.dependOn(&b.addRunArtifact(scale_tracker_tests).step); | 121 | test_step.dependOn(&b.addRunArtifact(scale_tracker_tests).step); |
| 122 | 122 | ||
| 123 | // Test wayland.zig | ||
| 124 | const wayland_test_mod = b.createModule(.{ | ||
| 125 | .root_source_file = b.path("src/wayland.zig"), | ||
| 126 | .target = target, | ||
| 127 | .optimize = optimize, | ||
| 128 | .link_libc = true, | ||
| 129 | }); | ||
| 130 | wayland_test_mod.addImport("wayland", wayland_generated_mod); | ||
| 131 | wayland_test_mod.addImport("scale_tracker", scale_tracker_mod); | ||
| 132 | wayland_test_mod.linkSystemLibrary("wayland-client", .{}); | ||
| 133 | wayland_test_mod.linkSystemLibrary("xkbcommon", .{}); | ||
| 134 | const wayland_tests = b.addTest(.{ | ||
| 135 | .root_module = wayland_test_mod, | ||
| 136 | }); | ||
| 137 | test_step.dependOn(&b.addRunArtifact(wayland_tests).step); | ||
| 138 | |||
| 123 | // Test main.zig (and transitively vt.zig via its import) | 139 | // Test main.zig (and transitively vt.zig via its import) |
| 124 | const main_test_mod = b.createModule(.{ | 140 | const main_test_mod = b.createModule(.{ |
| 125 | .root_source_file = b.path("src/main.zig"), | 141 | .root_source_file = b.path("src/main.zig"), |
src/wayland.zig
| Old | New | ||
|---|---|---|---|
| @@ -241,6 +241,10 @@ pub const Window = struct { | |||
| 241 | surface: *wl.Surface, | 241 | surface: *wl.Surface, |
| 242 | xdg_surface: *xdg.Surface, | 242 | xdg_surface: *xdg.Surface, |
| 243 | xdg_toplevel: *xdg.Toplevel, | 243 | xdg_toplevel: *xdg.Toplevel, |
| 244 | tracker: *ScaleTracker, | ||
| 245 | outputs: *std.ArrayListUnmanaged(*Output), | ||
| 246 | scale_generation: u64 = 0, | ||
| 247 | applied_buffer_scale: i32 = 1, | ||
| 244 | configured: bool = false, | 248 | configured: bool = false, |
| 245 | should_close: bool = false, | 249 | should_close: bool = false, |
| 246 | width: u32 = 800, | 250 | width: u32 = 800, |
| @@ -256,6 +260,28 @@ pub const Window = struct { | |||
| 256 | pub fn setTitle(self: *Window, title: ?[:0]const u8) void { | 260 | pub fn setTitle(self: *Window, title: ?[:0]const u8) void { |
| 257 | self.xdg_toplevel.setTitle((title orelse "waystty")); | 261 | self.xdg_toplevel.setTitle((title orelse "waystty")); |
| 258 | } | 262 | } |
| 263 | |||
| 264 | pub fn bufferScale(self: *const Window) i32 { | ||
| 265 | return self.tracker.bufferScale(); | ||
| 266 | } | ||
| 267 | |||
| 268 | pub fn handleSurfaceEnter(self: *Window, wl_out: *wl.Output) void { | ||
| 269 | for (self.outputs.items) |out| { | ||
| 270 | if (out.wl_output == wl_out) { | ||
| 271 | self.tracker.enterOutput(out.name) catch {}; | ||
| 272 | return; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | pub fn handleSurfaceLeave(self: *Window, wl_out: *wl.Output) void { | ||
| 278 | for (self.outputs.items) |out| { | ||
| 279 | if (out.wl_output == wl_out) { | ||
| 280 | self.tracker.leaveOutput(out.name); | ||
| 281 | return; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | } | ||
| 259 | }; | 285 | }; |
| 260 | 286 | ||
| 261 | pub const Connection = struct { | 287 | pub const Connection = struct { |
| @@ -335,9 +361,13 @@ pub const Connection = struct { | |||
| 335 | .surface = try compositor.createSurface(), | 361 | .surface = try compositor.createSurface(), |
| 336 | .xdg_surface = undefined, | 362 | .xdg_surface = undefined, |
| 337 | .xdg_toplevel = undefined, | 363 | .xdg_toplevel = undefined, |
| 364 | .tracker = &self.scale_tracker, | ||
| 365 | .outputs = &self.outputs, | ||
| 338 | }; | 366 | }; |
| 339 | errdefer window.surface.destroy(); | 367 | errdefer window.surface.destroy(); |
| 340 | 368 | ||
| 369 | window.surface.setListener(*Window, surfaceListener, window); | ||
| 370 | |||
| 341 | window.xdg_surface = try wm_base.getXdgSurface(window.surface); | 371 | window.xdg_surface = try wm_base.getXdgSurface(window.surface); |
| 342 | errdefer window.xdg_surface.destroy(); | 372 | errdefer window.xdg_surface.destroy(); |
| 343 | 373 | ||
| @@ -519,6 +549,23 @@ fn xdgSurfaceListener(surface: *xdg.Surface, event: xdg.Surface.Event, window: * | |||
| 519 | } | 549 | } |
| 520 | } | 550 | } |
| 521 | 551 | ||
| 552 | fn surfaceListener(_: *wl.Surface, event: wl.Surface.Event, window: *Window) void { | ||
| 553 | switch (event) { | ||
| 554 | .enter => |e| { | ||
| 555 | const wl_out = e.output orelse return; | ||
| 556 | window.handleSurfaceEnter(wl_out); | ||
| 557 | window.scale_generation += 1; | ||
| 558 | }, | ||
| 559 | .leave => |e| { | ||
| 560 | const wl_out = e.output orelse return; | ||
| 561 | window.handleSurfaceLeave(wl_out); | ||
| 562 | window.scale_generation += 1; | ||
| 563 | }, | ||
| 564 | .preferred_buffer_scale => {}, | ||
| 565 | .preferred_buffer_transform => {}, | ||
| 566 | } | ||
| 567 | } | ||
| 568 | |||
| 522 | fn xdgToplevelListener(_: *xdg.Toplevel, event: xdg.Toplevel.Event, window: *Window) void { | 569 | fn xdgToplevelListener(_: *xdg.Toplevel, event: xdg.Toplevel.Event, window: *Window) void { |
| 523 | switch (event) { | 570 | switch (event) { |
| 524 | .configure => |cfg| { | 571 | .configure => |cfg| { |
| @@ -655,3 +702,20 @@ test "drainSelectionPipeThenRoundtrip drains large payload before roundtrip" { | |||
| 655 | try std.testing.expect(roundtrip_called); | 702 | try std.testing.expect(roundtrip_called); |
| 656 | try std.testing.expectEqualStrings(payload, text); | 703 | try std.testing.expectEqualStrings(payload, text); |
| 657 | } | 704 | } |
| 705 | |||
| 706 | test "Window.bufferScale reflects ScaleTracker entered outputs" { | ||
| 707 | var tracker = ScaleTracker.init(std.testing.allocator); | ||
| 708 | defer tracker.deinit(); | ||
| 709 | |||
| 710 | try tracker.addOutput(1); | ||
| 711 | try tracker.addOutput(2); | ||
| 712 | tracker.setOutputScale(1, 1); | ||
| 713 | tracker.setOutputScale(2, 2); | ||
| 714 | |||
| 715 | // Simulate the bits Window.bufferScale delegates to. | ||
| 716 | try tracker.enterOutput(2); | ||
| 717 | try std.testing.expectEqual(@as(i32, 2), tracker.bufferScale()); | ||
| 718 | |||
| 719 | tracker.leaveOutput(2); | ||
| 720 | try std.testing.expectEqual(@as(i32, 1), tracker.bufferScale()); | ||
| 721 | } | ||