diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index df5a7b7..a0e3329 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -71,6 +71,38 @@ borders { Colors are specified in `0xRRGGBB` or `0xRRGGBBAA` hex format. +## Bar + +The bar is an optional widget that shows the time on your screen. Right now, that's it. +It is only created when a `bar` block is present in the config. All settings have +defaults, with the color based on the Catppuccin Mocha theme. An empty block can be used +to enable the widget with all defaults: + +```kdl +bar { +} +``` + +### Bar Settings + +| Setting | Type | Default | Description | +|--------------------|--------|--------------------|-----------------------------------| +| `fonts` | string | `monospace:size=14` | Comma-separated FontConfig fonts | +| `text_color` | color | `0xcdd6f4` | Text color | +| `background_color` | color | `0x1e1e2e` | Background color | +| `position` | enum | `top` | Bar position (`top` or `bottom`) | + +### Margins + +The `margins` child block sets pixel offsets from the anchored edge(s). + +| Setting | Type | Default | +|----------|------|---------| +| `top` | i32 | `0` | +| `right` | i32 | `0` | +| `bottom` | i32 | `0` | +| `left` | i32 | `0` | + ## Tag Overlay The tag overlay is an optional widget that briefly shows your tag state when switching tags. diff --git a/docs/TODO.md b/docs/TODO.md index c1b536e..d151e8f 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -2,7 +2,6 @@ These are in rough order of my priority, though no promises I do them in this order. -- [ ] Add options to the bar - [ ] Make a Rect struct to combine x, y, width, and height - [ ] Support window rules (float/tags/SSD by app-id/title) - [ ] Support overriding config location @@ -31,3 +30,4 @@ These are in rough order of my priority, though no promises I do them in this or - [x] Implement an optional clock bar - [x] Implement a river-tag-overlay clone - [x] Add options to the tag overlay +- [x] Add options to the bar diff --git a/examples/config.kdl b/examples/config.kdl index 192cb28..9be9915 100644 --- a/examples/config.kdl +++ b/examples/config.kdl @@ -18,7 +18,11 @@ borders { color_focused "0x89b4fa" color_unfocused "0x1e1e2e" } -// Tag overlay widget — shown briefly when switching tags +// Bar widget - shows the time +bar { + position top +} +// Tag overlay widget - shown briefly when switching tags // Remove this block to disable the overlay entirely tag_overlay { tag_amount 10 diff --git a/src/Bar.zig b/src/Bar.zig index 2b22302..e184206 100644 --- a/src/Bar.zig +++ b/src/Bar.zig @@ -12,8 +12,10 @@ context: *Context, /// The timezone of the computer. timezone: zeit.timezone.TimeZone, -fonts: *fcft.Font, -font_scale: u31 = 0, +options: Options, + +fcft_fonts: *fcft.Font, +font_scale: u31, output: *Output, @@ -28,22 +30,40 @@ surfaces: ?struct { configured: bool = false, -pub fn init(context: *Context, output: *Output) !Bar { +pub const Position = enum { top, bottom }; + +pub const Options = struct { + /// Comma separated list of FontConfig formatted font specifications + fonts: []const u8 = "monospace:size=14", + /// Color of text on the bar + text_color: pixman.Color = utils.parseRgbaPixmanComptime("0xcdd6f4"), + /// Background color of the bar + background_color: pixman.Color = utils.parseRgbaPixmanComptime("0x1e1e2e"), + + /// Whether the bar is at the top or bottom of the screen + position: Position = .top, + /// Directional margins top, right, bottom, left, in pixels + margins: struct { top: i32 = 0, right: i32 = 0, bottom: i32 = 0, left: i32 = 0 } = .{}, +}; + +pub fn init(context: *Context, output: *Output, options: Options) !Bar { const timezone = try zeit.local(utils.gpa, &context.env); errdefer timezone.deinit(); - const fonts = try getFcftFonts("monospace:size=14", 1); - errdefer fonts.destroy(); + const scale = output.scale; + const fcft_fonts = try getFcftFonts(options.fonts, scale); + errdefer fcft_fonts.destroy(); return .{ .context = context, - .fonts = fonts, + .options = options, + .fcft_fonts = fcft_fonts, + .font_scale = scale, .timezone = timezone, .output = output, }; } -// TODO: Add config options for whether it's top or bottom pub fn initSurface(bar: *Bar) !void { if (bar.surfaces) |_| { // This bar already has a surface, we can exit early @@ -51,6 +71,7 @@ pub fn initSurface(bar: *Bar) !void { } const context = bar.context; + const options = bar.options; const wl_surface = try context.wl_compositor.createSurface(); errdefer wl_surface.destroy(); @@ -60,7 +81,6 @@ pub fn initSurface(bar: *Bar) !void { .getLayerSurface(wl_surface, bar.output.wl_output, .top, "beansprout-bar"); errdefer layer_surface.destroy(); - // TODO: Allow clicking on tags to switch between them? // We don't want our surface to have any input region (default is infinite) const empty_region = try context.wl_compositor.createRegion(); defer empty_region.destroy(); @@ -68,9 +88,11 @@ pub fn initSurface(bar: *Bar) !void { // TODO: Add padding to config const vertical_padding = 5; - const bar_height: u31 = @intCast(bar.fonts.height + 2 * vertical_padding); + const bar_height: u31 = @intCast(bar.fcft_fonts.height + 2 * vertical_padding); layer_surface.setSize(0, bar_height); - layer_surface.setAnchor(.{ .top = true, .right = true, .left = true }); + + layer_surface.setAnchor(.{ .top = options.position == .top, .bottom = options.position == .bottom, .left = true, .right = true }); + layer_surface.setMargin(options.margins.top, options.margins.right, options.margins.bottom, options.margins.left); bar.surfaces = .{ .wl_surface = wl_surface, @@ -85,10 +107,9 @@ pub fn initSurface(bar: *Bar) !void { pub fn deinit(bar: *Bar) void { bar.configured = false; bar.timezone.deinit(); - bar.fonts.destroy(); if (bar.surfaces) |surfaces| { - surfaces.wl_surface.destroy(); surfaces.layer_surface.destroy(); + surfaces.wl_surface.destroy(); bar.context.buffer_pool.surface_count -= 1; } } @@ -144,13 +165,14 @@ pub fn layerSurfaceListener( /// Renders the bar and its components pub fn render(bar: *Bar) !void { const context = bar.context; + const options = bar.options; const scale = bar.output.scale; // Recreate fonts at the output's new scale if (scale != bar.font_scale) { - bar.fonts.destroy(); - bar.fonts = try getFcftFonts("monospace:size=14", scale); + bar.fcft_fonts.destroy(); + bar.fcft_fonts = try getFcftFonts(bar.options.fonts, scale); bar.font_scale = scale; } @@ -165,8 +187,7 @@ pub fn render(bar: *Bar) !void { const buffer = try context.buffer_pool.nextBuffer(bar.context.wl_shm, render_width, render_height); // Fill with a solid color (e.g., dark background) - // TODO: Configure text/bg colors - const bg_color: pixman.Color = .{ .red = 0x1e1e, .green = 0x1e1e, .blue = 0x2e2e, .alpha = 0xffff }; + const bg_color = options.background_color; _ = pixman.Image.fillRectangles( .src, buffer.pixman_image, @@ -181,7 +202,7 @@ pub fn render(bar: *Bar) !void { ); // Set-up text color - const text_color: pixman.Color = .{ .red = 0xffff, .green = 0xffff, .blue = 0xffff, .alpha = 0xffff }; + const text_color = options.text_color; const color = pixman.Image.createSolidFill(&text_color) orelse return error.FailedToCreatePixmanImage; defer _ = color.unref(); @@ -214,7 +235,7 @@ pub fn render(bar: *Bar) !void { const text_width = try bar.textWidth(codepoints); var x: i32 = @divFloor(buffer.width - text_width, 2); - const y: i32 = @divFloor(buffer.height - bar.fonts.height, 2); + const y: i32 = @divFloor(buffer.height - bar.fcft_fonts.height, 2); // Actually render the unicode codepoints try bar.renderChars(codepoints, buffer, &x, y, color); @@ -233,11 +254,11 @@ pub fn render(bar: *Bar) !void { fn textWidth(bar: *Bar, text: []const u32) !i32 { var width: i32 = 0; for (text, 0..) |cp, i| { - const glyph = try bar.fonts.rasterizeCharUtf32(cp, .default); + const glyph = try bar.fcft_fonts.rasterizeCharUtf32(cp, .default); width += glyph.advance.x; if (i > 0) { var x_kern: c_long = 0; - if (bar.fonts.kerning(text[i - 1], cp, &x_kern, null)) { + if (bar.fcft_fonts.kerning(text[i - 1], cp, &x_kern, null)) { width += @intCast(x_kern); } } @@ -261,12 +282,12 @@ fn renderChars( var i: usize = 0; while (i < text.len) : (i += 1) { - glyphs[i] = try bar.fonts.rasterizeCharUtf32(text[i], .default); + glyphs[i] = try bar.fcft_fonts.rasterizeCharUtf32(text[i], .default); kerns[i] = 0; if (i > 0) { var x_kern: c_long = 0; - if (bar.fonts.kerning(text[i - 1], text[i], &x_kern, null)) { + if (bar.fcft_fonts.kerning(text[i - 1], text[i], &x_kern, null)) { kerns[i] = x_kern; } } @@ -303,7 +324,7 @@ fn renderGlyphs( 0, 0, x.* + @as(i32, @intCast(glyphs[i].x)), - y + bar.fonts.ascent - @as(i32, @intCast(glyphs[i].y)), + y + bar.fcft_fonts.ascent - @as(i32, @intCast(glyphs[i].y)), glyphs[i].width, glyphs[i].height, ); @@ -320,7 +341,7 @@ fn renderGlyphs( 0, 0, x.* + @as(i32, @intCast(glyphs[i].x)), - y + bar.fonts.ascent - @as(i32, @intCast(glyphs[i].y)), + y + bar.fcft_fonts.ascent - @as(i32, @intCast(glyphs[i].y)), glyphs[i].width, glyphs[i].height, ); diff --git a/src/Config.zig b/src/Config.zig index 1a35dba..d8e20f8 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -32,7 +32,9 @@ pointer_warp_on_focus_change: bool = true, wallpaper_image_path: ?[]const u8 = null, /// Tag overlay configuration. If null, no overlay is created. -tag_overlay: ?TagOverlayConfig = null, +tag_overlay_config: ?TagOverlayConfig = null, +/// Bar configuration. If null, no bar is created. +bar_config: ?BarConfig = null, /// Tag bind entries parsed from config (tag_bind nodes in keybinds block) tag_binds: std.ArrayList(Keybind) = .{}, @@ -44,6 +46,7 @@ input_configs: std.ArrayList(InputConfig) = .{}, pub const Keybind = keybind_helper.Keybind; pub const PointerBind = pointer_bind_helper.PointerBind; +pub const BarConfig = bar_helper.BarConfig; pub const TagOverlayConfig = tag_overlay_helper.TagOverlayConfig; pub const InputConfig = input_helper.InputConfig; @@ -60,10 +63,11 @@ const NodeName = enum { pointer_warp_on_focus_change, wallpaper_image_path, // Sections with child blocks + bar, borders, + input, keybinds, pointer_binds, - input, tag_overlay, }; @@ -102,6 +106,9 @@ pub fn create() !*Config { if (ic.name) |name| utils.gpa.free(name); } config.input_configs.clearAndFree(utils.gpa); + if (config.bar_config) |bc| { + if (bc.fonts) |fonts| utils.gpa.free(fonts); + } if (config.wallpaper_image_path) |path| { utils.gpa.free(path); } @@ -129,6 +136,9 @@ pub fn destroy(config: *Config) void { if (ic.name) |name| utils.gpa.free(name); } config.input_configs.deinit(utils.gpa); + if (config.bar_config) |bc| { + if (bc.fonts) |fonts| utils.gpa.free(fonts); + } if (config.wallpaper_image_path) |path| { utils.gpa.free(path); } @@ -231,15 +241,8 @@ fn load(config: *Config, reader: *Io.Reader) !void { }; logDebugSettingNode(name, path_str); }, - .borders => { - next_child_block = .borders; - }, - .keybinds => { - next_child_block = .keybinds; - }, - .pointer_binds => { - next_child_block = .pointer_binds; - }, + .bar => next_child_block = .bar, + .borders => next_child_block = .borders, .input => { pending_input_name = if (node.prop(&parser, "name")) |n| try utils.gpa.dupe(u8, utils.stripQuotes(n)) @@ -247,6 +250,12 @@ fn load(config: *Config, reader: *Io.Reader) !void { null; next_child_block = .input; }, + .keybinds => { + next_child_block = .keybinds; + }, + .pointer_binds => { + next_child_block = .pointer_binds; + }, .tag_overlay => { next_child_block = .tag_overlay; }, @@ -258,6 +267,7 @@ fn load(config: *Config, reader: *Io.Reader) !void { .child_block_begin => { if (next_child_block) |child_block| { switch (child_block) { + .bar => try bar_helper.load(config, &parser, hostname), .borders => try borders_helper.load(config, &parser, hostname), .keybinds => try keybind_helper.load(config, &parser, hostname), .pointer_binds => try pointer_bind_helper.load(config, &parser, hostname), @@ -311,6 +321,7 @@ const utils = @import("utils.zig"); const RiverColor = utils.RiverColor; const XkbBindings = @import("XkbBindings.zig"); +const bar_helper = @import("config/bar.zig"); const borders_helper = @import("config/borders.zig"); const input_helper = @import("config/input.zig"); const keybind_helper = @import("config/keybinds.zig"); diff --git a/src/Context.zig b/src/Context.zig index 03dbefd..5612faa 100644 --- a/src/Context.zig +++ b/src/Context.zig @@ -78,7 +78,7 @@ pub fn create(options: Options) !*Context { const env = try process.getEnvMap(utils.gpa); errdefer env.deinit(); - const tag_overlay_timer_fd: ?posix.fd_t = if (options.config.tag_overlay) |_| + const tag_overlay_timer_fd: ?posix.fd_t = if (options.config.tag_overlay_config) |_| posix.timerfd_create(.MONOTONIC, .{ .CLOEXEC = true }) catch |e| blk: { log.err("Failed to create tag overlay timer: {}", .{e}); break :blk null; @@ -133,6 +133,10 @@ pub fn manage(context: *Context) void { binding.destroy(); } + // Capture old config state before destroying + const had_overlay = context.config.tag_overlay_config != null; + const had_bar = context.config.bar_config != null; + // Check if wallpaper path changed before destroying old config const wallpaper_changed = !pathsEqual( context.config.wallpaper_image_path, @@ -150,8 +154,7 @@ pub fn manage(context: *Context) void { } // Handle tag overlay config changes - const had_overlay = context.config.tag_overlay != null; - const has_overlay = new_config.tag_overlay != null; + const has_overlay = new_config.tag_overlay_config != null; if (!had_overlay and has_overlay) { // Create timerfd for newly enabled tag overlay @@ -176,7 +179,7 @@ pub fn manage(context: *Context) void { } // Create new overlay if configured // Create new overlay struct if configured (surfaces created on-demand) - if (new_config.tag_overlay) |tag_overlay_config| { + if (new_config.tag_overlay_config) |tag_overlay_config| { output.tag_overlay = TagOverlay.init(context, output, tag_overlay_config.toTagOverlayOptions()) catch |e| { log.err("Failed to create tag overlay: {}", .{e}); continue; @@ -185,6 +188,32 @@ pub fn manage(context: *Context) void { } } + // Recreate or destroy bars on all outputs + const has_bar = new_config.bar_config != null; + if (had_bar or has_bar) { + var out_it = context.wm.outputs.iterator(.forward); + while (out_it.next()) |output| { + // Destroy existing bar + if (output.bar) |*bar| { + bar.deinit(); + output.bar = null; + } + // Create new bar if configured + if (new_config.bar_config) |bar_config| { + output.bar = Bar.init(context, output, bar_config.toBarOptions()) catch |e| { + log.err("Failed to create bar: {}", .{e}); + continue; + }; + // If the output already has a wl_output, init the surface immediately + if (output.wl_output != null) { + output.bar.?.initSurface() catch |e| { + log.err("Failed to init bar surface: {}", .{e}); + }; + } + } + } + } + if (wallpaper_changed) { if (context.wallpaper_image) |img| img.destroy(); context.wallpaper_image = loadWallpaperImage(new_config); @@ -239,6 +268,7 @@ const wl = wayland.client.wl; const zwlr = wayland.client.zwlr; const utils = @import("utils.zig"); +const Bar = @import("Bar.zig"); const BufferPool = @import("BufferPool.zig"); const Config = @import("Config.zig"); const InputManager = @import("InputManager.zig"); diff --git a/src/Output.zig b/src/Output.zig index 62928bd..4190fb6 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -92,13 +92,15 @@ pub fn create(context: *Context, river_output_v1: *river.OutputV1) !*Output { var output = try utils.gpa.create(Output); errdefer utils.gpa.destroy(output); - var bar = Bar.init(context, output) catch |e| blk: { - log.err("Failed to create a bar: {}", .{e}); - break :blk null; - }; + var bar = if (context.config.bar_config) |bar_config| blk: { + break :blk Bar.init(context, output, bar_config.toBarOptions()) catch |e| { + log.err("Failed to create a bar: {}", .{e}); + break :blk null; + }; + } else null; errdefer if (bar) |*b| b.deinit(); - var tag_overlay = if (context.config.tag_overlay) |tag_overlay_config| blk: { + var tag_overlay = if (context.config.tag_overlay_config) |tag_overlay_config| blk: { break :blk TagOverlay.init(context, output, tag_overlay_config.toTagOverlayOptions()) catch |e| { log.err("Failed to create a tag overlay: {}", .{e}); break :blk null; @@ -377,8 +379,8 @@ pub fn initWallpaperLayerSurface(output: *Output) !void { pub fn deinitWallpaperLayerSurface(output: *Output) void { if (output.surfaces) |surfaces| { - surfaces.wl_surface.destroy(); surfaces.layer_surface.destroy(); + surfaces.wl_surface.destroy(); output.context.buffer_pool.surface_count -= 1; } diff --git a/src/config/bar.zig b/src/config/bar.zig new file mode 100644 index 0000000..6ba7d8f --- /dev/null +++ b/src/config/bar.zig @@ -0,0 +1,186 @@ +// SPDX-FileCopyrightText: 2026 Ben Buhse +// +// SPDX-License-Identifier: GPL-3.0-only + +pub const NodeName = enum { + fonts, + text_color, + background_color, + position, + margins, +}; +pub const MarginsNodeName = enum { top, right, bottom, left }; + +pub const BarConfig = struct { + // Comma separated list of FontConfig formatted font specifications. + // null means use the default ("monospace:size=14"). + fonts: ?[]const u8 = null, + text_color: pixman.Color = utils.parseRgbaPixmanComptime("0xcdd6f4"), + background_color: pixman.Color = utils.parseRgbaPixmanComptime("0x1e1e2e"), + position: Bar.Position = .top, + margin_top: i32 = 0, + margin_right: i32 = 0, + margin_bottom: i32 = 0, + margin_left: i32 = 0, + // TODO: Support only having the bar on specific outputs + // output: []const u8, + + pub fn toBarOptions(config: BarConfig) Bar.Options { + return .{ + .fonts = config.fonts orelse "monospace:size=14", + .text_color = config.text_color, + .background_color = config.background_color, + .position = config.position, + .margins = .{ + .top = config.margin_top, + .right = config.margin_right, + .bottom = config.margin_bottom, + .left = config.margin_left, + }, + }; + } +}; + +pub fn load(config: *Config, parser: *kdl.Parser, hostname: ?[]const u8) !void { + config.bar_config = .{}; // Presence of block = enabled; initialize with defaults + + const BarChild = enum { margins }; + var next_child_block: ?BarChild = null; + + while (try parser.next()) |event| { + switch (event) { + .node => |node| { + if (next_child_block) |child| { + log.warn("Expected child block for bar.{s}, got node instead. Ignoring", .{@tagName(child)}); + next_child_block = null; + } + const node_name = std.meta.stringToEnum(NodeName, node.name); + if (node_name) |name| { + if (!helpers.hostMatches(node, parser, hostname)) { + logDebugHostMismatch(name); + continue; + } + const val_str = utils.stripQuotes(node.arg(parser, 0) orelse ""); + switch (name) { + .fonts => { + if (node.argcount() < 1) { + logWarnMissingNodeArg(name, "font specification"); + continue; + } + config.bar_config.?.fonts = utils.gpa.dupe(u8, val_str) catch @panic("Out of memory"); + logDebugSettingNode(name, val_str); + }, + .position => { + if (std.meta.stringToEnum(Bar.Position, val_str)) |pos| { + config.bar_config.?.position = pos; + logDebugSettingNode(name, val_str); + } else { + logWarnInvalidNodeArg(name, val_str); + } + }, + .margins => next_child_block = .margins, + inline .background_color, + .text_color, + => |tag| { + @field(config.bar_config.?, @tagName(tag)) = utils.parseRgbaPixman(val_str) catch { + logWarnInvalidNodeArg(name, val_str); + continue; + }; + logDebugSettingNode(name, val_str); + }, + } + } else { + helpers.logWarnInvalidNode(node.name); + } + }, + .child_block_begin => { + if (next_child_block) |child| { + switch (child) { + .margins => try loadMarginsBlock(config, parser, hostname), + } + next_child_block = null; + } else { + try helpers.skipChildBlock(parser); + } + }, + .child_block_end => return, + } + } +} + +fn loadMarginsBlock(config: *Config, parser: *kdl.Parser, hostname: ?[]const u8) !void { + while (try parser.next()) |event| { + switch (event) { + .node => |node| { + const node_name = std.meta.stringToEnum(MarginsNodeName, node.name); + if (node_name) |name| { + if (!helpers.hostMatches(node, parser, hostname)) { + logDebugHostMismatch(name); + continue; + } + const val_str = utils.stripQuotes(node.arg(parser, 0) orelse ""); + const val = fmt.parseInt(i32, val_str, 10) catch { + logWarnInvalidNodeArg(name, val_str); + continue; + }; + switch (name) { + .top => config.bar_config.?.margin_top = val, + .right => config.bar_config.?.margin_right = val, + .bottom => config.bar_config.?.margin_bottom = val, + .left => config.bar_config.?.margin_left = val, + } + logDebugSettingNode(name, val_str); + } else { + helpers.logWarnInvalidNode(node.name); + } + }, + .child_block_begin => try helpers.skipChildBlock(parser), + .child_block_end => return, + } + } +} + +inline fn logDebugSettingNode(node_name: anytype, node_value: []const u8) void { + const node_name_type = @TypeOf(node_name); + switch (node_name_type) { + NodeName => log.debug("Setting bar.{s} to {s}", .{ @tagName(node_name), node_value }), + MarginsNodeName => log.debug("Setting bar.margins.{s} to {s}", .{ @tagName(node_name), node_value }), + else => @compileError("This function does not (yet) support type \"" ++ @typeName(@TypeOf(node_name)) ++ "\""), + } +} + +inline fn logDebugHostMismatch(node_name: anytype) void { + const node_name_type = @TypeOf(node_name); + switch (node_name_type) { + NodeName => log.debug("Skipping \"bar.{s}\" (host mismatch)", .{@tagName(node_name)}), + MarginsNodeName => log.debug("Skipping \"bar.margins.{s}\" (host mismatch)", .{@tagName(node_name)}), + else => @compileError("This function does not (yet) support type \"" ++ @typeName(node_name_type) ++ "\""), + } +} + +inline fn logWarnInvalidNodeArg(node_name: anytype, node_value: []const u8) void { + const node_name_type = @TypeOf(node_name); + switch (node_name_type) { + NodeName => log.warn("Invalid \"bar.{s}\" ({s}). Using default value", .{ @tagName(node_name), node_value }), + MarginsNodeName => log.warn("Invalid \"bar.margins.{s}\" ({s}). Using default value", .{ @tagName(node_name), node_value }), + else => @compileError("This function does not (yet) support type \"" ++ @typeName(node_name_type) ++ "\""), + } +} + +inline fn logWarnMissingNodeArg(node_name: NodeName, comptime arg: []const u8) void { + log.warn("\"bar.{s}\" missing " ++ arg ++ " argument. Ignoring", .{@tagName(node_name)}); +} + +const std = @import("std"); +const fmt = std.fmt; + +const kdl = @import("kdl"); +const pixman = @import("pixman"); + +const utils = @import("../utils.zig"); +const Bar = @import("../Bar.zig"); +const Config = @import("../Config.zig"); + +const helpers = @import("helpers.zig"); + +const log = std.log.scoped(.config_bar); diff --git a/src/config/tag_overlay.zig b/src/config/tag_overlay.zig index 4b1e1bf..ae0eaf1 100644 --- a/src/config/tag_overlay.zig +++ b/src/config/tag_overlay.zig @@ -52,42 +52,42 @@ pub const TagOverlayConfig = struct { margin_bottom: i32 = 0, margin_left: i32 = 0, - pub fn toTagOverlayOptions(self: TagOverlayConfig) TagOverlay.Options { + pub fn toTagOverlayOptions(config: TagOverlayConfig) TagOverlay.Options { return .{ - .border_width = self.border_width, - .tag_amount = @intCast(std.math.clamp(@as(u32, self.tag_amount), 1, 32)), - .tags_per_row = @intCast(std.math.clamp(@as(u32, self.tags_per_row), 1, 32)), - .square_size = self.square_size, - .square_inner_padding = self.square_inner_padding, - .square_padding = self.square_padding, - .square_border_width = self.square_border_width, - .background_color = self.background_color, - .border_color = self.border_color, - .square_active_background_color = self.square_active_background_color, - .square_active_border_color = self.square_active_border_color, - .square_active_occupied_color = self.square_active_occupied_color, - .square_inactive_background_color = self.square_inactive_background_color, - .square_inactive_border_color = self.square_inactive_border_color, - .square_inactive_occupied_color = self.square_inactive_occupied_color, + .border_width = config.border_width, + .tag_amount = @intCast(std.math.clamp(@as(u32, config.tag_amount), 1, 32)), + .tags_per_row = @intCast(std.math.clamp(@as(u32, config.tags_per_row), 1, 32)), + .square_size = config.square_size, + .square_inner_padding = config.square_inner_padding, + .square_padding = config.square_padding, + .square_border_width = config.square_border_width, + .background_color = config.background_color, + .border_color = config.border_color, + .square_active_background_color = config.square_active_background_color, + .square_active_border_color = config.square_active_border_color, + .square_active_occupied_color = config.square_active_occupied_color, + .square_inactive_background_color = config.square_inactive_background_color, + .square_inactive_border_color = config.square_inactive_border_color, + .square_inactive_occupied_color = config.square_inactive_occupied_color, .anchors = .{ - .top = self.anchor_top, - .right = self.anchor_right, - .bottom = self.anchor_bottom, - .left = self.anchor_left, + .top = config.anchor_top, + .right = config.anchor_right, + .bottom = config.anchor_bottom, + .left = config.anchor_left, }, .margins = .{ - .top = self.margin_top, - .right = self.margin_right, - .bottom = self.margin_bottom, - .left = self.margin_left, + .top = config.margin_top, + .right = config.margin_right, + .bottom = config.margin_bottom, + .left = config.margin_left, }, - .timeout = self.timeout, + .timeout = config.timeout, }; } }; pub fn load(config: *Config, parser: *kdl.Parser, hostname: ?[]const u8) !void { - config.tag_overlay = .{}; // Presence of block = enabled; initialize with defaults + config.tag_overlay_config = .{}; // Presence of block = enabled; initialize with defaults const TagOverlayChild = enum { anchors, margins }; var next_child_block: ?TagOverlayChild = null; @@ -122,11 +122,11 @@ pub fn load(config: *Config, parser: *kdl.Parser, hostname: ?[]const u8) !void { logWarnInvalidNodeArg(name, val_str); continue; }; - @field(config.tag_overlay.?, @tagName(tag)) = val; + @field(config.tag_overlay_config.?, @tagName(tag)) = val; logDebugSettingNode(name, val_str); }, .timeout => { - config.tag_overlay.?.timeout = fmt.parseInt(u32, val_str, 10) catch { + config.tag_overlay_config.?.timeout = fmt.parseInt(u32, val_str, 10) catch { logWarnInvalidNodeArg(name, val_str); continue; }; @@ -141,7 +141,7 @@ pub fn load(config: *Config, parser: *kdl.Parser, hostname: ?[]const u8) !void { .square_inactive_border_color, .square_inactive_occupied_color, => |tag| { - @field(config.tag_overlay.?, @tagName(tag)) = utils.parseRgbaPixman(val_str) catch { + @field(config.tag_overlay_config.?, @tagName(tag)) = utils.parseRgbaPixman(val_str) catch { logWarnInvalidNodeArg(name, val_str); continue; }; @@ -181,10 +181,10 @@ fn loadAnchorsBlock(config: *Config, parser: *kdl.Parser, hostname: ?[]const u8) const val_str = utils.stripQuotes(node.arg(parser, 0) orelse ""); if (helpers.boolFromKdlStr(val_str)) |val| { switch (name) { - .top => config.tag_overlay.?.anchor_top = val, - .right => config.tag_overlay.?.anchor_right = val, - .bottom => config.tag_overlay.?.anchor_bottom = val, - .left => config.tag_overlay.?.anchor_left = val, + .top => config.tag_overlay_config.?.anchor_top = val, + .right => config.tag_overlay_config.?.anchor_right = val, + .bottom => config.tag_overlay_config.?.anchor_bottom = val, + .left => config.tag_overlay_config.?.anchor_left = val, } logDebugSettingNode(name, val_str); } else { @@ -216,10 +216,10 @@ fn loadMarginsBlock(config: *Config, parser: *kdl.Parser, hostname: ?[]const u8) continue; }; switch (name) { - .top => config.tag_overlay.?.margin_top = val, - .right => config.tag_overlay.?.margin_right = val, - .bottom => config.tag_overlay.?.margin_bottom = val, - .left => config.tag_overlay.?.margin_left = val, + .top => config.tag_overlay_config.?.margin_top = val, + .right => config.tag_overlay_config.?.margin_right = val, + .bottom => config.tag_overlay_config.?.margin_bottom = val, + .left => config.tag_overlay_config.?.margin_left = val, } logDebugSettingNode(name, val_str); } else { @@ -231,6 +231,7 @@ fn loadMarginsBlock(config: *Config, parser: *kdl.Parser, hostname: ?[]const u8) } } } + inline fn logDebugSettingNode(node_name: anytype, node_value: []const u8) void { const node_name_type = @TypeOf(node_name); switch (node_name_type) {