diff --git a/src/Bar.zig b/src/Bar.zig index 275e5a4..79ae538 100644 --- a/src/Bar.zig +++ b/src/Bar.zig @@ -88,7 +88,9 @@ pub fn initSurface(bar: *Bar) !void { // TODO: Add padding to config const vertical_padding = 5; - const bar_height: u31 = @intCast(bar.fcft_fonts.height + 2 * vertical_padding); + // Set size wants logical pixels, so we have to scale the height + const logical_font_height = @divFloor(bar.fcft_fonts.height, @as(i32, bar.font_scale)); + const bar_height: u31 = @intCast(logical_font_height + 2 * vertical_padding); layer_surface.setSize(0, bar_height); layer_surface.setAnchor(.{ .top = options.position == .top, .bottom = options.position == .bottom, .left = true, .right = true }); @@ -366,7 +368,7 @@ fn getFcftFonts(fonts: []const u8, scale: u31) !*fcft.Font { while (it.next()) |font| { if (scale > 1) { // If scale >1, we append :dpi so we can scale the font - log.debug("bwbuhse {d} {d}", .{ base_dpi, scale }); + log.debug("Scaling font DPI: base={d} scale={d}", .{ base_dpi, scale }); const scaled = try arena_alloc.dupeZ( u8, try std.fmt.allocPrint(arena_alloc, "{s}:dpi={}", .{ font, @as(u32, base_dpi) * scale }), diff --git a/src/Context.zig b/src/Context.zig index 5612faa..30d0802 100644 --- a/src/Context.zig +++ b/src/Context.zig @@ -14,7 +14,6 @@ wl_compositor: *wl.Compositor, wl_display: *wl.Display, wl_registry: *wl.Registry, wl_shm: *wl.Shm, -wl_outputs: *std.AutoHashMapUnmanaged(u32, *wl.Output), river_layer_shell_v1: *river.LayerShellV1, zwlr_layer_shell_v1: *zwlr.LayerShellV1, @@ -52,7 +51,6 @@ pub const Options = struct { wl_display: *wl.Display, wl_registry: *wl.Registry, wl_shm: *wl.Shm, - wl_outputs: *std.AutoHashMapUnmanaged(u32, *wl.Output), river_input_manager_v1: *river.InputManagerV1, river_libinput_config_v1: *river.LibinputConfigV1, @@ -93,7 +91,6 @@ pub fn create(options: Options) !*Context { .wl_display = options.wl_display, .wl_registry = options.wl_registry, .wl_shm = options.wl_shm, - .wl_outputs = options.wl_outputs, .river_layer_shell_v1 = options.river_layer_shell_v1, .zwlr_layer_shell_v1 = options.zwlr_layer_shell_v1, .wallpaper_image = loadWallpaperImage(options.config), diff --git a/src/Output.zig b/src/Output.zig index 54b5875..ec65420 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -129,6 +129,7 @@ pub fn destroy(output: *Output) void { output.tag_layout_overrides.deinit(utils.gpa); output.deinitWallpaperLayerSurface(); + if (output.wl_output) |wl_output| wl_output.release(); output.river_output_v1.destroy(); output.river_layer_shell_output_v1.destroy(); utils.gpa.destroy(output); @@ -217,26 +218,19 @@ fn riverOutputListener(river_output_v1: *river.OutputV1, event: river.OutputV1.E output.destroy(); }, .wl_output => |ev| { - // It's guaranteed for the wl_output global to advertised before this event happens - output.wl_output = output.context.wl_outputs.get(ev.name).?; - output.wl_output.?.setListener(*Output, wlOutputListener, output); - - // The wl_output's initial events come during the initial roundtrip - // before we set our listener, so the .done event that triggers - // wallpaper init was lost. Explicitly init the surfaces here. - output.initWallpaperLayerSurface() catch |err| { - const output_name = output.name orelse "some output"; - log.err("failed to add a surface to {s}: {}", .{ output_name, err }); + // Bind the wl_output here so that our listener is set before the server sends the + // initial events (.scale, .mode, .name, .done, etc.). The .done handler will init + // bar/wallpaper surfaces. + const wl_output = output.context.wl_registry.bind( + ev.name, + wl.Output, + 4, + ) catch |err| { + log.err("Failed to bind wl_output: {}", .{err}); + return; }; - if (output.bar) |*bar| { - bar.initSurface() catch |err| { - const output_name = output.name orelse "some output"; - log.err("failed to init bar for {s}: {}", .{ output_name, err }); - return; - }; - } - // Tag overlay surfaces are created on-demand when tags change, - // so we don't init them here. + wl_output.setListener(*Output, wlOutputListener, output); + output.wl_output = wl_output; }, .dimensions => |ev| { // Protocol guarantees that width and height are strictly greater than zero diff --git a/src/main.zig b/src/main.zig index d2e9521..72db61e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -12,17 +12,8 @@ const Globals = struct { wl_compositor: ?*wl.Compositor = null, wl_shm: ?*wl.Shm = null, - wl_outputs: std.AutoHashMapUnmanaged(u32, *wl.Output) = .empty, zwlr_layer_shell_v1: ?*zwlr.LayerShellV1 = null, - - fn deinit(globals: *Globals) void { - var it = globals.wl_outputs.valueIterator(); - while (it.next()) |output| { - output.*.release(); - } - globals.wl_outputs.deinit(utils.gpa); - } }; const usage: []const u8 = @@ -62,7 +53,6 @@ pub fn main() !void { const wl_registry = try wl_display.getRegistry(); var globals: Globals = .{}; - defer globals.deinit(); wl_registry.setListener(*Globals, registryListener, &globals); const errno = wl_display.roundtrip(); @@ -72,8 +62,6 @@ pub fn main() !void { const wl_compositor = globals.wl_compositor orelse utils.interfaceNotAdvertised(wl.Compositor); const wl_shm = globals.wl_shm orelse utils.interfaceNotAdvertised(wl.Shm); - // We can theoretically start with zero wl_outputs; don't panic if it's empty. - const wl_outputs = &globals.wl_outputs; const river_input_manager_v1 = globals.river_input_manager_v1 orelse utils.interfaceNotAdvertised(river.InputManagerV1); const river_libinput_config_v1 = globals.river_libinput_config_v1 orelse utils.interfaceNotAdvertised(river.LibinputConfigV1); @@ -88,7 +76,6 @@ pub fn main() !void { const context = try Context.create(.{ .wl_compositor = wl_compositor, .wl_display = wl_display, - .wl_outputs = wl_outputs, .wl_registry = wl_registry, .wl_shm = wl_shm, .river_input_manager_v1 = river_input_manager_v1, @@ -268,16 +255,8 @@ fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: * }; } else if (mem.orderZ(u8, ev.interface, wl.Output.interface.name) == .eq) { if (ev.version < 4) utils.versionNotSupported(wl.Output, ev.version, 4); - - const wl_output = registry.bind(ev.name, wl.Output, 4) catch |e| { - fatal("Failed to bind to wl_output: {any}", .{@errorName(e)}); - }; - - // We can get multiple wl_outputs, so we have to try add them to our HashMap - // instead of just keeping the one - globals.wl_outputs.put(utils.gpa, ev.name, wl_output) catch |e| { - fatal("Failed to add wl_output to hashmap: {any}", .{@errorName(e)}); - }; + // We don't bind wl_output until the river_output send its .wl_output event + // This way, we don't miss the initial configuration events } else if (mem.orderZ(u8, ev.interface, wl.Shm.interface.name) == .eq) { globals.wl_shm = registry.bind(ev.name, wl.Shm, 1) catch |e| { fatal("Failed to bind to wl_shm: {any}", .{@errorName(e)}); @@ -309,11 +288,9 @@ fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: * }; } }, - .global_remove => |ev| { - // The only remove we care about is for wl_outputs - if (!globals.wl_outputs.remove(ev.name)) { - log.debug("Received a global_remove event for something other than a wl_output", .{}); - } + .global_remove => |_| { + // wl_output removal is handled by the river protocol's .removed + // event, and we don't care about any other globals being removed. }, } }