hello.zig (3461B)
1 const std = @import("std"); 2 const mem = std.mem; 3 const posix = std.posix; 4 5 const wayland = @import("wayland"); 6 const wl = wayland.client.wl; 7 const xdg = wayland.client.xdg; 8 9 const Context = struct { 10 shm: ?*wl.Shm, 11 compositor: ?*wl.Compositor, 12 wm_base: ?*xdg.WmBase, 13 }; 14 15 pub fn main() anyerror!void { 16 const display = try wl.Display.connect(null); 17 const registry = try display.getRegistry(); 18 19 var context = Context{ 20 .shm = null, 21 .compositor = null, 22 .wm_base = null, 23 }; 24 25 registry.setListener(*Context, registryListener, &context); 26 if (display.roundtrip() != .SUCCESS) return error.RoundtripFailed; 27 28 const shm = context.shm orelse return error.NoWlShm; 29 const compositor = context.compositor orelse return error.NoWlCompositor; 30 const wm_base = context.wm_base orelse return error.NoXdgWmBase; 31 32 const buffer = blk: { 33 const width = 128; 34 const height = 128; 35 const stride = width * 4; 36 const size = stride * height; 37 38 const fd = try posix.memfd_create("hello-zig-wayland", 0); 39 try posix.ftruncate(fd, size); 40 const data = try posix.mmap( 41 null, 42 size, 43 posix.PROT.READ | posix.PROT.WRITE, 44 .{ .TYPE = .SHARED }, 45 fd, 46 0, 47 ); 48 @memcpy(data, @embedFile("cat.bgra")); 49 50 const pool = try shm.createPool(fd, size); 51 defer pool.destroy(); 52 53 break :blk try pool.createBuffer(0, width, height, stride, wl.Shm.Format.argb8888); 54 }; 55 defer buffer.destroy(); 56 57 const surface = try compositor.createSurface(); 58 defer surface.destroy(); 59 const xdg_surface = try wm_base.getXdgSurface(surface); 60 defer xdg_surface.destroy(); 61 const xdg_toplevel = try xdg_surface.getToplevel(); 62 defer xdg_toplevel.destroy(); 63 64 var running = true; 65 66 xdg_surface.setListener(*wl.Surface, xdgSurfaceListener, surface); 67 xdg_toplevel.setListener(*bool, xdgToplevelListener, &running); 68 69 surface.commit(); 70 if (display.roundtrip() != .SUCCESS) return error.RoundtripFailed; 71 72 surface.attach(buffer, 0, 0); 73 surface.commit(); 74 75 while (running) { 76 if (display.dispatch() != .SUCCESS) return error.DispatchFailed; 77 } 78 } 79 80 fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, context: *Context) void { 81 switch (event) { 82 .global => |global| { 83 if (mem.orderZ(u8, global.interface, wl.Compositor.interface.name) == .eq) { 84 context.compositor = registry.bind(global.name, wl.Compositor, 1) catch return; 85 } else if (mem.orderZ(u8, global.interface, wl.Shm.interface.name) == .eq) { 86 context.shm = registry.bind(global.name, wl.Shm, 1) catch return; 87 } else if (mem.orderZ(u8, global.interface, xdg.WmBase.interface.name) == .eq) { 88 context.wm_base = registry.bind(global.name, xdg.WmBase, 1) catch return; 89 } 90 }, 91 .global_remove => {}, 92 } 93 } 94 95 fn xdgSurfaceListener(xdg_surface: *xdg.Surface, event: xdg.Surface.Event, surface: *wl.Surface) void { 96 switch (event) { 97 .configure => |configure| { 98 xdg_surface.ackConfigure(configure.serial); 99 surface.commit(); 100 }, 101 } 102 } 103 104 fn xdgToplevelListener(_: *xdg.Toplevel, event: xdg.Toplevel.Event, running: *bool) void { 105 switch (event) { 106 .configure => {}, 107 .close => running.* = false, 108 } 109 }