From 7f5de6c15243bd8f3f9952ed091e4dd15e809020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaroslav=20de=20la=20Pe=C3=B1a=20Smirnov?= Date: Thu, 12 Sep 2024 22:51:07 +0300 Subject: pango and cairo with shm Use pango and cairo to render text to the shared mem buffer. --- src/main.zig | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'src/main.zig') diff --git a/src/main.zig b/src/main.zig index 4902176..436e14d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6,6 +6,10 @@ const wayland = @import("wayland"); const wl = wayland.client.wl; const xdg = wayland.client.xdg; +const pangocairo = @import("pangocairo.zig"); +const cairo = pangocairo.cairo; +const pango = pangocairo.pango; + /// Global Wayland registry context; contains pointers to the globals we expect /// from the compositor. const RegistryContext = struct { @@ -22,6 +26,8 @@ const WindowBuffer = struct { wl_buffer: *wl.Buffer, /// Backing data slice from memory mapping for this buffer map: []u8, + /// Cairo surface for painting with cairo + c_surface: cairo.Surface, /// Are we being read by the compositor right now? busy: bool = false, }; @@ -41,6 +47,8 @@ pub const Window = struct { buffers: [2]WindowBuffer = undefined, /// Memory mapped for both buffers buffers_map: []align(mem.page_size) u8 = undefined, + /// Pango font description for rendering our text + font: pango.FontDescription, /// This window's title title: [*:0]const u8, /// Width in pixels @@ -51,6 +59,8 @@ pub const Window = struct { offset: f32 = 0.0, /// Last frame's timestamp in ms last_frame: u32 = 0, + /// Frames per second statistic + current_fps: f32 = 0.0, /// Should we keep this window open? open: bool = true, @@ -64,10 +74,16 @@ pub const Window = struct { .allocator = allocator, .wl_surface = try compositor.createSurface(), .title = title, + // .font = try pango.FontDescription.fromString("monospace 24"), + .font = try pango.FontDescription.create(), }; win.xdg_surface = try wm_base.getXdgSurface(win.wl_surface); win.xdg_toplevel = try win.xdg_surface.getToplevel(); + win.font.setFamily("monospace"); + win.font.setWeight(600); + win.font.setSizePt(18); + try win.allocBuffers(); win.xdg_surface.setListener(*Window, xdgSurfaceListener, win); @@ -86,6 +102,7 @@ pub const Window = struct { /// Destroy this window and all its associated resources pub fn destroy(win: *Window) void { win.destroyBuffers(); + win.font.destroy(); win.xdg_toplevel.destroy(); win.xdg_surface.destroy(); win.wl_surface.destroy(); @@ -94,7 +111,8 @@ pub const Window = struct { /// Allocate new buffers for this window fn allocBuffers(win: *Window) !void { - const stride = win.width * 4; + const c_format = cairo.Format.argb32; + const stride = cairo.Surface.formatStrideForWidth(c_format, win.width); const buffer_size = stride * win.height; const total_size = buffer_size * 2; // we need two buffers @@ -124,12 +142,21 @@ pub const Window = struct { const bsize: usize = @intCast(buffer_size); buffer.busy = false; buffer.map = win.buffers_map[bsize *% i .. bsize *% (i + 1)]; + buffer.c_surface = try cairo.Surface.createImageForData( + buffer.map, + c_format, + win.width, + win.height, + stride, + ); buffer.wl_buffer.setListener(*WindowBuffer, bufferListener, buffer); } } /// Destroy this window's buffers fn destroyBuffers(win: *Window) void { + win.buffers[0].c_surface.destroy(); + win.buffers[1].c_surface.destroy(); win.buffers[0].wl_buffer.destroy(); win.buffers[1].wl_buffer.destroy(); posix.munmap(win.buffers_map); @@ -163,6 +190,25 @@ pub const Window = struct { } } + const layout = try pango.Layout.createForCairo(&buffer.c_surface); + defer layout.unref(); + buffer.c_surface.setSourceRgba(1, 1, 1, 1); + + layout.setFont(win.font); + layout.setText("Hello, wayland!", -1); + buffer.c_surface.moveTo(5, 5); + layout.show(&buffer.c_surface); + + var fps_buf: [32]u8 = undefined; + const fps_output = std.fmt.bufPrintZ( + &fps_buf, + "{d} FPS", + .{win.current_fps}, + ) catch unreachable; + layout.setText(fps_output, -1); + buffer.c_surface.moveTo(5, 40); + layout.show(&buffer.c_surface); + buffer.busy = true; return buffer.wl_buffer; } @@ -230,8 +276,9 @@ pub const Window = struct { if (win.last_frame != 0) { const elapsed: f32 = @floatFromInt(done.callback_data -% win.last_frame); win.offset -= elapsed / 1000.0 * 32.0; + win.current_fps = 1000.0 / elapsed; } - defer win.last_frame = done.callback_data; + win.last_frame = done.callback_data; const wl_buffer = win.drawFrame() catch |err| { std.debug.print("error drawing frame {}\n", .{err}); -- cgit v1.2.3