diff --git a/.editorconfig b/.editorconfig index afe398a..18446ef 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,3 +10,8 @@ insert_final_newline = true indent_style = space indent_size = 2 trim_trailing_whitespace = true + +[*.lua] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true diff --git a/runtime/share/mezzaluna/init.lua b/runtime/share/mezzaluna/init.lua index aa95fa4..a414489 100644 --- a/runtime/share/mezzaluna/init.lua +++ b/runtime/share/mezzaluna/init.lua @@ -10,16 +10,11 @@ end mez.path.config = mez.fs.joinpath(env_conf, "mez", "init.lua") package.path = package.path..";"..mez.fs.joinpath(env_conf, "mez", "lua", "?.lua") --- this is an example -mez.input.add_keymap("alt", "a", { - press = function() - print("hello from my keymap") - end -}) - mez.input.add_keymap("alt", "Return", { press = function() - mez.api.spawn("foot") + -- foot doesnt resize on uneven columns + -- this means alacritty is just better (period) + mez.api.spawn("alacritty") end, }) @@ -36,35 +31,27 @@ mez.input.add_keymap("alt", "q", { }) mez.input.add_keymap("alt", "v", { - press = function () - local view = mez.view.get_focused_id() - mez.view.set_position(view, 100, 100) - mez.view.set_size(view, 100, 100) - end -}) + press = function () + local id = mez.view.get_focused_id() -mez.input.add_keymap("alt", "v", { - press = function () - local view = mez.view.get_focused_id() - mez.view.set_position(view, 100, 100) - mez.view.set_size(view, 100, 100) - end + local details = mez.view.get_details(id); + print(details.title); + print(details.app_id); + end }) mez.input.add_keymap("alt", "Tab", { - press = function () - print("alt+tab") + press = function () + local focused = mez.view.get_focused_id() + local all = mez.view.get_all_ids() - local focused = mez.view.get_focused_id() - local all = mez.view.get_all_ids() - - for _, id in ipairs(all) do - if id ~= focused then - mez.view.set_focused(id) - return - end - end - end + for _, id in ipairs(all) do + if id ~= focused then + mez.view.set_focused(id) + return + end + end + end }) for i = 1, 12 do @@ -73,9 +60,22 @@ for i = 1, 12 do }) end +mez.input.add_keymap("alt", "t", { + press = function() tiler() end +}) + +local tiler = function () + local all = mez.view.get_all_ids() + + for i, id in ipairs(all) do + mez.view.set_position(id, (1920 / #all) * (i - 1), 0) + mez.view.set_size(id, 1920 / #all, 1080) + end +end + mez.hook.add("ViewMapPre", { callback = function(v) - mez.view.set_size(v, 1000, 1000) - mez.view.set_focused(v) + tiler() + mez.view.set_focused(v) end }) diff --git a/src/lua/api.zig b/src/lua/api.zig index be31ed3..91d0528 100644 --- a/src/lua/api.zig +++ b/src/lua/api.zig @@ -16,7 +16,6 @@ pub fn spawn(L: *zlua.Lua) i32 { } L.checkType(1, .string); - std.log.debug("GOT HERE", .{}); const cmd = L.toString(1) catch { L.raiseErrorStr("Lua error check your config", .{}); diff --git a/src/lua/lua.zig b/src/lua/lua.zig index 41c3aba..e94388e 100644 --- a/src/lua/lua.zig +++ b/src/lua/lua.zig @@ -10,6 +10,7 @@ const Input = @import("input.zig"); const Api = @import("api.zig"); const Hook = @import("hook.zig"); const View = @import("view.zig"); +const Output = @import("output.zig"); const gpa = std.heap.c_allocator; @@ -81,6 +82,11 @@ pub fn init(self: *Lua) !void { self.state.newLib(view_funcs); self.state.setField(-2, "view"); } + { + const output_funcs = zlua.fnRegsFromType(Output); + self.state.newLib(output_funcs); + self.state.setField(-2, "output"); + } } loadRuntimeDir(self) catch |err| { diff --git a/src/lua/output.zig b/src/lua/output.zig new file mode 100644 index 0000000..b1b55ce --- /dev/null +++ b/src/lua/output.zig @@ -0,0 +1,137 @@ +const std = @import("std"); +const zlua = @import("zlua"); +const wlr = @import("wlroots"); + +const Output = @import("../output.zig"); + +const gpa = std.heap.c_allocator; +const server = &@import("../main.zig").server; + +pub fn get_all_ids(L: *zlua.Lua) i32 { + var it = server.root.scene.outputs.iterator(.forward); + var index: usize = 1; + + L.newTable(); + + while(it.next()) |scene_output| : (index += 1) { + if(scene_output.output.data == null) continue; + + const output = @as(*Output, @ptrCast(@alignCast(scene_output.output.data.?))); + + L.pushInteger(@intCast(index)); + L.pushInteger(@intCast(output.id)); + L.setTable(-3); + } + + return 1; +} + +pub fn get_focused_id(L: *zlua.Lua) i32 { + if(server.seat.focused_output) |output| { + L.pushInteger(@intCast(output.id)); + return 1; + } + + return 0; +} + +pub fn get_rate(L: *zlua.Lua) i32 { + const nargs: i32 = L.getTop(); + + if(nargs != 1) { + L.raiseErrorStr("Expected 1 argument, found", .{nargs}); + } + + L.checkType(1, .number); + + const output_id: u64 = @as(u64, @intCast(L.toInteger(1) catch { + L.raiseErrorStr("Arg is not convertable to an int", .{}); + })); + + if(server.root.outputById(output_id)) |output| { + L.pushInteger(@intCast(output.wlr_output.refresh)); + return 1; + } + + return 0; +} + +pub fn get_resolution(L: *zlua.Lua) i32 { + const nargs: i32 = L.getTop(); + + if(nargs != 1) { + L.raiseErrorStr("Expected 1 argument, found", .{nargs}); + } + + L.checkType(1, .number); + + const output_id: u64 = @as(u64, @intCast(L.toInteger(1) catch { + L.raiseErrorStr("Arg is not convertable to an int", .{}); + })); + + if(server.root.outputById(output_id)) |output| { + L.newTable(); + + _ = L.pushString("width"); + L.pushInteger(@intCast(output.wlr_output.width)); + L.setTable(-3); + + _ = L.pushString("height"); + L.pushInteger(@intCast(output.wlr_output.height)); + L.setTable(-3); + + return 1; + } + + return 0; +} + +pub fn get_details(L: *zlua.Lua) i32 { + const nargs: i32 = L.getTop(); + + if(nargs != 1) { + L.raiseErrorStr("Expected 1 argument, found", .{nargs}); + } + + L.checkType(1, .number); + + const output_id: u64 = @as(u64, @intCast(L.toInteger(1) catch { + L.raiseErrorStr("Arg is not convertable to an int", .{}); + })); + + if(server.root.outputById(output_id)) |output| { + L.newTable(); + + if(output.wlr_output.description) |detail| { + _ = L.pushString("description"); + _ = L.pushString(std.mem.span(detail)); + L.setTable(-3); + } + + if(output.wlr_output.model) |detail| { + _ = L.pushString("model"); + _ = L.pushString(std.mem.span(detail)); + L.setTable(-3); + } + + if(output.wlr_output.make) |detail| { + _ = L.pushString("make"); + _ = L.pushString(std.mem.span(detail)); + L.setTable(-3); + } + + _ = L.pushString("name"); + _ = L.pushString(std.mem.span(output.wlr_output.name)); + L.setTable(-3); + + if(output.wlr_output.serial) |detail| { + _ = L.pushString("serial"); + _ = L.pushString(std.mem.span(detail)); + L.setTable(-3); + } + + return 1; + } + + return 0; +} diff --git a/src/lua/view.zig b/src/lua/view.zig index e759085..9d63586 100644 --- a/src/lua/view.zig +++ b/src/lua/view.zig @@ -21,7 +21,7 @@ pub fn get_all_ids(L: *zlua.Lua) i32 { L.pushInteger(@intCast(index)); L.pushInteger(@intCast(view.id)); - L.setTable(1); + L.setTable(-3); } return 1; @@ -39,8 +39,6 @@ pub fn get_focused_id(L: *zlua.Lua) i32 { pub fn set_position(L: *zlua.Lua) i32 { const nargs: i32 = L.getTop(); - std.log.debug("Starting view reposition", .{}); - if (nargs != 3) { L.raiseErrorStr("Expected 3 arguments, found {d}", .{nargs}); return 0; @@ -50,9 +48,9 @@ pub fn set_position(L: *zlua.Lua) i32 { L.checkType(@intCast(i), .number); } - const view_id: u64 = @as(u64, @intCast(L.toInteger(1) catch unreachable)); - const x: i32 = @as(i32, @intCast(L.toInteger(2) catch unreachable)); - const y: i32 = @as(i32, @intCast(L.toInteger(3) catch unreachable)); + const view_id: u64 = @as(u64, @intCast(L.toInteger(1) catch { L.raiseErrorStr("Arg is not convertable to an int", .{}); })); + const x: i32 = @as(i32, @intFromFloat(L.toNumber(2) catch { L.raiseErrorStr("Arg is not convertable to an int", .{}); })); + const y: i32 = @as(i32, @intFromFloat(L.toNumber(3) catch { L.raiseErrorStr("Arg is not convertable to an int", .{}); })); const view = server.root.viewById(view_id); if(view == null) { @@ -77,9 +75,9 @@ pub fn set_size(L: *zlua.Lua) i32 { L.checkType(@intCast(i), .number); } - const view_id: u64 = @as(u64, @intCast(L.toInteger(1) catch unreachable)); - const width: i32 = @as(i32, @intCast(L.toInteger(2) catch unreachable)); - const height: i32 = @as(i32, @intCast(L.toInteger(3) catch unreachable)); + const view_id: u64 = @as(u64, @intCast(L.toInteger(1) catch { L.raiseErrorStr("Arg is not convertable to an int", .{}); })); + const width: i32 = @as(i32, @intFromFloat(L.toNumber(2) catch { L.raiseErrorStr("Arg is not convertable to an int", .{}); })); + const height: i32 = @as(i32, @intFromFloat(L.toNumber(3) catch { L.raiseErrorStr("Arg is not convertable to an int", .{}); })); const view = server.root.viewById(view_id); if(view == null) { @@ -102,7 +100,7 @@ pub fn set_focused(L: *zlua.Lua) i32 { L.checkType(1, .number); - const view_id: u64 = @intCast(L.toInteger(1) catch unreachable); + const view_id: u64 = @as(u64, @intCast(L.toInteger(1) catch { L.raiseErrorStr("Arg is not convertable to an int", .{}); })); const view = server.root.viewById(view_id); if(view == null) { @@ -114,3 +112,36 @@ pub fn set_focused(L: *zlua.Lua) i32 { return 0; } + +pub fn get_details(L: *zlua.Lua) i32 { + const nargs: i32 = L.getTop(); + + if(nargs != 1) { + L.raiseErrorStr("Expected 1 arguments, found {d}", .{nargs}); + return 0; + } + + L.checkType(1, .number); + + const view_id: u64 = @as(u64, @intCast(L.toInteger(1) catch { L.raiseErrorStr("Arg is not convertable to an int", .{}); })); + + if(server.root.viewById(view_id)) |view| { + L.newTable(); + + if(view.xdg_toplevel.title) |detail| { + _ = L.pushString("title"); + _ = L.pushString(std.mem.span(detail)); + L.setTable(-3); + } + + if(view.xdg_toplevel.app_id) |detail| { + _ = L.pushString("app_id"); + _ = L.pushString(std.mem.span(detail)); + L.setTable(-3); + } + + return 1; + } + + return 0; +} diff --git a/src/output.zig b/src/output.zig index 70f3fcd..e66148c 100644 --- a/src/output.zig +++ b/src/output.zig @@ -11,6 +11,7 @@ const gpa = std.heap.c_allocator; const server = &@import("main.zig").server; focused: bool, +id: u64, wlr_output: *wlr.Output, state: wlr.Output.State, @@ -24,61 +25,73 @@ destroy: wl.Listener(*wlr.Output) = .init(handleDestroy), pub fn init(wlr_output: *wlr.Output) ?*Output { errdefer Utils.oomPanic(); - const output = try gpa.create(Output); + const self = try gpa.create(Output); - output.* = .{ + self.* = .{ .focused = false, + .id = @intFromPtr(wlr_output), .wlr_output = wlr_output, .scene_output = try server.root.scene.createSceneOutput(wlr_output), .state = wlr.Output.State.init() }; - wlr_output.events.frame.add(&output.frame); - wlr_output.events.request_state.add(&output.request_state); - wlr_output.events.destroy.add(&output.destroy); + wlr_output.events.frame.add(&self.frame); + wlr_output.events.request_state.add(&self.request_state); + wlr_output.events.destroy.add(&self.destroy); - errdefer deinit(output); + errdefer deinit(self); if(!wlr_output.initRender(server.allocator, server.renderer)) { std.log.err("Unable to start output {s}", .{wlr_output.name}); return null; } - output.state.setEnabled(true); + self.state.setEnabled(true); if (wlr_output.preferredMode()) |mode| { - output.state.setMode(mode); + self.state.setMode(mode); } - if(!wlr_output.commitState(&output.state)) { + if(!wlr_output.commitState(&self.state)) { std.log.err("Unable to commit state to output {s}", .{wlr_output.name}); return null; } - server.root.addOutput(output); + const layout_output = try server.root.output_layout.addAuto(self.wlr_output); + server.root.scene_output_layout.addOutput(layout_output, self.scene_output); + self.setFocused(); - return output; + wlr_output.data = self; + + return self; } -pub fn deinit(output: *Output) void { - output.frame.link.remove(); - output.request_state.link.remove(); - output.destroy.remove(); +pub fn deinit(self: *Output) void { + self.frame.link.remove(); + self.request_state.link.remove(); + self.destroy.link.remove(); - output.state.finish(); + self.state.finish(); - output.wlr_output.destroy(); + self.wlr_output.destroy(); - gpa.free(output); + gpa.destroy(self); } +pub fn setFocused(self: *Output) void { + if(server.seat.focused_output) |prev_output| { + prev_output.focused = false; + } + + server.seat.focused_output = self; + self.focused = true; +} // --------- WlrOutput Event Handlers --------- fn handleRequestState( listener: *wl.Listener(*wlr.Output.event.RequestState), event: *wlr.Output.event.RequestState, ) void { - std.log.debug("Handling request state", .{}); const output: *Output = @fieldParentPtr("request_state", listener); if (!output.wlr_output.commitState(event.state)) { diff --git a/src/root.zig b/src/root.zig index 474cf11..925dd9a 100644 --- a/src/root.zig +++ b/src/root.zig @@ -67,11 +67,17 @@ pub fn viewById(self: *Root, id: u64) ?*View { return null; } -pub fn addOutput(self: *Root, new_output: *Output) void { - errdefer Utils.oomPanic(); - const layout_output = try self.output_layout.addAuto(new_output.wlr_output); - self.scene_output_layout.addOutput(layout_output, new_output.scene_output); - server.seat.focusOutput(new_output); +pub fn outputById(self: *Root, id: u64) ?*Output { + var it = self.scene.outputs.iterator(.forward); + + while(it.next()) |scene_output| { + if(scene_output.output.data == null) continue; + + const output: *Output = @as(*Output, @ptrCast(@alignCast(scene_output.output.data.?))); + if(output.id == id) return output; + } + + return null; } const ViewAtResult = struct { diff --git a/src/seat.zig b/src/seat.zig index 2659fb0..9f47647 100644 --- a/src/seat.zig +++ b/src/seat.zig @@ -66,7 +66,7 @@ pub fn deinit(self: *Seat) void { } pub fn focusOutput(self: *Seat, output: *Output) void { - if(self.focused_output) |prev_output| { + if(server.seat.focused_output) |prev_output| { prev_output.focused = false; } diff --git a/src/types/hook.zig b/src/types/hook.zig index 7b2693f..511e84a 100644 --- a/src/types/hook.zig +++ b/src/types/hook.zig @@ -38,7 +38,6 @@ pub fn callback(self: *const Hook, args: anytype) void { i = k; } - Lua.state.protectedCall(.{ .args = i }) catch { - }; + Lua.state.protectedCall(.{ .args = i }) catch { }; Lua.state.pop(-1); } diff --git a/src/view.zig b/src/view.zig index a348c96..63dd942 100644 --- a/src/view.zig +++ b/src/view.zig @@ -157,6 +157,8 @@ fn handleUnmap(listener: *wl.Listener(void)) void { const view: *View = @fieldParentPtr("unmap", listener); std.log.debug("Unmapping view '{s}'", .{view.xdg_toplevel.title orelse "(unnamed)"}); + server.events.exec("ViewUnmapPre", .{view.id}); + view.request_fullscreen.link.remove(); view.request_move.link.remove(); view.request_resize.link.remove(); @@ -167,6 +169,8 @@ fn handleUnmap(listener: *wl.Listener(void)) void { // view.ack_configure.link.remove(); view.mapped = false; + + server.events.exec("ViewUnmapPost", .{view.id}); } fn handleDestroy(listener: *wl.Listener(void)) void {