From e6a45f91b633acb91b2b078b267b893f4520a7d3 Mon Sep 17 00:00:00 2001 From: Squibid Date: Sun, 1 Mar 2026 21:28:53 -0500 Subject: [PATCH] allow borders to be configured using lua --- runtime/share/mezzaluna/master.lua | 9 ++++++ src/View.zig | 10 ++++-- src/lua/View.zig | 52 ++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/runtime/share/mezzaluna/master.lua b/runtime/share/mezzaluna/master.lua index cd5210a..39aef0a 100644 --- a/runtime/share/mezzaluna/master.lua +++ b/runtime/share/mezzaluna/master.lua @@ -96,6 +96,15 @@ local master = function() end }) + mez.hook.add("ViewMapPre", { + callback = function(v) + mez.view.set_border(v, { + color = "#ff0000", + width = 4, + }) + end + }) + mez.hook.add("ViewUnmapPost", { callback = function(v) if v == ctx.tags[ctx.tag_id].master then diff --git a/src/View.zig b/src/View.zig index 8fd1605..2a934ae 100644 --- a/src/View.zig +++ b/src/View.zig @@ -74,7 +74,7 @@ pub fn init(xdg_toplevel: *wlr.XdgToplevel) *View { .surface_tree = undefined, .xdg_toplevel_decoration = null, .borders = undefined, - .border_width = 10, + .border_width = 0, .scene_node_data = .{ .view = self } }; @@ -97,7 +97,7 @@ pub fn init(xdg_toplevel: *wlr.XdgToplevel) *View { self.xdg_toplevel.base.events.ack_configure.add(&self.ack_configure); for (self.borders, 0..) |_, i| { - const color: [4]f32 = .{ 1, 0, 0, 1 }; + const color: [4]f32 = .{ 0, 0, 0, 1 }; self.borders[i] = try wlr.SceneTree.createSceneRect(self.scene_tree, 0, 0, &color); self.borders[i].node.data = self; } @@ -111,6 +111,10 @@ pub fn close(self: *View) void { self.xdg_toplevel.sendClose(); } +pub fn setBorderColor(self: *View, color: *const [4]f32) void { + for (self.borders) |border| border.setColor(color); +} + pub fn toggleFullscreen(self: *View) void { self.fullscreen = !self.fullscreen; if(self.output) |output| { @@ -169,7 +173,7 @@ pub fn setSize(self: *View, width: i32, height: i32) void { /// this function handles all things related to sizing and positioning and /// should be called after something in the size or position is changed -fn resizeBorders(self: *View) void { +pub fn resizeBorders(self: *View) void { // set the position of the surface to not clip with the borders self.surface_tree.node.setPosition(self.border_width, self.border_width); diff --git a/src/lua/View.zig b/src/lua/View.zig index 7cc291d..220a40f 100644 --- a/src/lua/View.zig +++ b/src/lua/View.zig @@ -323,6 +323,58 @@ pub fn get_resizing(L: *zlua.Lua) i32 { return 1; } +// ---Set the borders of a view +// ---@param view_id view_id 0 maps to focused view +/// ---@param options table options for the view's borders +pub fn set_border(L: *zlua.Lua) i32 { + const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L); + + _ = L.pushString("color"); + _ = L.getTable(2); + if (!L.isString(-1)) L.raiseErrorStr("The color must be a string", .{}); + const color = L.checkString(-1); + const border_color: [4]f32 = color: { + errdefer L.raiseErrorStr("The color must be a valid hex string", .{}); + + var start_color_idx: u8 = 0; + if (color[0] == '#') start_color_idx = 1; + const color_fields = (color.len - start_color_idx) / 2; + + var alpha: ?f32 = null; + if (color_fields != 4) { + if (color_fields != 3) L.raiseErrorStr("The color must be at least 6 characters long", .{}); + alpha = 1; + } + + const r = ((@as(f32, @floatFromInt(try std.fmt.parseInt(u8, color[start_color_idx..start_color_idx + 2], 16))) / 255.0) * 1000.0) / 1000.0; + const g = ((@as(f32, @floatFromInt(try std.fmt.parseInt(u8, color[start_color_idx + 2..start_color_idx + 4], 16))) / 255.0) * 1000.0) / 1000.0; + const b = ((@as(f32, @floatFromInt(try std.fmt.parseInt(u8, color[start_color_idx + 4..start_color_idx + 6], 16))) / 255.0) * 1000.0) / 1000.0; + const a = alpha orelse ((@as(f32, @floatFromInt(try std.fmt.parseInt(u8, color[start_color_idx + 6..start_color_idx + 8], 16))) / 255.0) * 1000.0) / 1000.0; + + break :color .{ r, g, b, a }; + }; + + _ = L.pushString("width"); + _ = L.getTable(2); + const width = LuaUtils.coerceInteger(u32, L.checkInteger(-1)) catch { + L.raiseErrorStr("The border width must be >= 0 and < inf", .{}); + }; + + if (LuaUtils.viewById(view_id)) |v| { + v.setBorderColor(&border_color); + + if (width != v.border_width) { + v.border_width = @intCast(width); + // the size has changed which means we need to update the borders + v.resizeBorders(); + } + + return 0; + } + + return 0; +} + /// TODO: impl /// Setting the wm capabilities is for telling the client what they can request. /// This is important to letting the user define whatever type of layout they