eb6c0232
Add real-path DisplayOps adapter on Window
a73x 2026-04-16 11:08
Commit message
src/wayland.zig
| Old | New | ||
|---|---|---|---|
| @@ -11,6 +11,12 @@ const c = @cImport({ | |||
| 11 | @cInclude("unistd.h"); | 11 | @cInclude("unistd.h"); |
| 12 | }); | 12 | }); |
| 13 | 13 | ||
| 14 | const frame_loop_mod = @import("frame_loop"); | ||
| 15 | pub const FrameLoop = frame_loop_mod.FrameLoop; | ||
| 16 | pub const DisplayOps = frame_loop_mod.DisplayOps; | ||
| 17 | pub const SurfaceStateView = frame_loop_mod.SurfaceStateView; | ||
| 18 | pub const CallbackToken = frame_loop_mod.CallbackToken; | ||
| 19 | |||
| 14 | pub const Output = struct { | 20 | pub const Output = struct { |
| 15 | wl_output: *wl.Output, | 21 | wl_output: *wl.Output, |
| 16 | name: u32, | 22 | name: u32, |
| @@ -555,6 +561,56 @@ fn choosePreferredMime(mime_types: []const [:0]const u8) ?[:0]const u8 { | |||
| 555 | return null; | 561 | return null; |
| 556 | } | 562 | } |
| 557 | 563 | ||
| 564 | pub const DisplayAdapter = struct { | ||
| 565 | display: *wl.Display, | ||
| 566 | surface: *wl.Surface, | ||
| 567 | // NOTE: The frame listener receives `loop: *FrameLoop` directly through | ||
| 568 | // zig-wayland's setListener data slot, so the adapter does not need to | ||
| 569 | // carry a reference to the loop itself to dispatch .done events. | ||
| 570 | |||
| 571 | fn flushThunk(ctx: *anyopaque) void { | ||
| 572 | const self: *DisplayAdapter = @ptrCast(@alignCast(ctx)); | ||
| 573 | _ = self.display.flush(); | ||
| 574 | } | ||
| 575 | fn prepareReadThunk(ctx: *anyopaque) bool { | ||
| 576 | const self: *DisplayAdapter = @ptrCast(@alignCast(ctx)); | ||
| 577 | return self.display.prepareRead(); | ||
| 578 | } | ||
| 579 | fn readEventsThunk(ctx: *anyopaque) void { | ||
| 580 | const self: *DisplayAdapter = @ptrCast(@alignCast(ctx)); | ||
| 581 | _ = self.display.readEvents(); | ||
| 582 | } | ||
| 583 | fn dispatchPendingThunk(ctx: *anyopaque) void { | ||
| 584 | const self: *DisplayAdapter = @ptrCast(@alignCast(ctx)); | ||
| 585 | _ = self.display.dispatchPending(); | ||
| 586 | } | ||
| 587 | fn getFdThunk(ctx: *anyopaque) std.posix.fd_t { | ||
| 588 | const self: *DisplayAdapter = @ptrCast(@alignCast(ctx)); | ||
| 589 | return self.display.getFd(); | ||
| 590 | } | ||
| 591 | |||
| 592 | fn requestFrameThunk(ctx: *anyopaque, loop: *FrameLoop) anyerror!CallbackToken { | ||
| 593 | const self: *DisplayAdapter = @ptrCast(@alignCast(ctx)); | ||
| 594 | const cb = try self.surface.frame(); | ||
| 595 | cb.setListener(*FrameLoop, frameCallbackListener, loop); | ||
| 596 | return @ptrCast(cb); | ||
| 597 | } | ||
| 598 | |||
| 599 | fn destroyCallbackThunk(_: *anyopaque, token: CallbackToken) void { | ||
| 600 | const cb: *wl.Callback = @constCast(@ptrCast(@alignCast(token))); | ||
| 601 | cb.destroy(); | ||
| 602 | } | ||
| 603 | }; | ||
| 604 | |||
| 605 | fn frameCallbackListener(cb: *wl.Callback, event: wl.Callback.Event, loop: *FrameLoop) void { | ||
| 606 | switch (event) { | ||
| 607 | .done => { | ||
| 608 | const tok: CallbackToken = @ptrCast(cb); | ||
| 609 | loop.onFrameCallbackDone(tok); | ||
| 610 | }, | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 558 | pub const Window = struct { | 614 | pub const Window = struct { |
| 559 | alloc: std.mem.Allocator, | 615 | alloc: std.mem.Allocator, |
| 560 | surface: *wl.Surface, | 616 | surface: *wl.Surface, |
| @@ -568,6 +624,7 @@ pub const Window = struct { | |||
| 568 | should_close: bool = false, | 624 | should_close: bool = false, |
| 569 | width: u32 = 800, | 625 | width: u32 = 800, |
| 570 | height: u32 = 600, | 626 | height: u32 = 600, |
| 627 | display_adapter: DisplayAdapter = undefined, | ||
| 571 | 628 | ||
| 572 | pub fn deinit(self: *Window) void { | 629 | pub fn deinit(self: *Window) void { |
| 573 | self.xdg_toplevel.destroy(); | 630 | self.xdg_toplevel.destroy(); |
| @@ -601,6 +658,33 @@ pub const Window = struct { | |||
| 601 | } | 658 | } |
| 602 | } | 659 | } |
| 603 | } | 660 | } |
| 661 | |||
| 662 | /// Build a DisplayOps vtable that drives the real compositor. | ||
| 663 | pub fn displayOps(self: *Window, display: *wl.Display) DisplayOps { | ||
| 664 | // Carry both display and surface via the owned adapter struct. | ||
| 665 | self.display_adapter = .{ | ||
| 666 | .display = display, | ||
| 667 | .surface = self.surface, | ||
| 668 | }; | ||
| 669 | return .{ | ||
| 670 | .ctx = &self.display_adapter, | ||
| 671 | .flushFn = DisplayAdapter.flushThunk, | ||
| 672 | .prepareReadFn = DisplayAdapter.prepareReadThunk, | ||
| 673 | .readEventsFn = DisplayAdapter.readEventsThunk, | ||
| 674 | .dispatchPendingFn = DisplayAdapter.dispatchPendingThunk, | ||
| 675 | .getFdFn = DisplayAdapter.getFdThunk, | ||
| 676 | .requestFrameFn = DisplayAdapter.requestFrameThunk, | ||
| 677 | .destroyCallbackFn = DisplayAdapter.destroyCallbackThunk, | ||
| 678 | }; | ||
| 679 | } | ||
| 680 | |||
| 681 | pub fn surfaceStateView(self: *const Window) SurfaceStateView { | ||
| 682 | return .{ | ||
| 683 | .configured_ptr = &self.state.configured, | ||
| 684 | .suspended_ptr = &self.state.suspended, | ||
| 685 | .tracker = self.tracker, | ||
| 686 | }; | ||
| 687 | } | ||
| 604 | }; | 688 | }; |
| 605 | 689 | ||
| 606 | pub const Connection = struct { | 690 | pub const Connection = struct { |