mirror of
https://github.com/MezzalunaWM/Mezzaluna.git
synced 2026-03-07 19:49:53 -05:00
lua position, size, focus and z-index (not really)
This commit is contained in:
parent
2c130539f6
commit
47bcce621d
14 changed files with 236 additions and 98 deletions
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
A utensil for chopping herbs, vegetables, or pizza, with a large semicircular blade and a handle at each end.
|
||||
|
||||
The idea is that Mezzaluna takes care of the hardwork while leaving configuration, tiling behaviour and general exstensability to be done with easy to write Lua.
|
||||
The idea is that Mezzaluna takes care of the hardwork while leaving configuration, tiling behaviour and general exstensability to be done with easy to write, lovable Lua.
|
||||
|
|
|
|||
12
build.zig
12
build.zig
|
|
@ -77,6 +77,18 @@ pub fn build(b: *std.Build) void {
|
|||
|
||||
b.installArtifact(mez);
|
||||
|
||||
const exe_check = b.addExecutable(.{
|
||||
.name = "mez",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
})
|
||||
});
|
||||
|
||||
const check = b.step("check", "check if mez compiles");
|
||||
check.dependOn(&exe_check.step);
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
const run_cmd = b.addRunArtifact(mez);
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
|
|
|||
|
|
@ -35,9 +35,17 @@ mez.input.add_keymap("alt", "q", {
|
|||
end
|
||||
})
|
||||
|
||||
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
|
||||
})
|
||||
|
||||
for i = 1, 12 do
|
||||
mez.input.add_keymap("ctrl|alt", "XF86Switch_VT_"..i, {
|
||||
press = function() mez.api.chvt(i) end
|
||||
press = function() mez.api.change_vt(i) end
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ pub fn processCursorMotion(self: *Cursor, time_msec: u32) void {
|
|||
switch (self.mode) {
|
||||
.passthrough => {
|
||||
if (server.root.viewAt(self.wlr_cursor.x, self.wlr_cursor.y)) |res| {
|
||||
server.seat.focusView(res.view);
|
||||
res.view.setFocused();
|
||||
|
||||
server.seat.wlr_seat.pointerNotifyEnter(res.surface, res.sx, res.sy);
|
||||
server.seat.wlr_seat.pointerNotifyMotion(time_msec, res.sx, res.sy);
|
||||
|
|
@ -134,8 +134,7 @@ fn handleButton(
|
|||
_ = server.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
|
||||
|
||||
if (server.seat.focused_view) |view| {
|
||||
server.seat.focusView(view);
|
||||
server.root.focusView(view);
|
||||
view.setFocused();
|
||||
}
|
||||
|
||||
switch (event.state) {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ pub fn exit(L: *zlua.Lua) i32 {
|
|||
return 0;
|
||||
}
|
||||
|
||||
pub fn chvt(L: *zlua.Lua) i32 {
|
||||
pub fn change_vt(L: *zlua.Lua) i32 {
|
||||
L.checkType(1, .number);
|
||||
const f = L.toNumber(-1) catch unreachable;
|
||||
const n: u32 = @intFromFloat(f);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const Fs = @import("fs.zig");
|
|||
const Input = @import("input.zig");
|
||||
const Api = @import("api.zig");
|
||||
const Hook = @import("hook.zig");
|
||||
const View = @import("view.zig");
|
||||
|
||||
const gpa = std.heap.c_allocator;
|
||||
|
||||
|
|
@ -75,6 +76,11 @@ pub fn init(self: *Lua) !void {
|
|||
self.state.newLib(api_funcs);
|
||||
self.state.setField(-2, "api");
|
||||
}
|
||||
{
|
||||
const view_funcs = zlua.fnRegsFromType(View);
|
||||
self.state.newLib(view_funcs);
|
||||
self.state.setField(-2, "view");
|
||||
}
|
||||
}
|
||||
|
||||
loadRuntimeDir(self) catch |err| {
|
||||
|
|
@ -82,6 +88,7 @@ pub fn init(self: *Lua) !void {
|
|||
std.log.warn("{s}", .{try self.state.toString(-1)});
|
||||
}
|
||||
};
|
||||
|
||||
loadConfigDir(self) catch |err| {
|
||||
if (err == error.LuaRuntime) {
|
||||
std.log.warn("{s}", .{try self.state.toString(-1)});
|
||||
|
|
|
|||
116
src/lua/view.zig
Normal file
116
src/lua/view.zig
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
const std = @import("std");
|
||||
const zlua = @import("zlua");
|
||||
const wlr = @import("wlroots");
|
||||
|
||||
const View = @import("../view.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.tree.children.iterator(.forward);
|
||||
var index: usize = 1;
|
||||
|
||||
L.newTable();
|
||||
|
||||
while(it.next()) |node| : (index += 1) {
|
||||
if(node.data == null) continue;
|
||||
|
||||
const view = @as(*View, @ptrCast(@alignCast(node.data.?)));
|
||||
|
||||
L.pushInteger(@intCast(index));
|
||||
L.pushInteger(@intCast(view.id));
|
||||
L.setTable(1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
pub fn get_focused_id(L: *zlua.Lua) i32 {
|
||||
if(server.seat.focused_view) |view| {
|
||||
_ = L.pushNumber(@floatFromInt(view.id));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (1..@intCast(nargs + 1)) |i| {
|
||||
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 = server.root.viewById(view_id);
|
||||
if(view == null) {
|
||||
L.raiseErrorStr("View with id {d} does not exist", .{view_id});
|
||||
return 0;
|
||||
}
|
||||
|
||||
view.?.setPosition(x, y);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn set_size(L: *zlua.Lua) i32 {
|
||||
const nargs: i32 = L.getTop();
|
||||
|
||||
if (nargs != 3) {
|
||||
L.raiseErrorStr("Expected 3 arguments, found {d}", .{nargs});
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (1..@intCast(nargs + 1)) |i| {
|
||||
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 = server.root.viewById(view_id);
|
||||
if(view == null) {
|
||||
L.raiseErrorStr("View with id {d} does not exist", .{view_id});
|
||||
return 0;
|
||||
}
|
||||
|
||||
view.?.setSize(width, height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn raise_to_top(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 = @intCast(L.toInteger(1) catch unreachable);
|
||||
|
||||
const view = server.root.viewById(view_id);
|
||||
if(view == null) {
|
||||
L.raiseErrorStr("View with id {d} does not exist", .{view_id});
|
||||
return 0;
|
||||
}
|
||||
|
||||
view.?.raiseToTop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ const server = &@import("main.zig").server;
|
|||
focused: bool,
|
||||
|
||||
wlr_output: *wlr.Output,
|
||||
state: wlr.Output.State,
|
||||
scene_output: *wlr.SceneOutput,
|
||||
|
||||
frame: wl.Listener(*wlr.Output) = .init(handleFrame),
|
||||
|
|
@ -20,7 +21,7 @@ request_state: wl.Listener(*wlr.Output.event.RequestState) = .init(handleRequest
|
|||
destroy: wl.Listener(*wlr.Output) = .init(handleDestroy),
|
||||
|
||||
// The wlr.Output should be destroyed by the caller on failure to trigger cleanup.
|
||||
pub fn create(wlr_output: *wlr.Output) *Output {
|
||||
pub fn init(wlr_output: *wlr.Output) ?*Output {
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
const output = try gpa.create(Output);
|
||||
|
|
@ -28,25 +29,51 @@ pub fn create(wlr_output: *wlr.Output) *Output {
|
|||
output.* = .{
|
||||
.focused = false,
|
||||
.wlr_output = wlr_output,
|
||||
.scene_output = try server.root.scene.createSceneOutput(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);
|
||||
|
||||
std.log.debug("adding output: {s}", .{output.wlr_output.name});
|
||||
errdefer deinit(output);
|
||||
|
||||
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);
|
||||
|
||||
if (wlr_output.preferredMode()) |mode| {
|
||||
output.state.setMode(mode);
|
||||
}
|
||||
|
||||
if(!wlr_output.commitState(&output.state)) {
|
||||
std.log.err("Unable to commit state to output {s}", .{wlr_output.name});
|
||||
return null;
|
||||
}
|
||||
|
||||
server.root.addOutput(output);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// Conflicting name with destroy listener
|
||||
// Should probably add _listner as a postfix to listeners
|
||||
//
|
||||
// pub fn destroy(output: *Output) void {
|
||||
// gpa.free(output);
|
||||
// }
|
||||
pub fn deinit(output: *Output) void {
|
||||
output.frame.link.remove();
|
||||
output.request_state.link.remove();
|
||||
output.destroy.remove();
|
||||
|
||||
output.state.finish();
|
||||
|
||||
output.wlr_output.destroy();
|
||||
|
||||
gpa.free(output);
|
||||
}
|
||||
|
||||
|
||||
// --------- WlrOutput Event Handlers ---------
|
||||
fn handleRequestState(
|
||||
listener: *wl.Listener(*wlr.Output.event.RequestState),
|
||||
event: *wlr.Output.event.RequestState,
|
||||
|
|
|
|||
31
src/root.zig
31
src/root.zig
|
|
@ -1,3 +1,6 @@
|
|||
/// The root of Mezzaluna is, you guessed it, the root of many of the systems mez needs:
|
||||
/// - Managing outputs
|
||||
/// -
|
||||
const Root = @This();
|
||||
|
||||
const std = @import("std");
|
||||
|
|
@ -18,8 +21,6 @@ scene_output_layout: *wlr.SceneOutputLayout,
|
|||
|
||||
output_layout: *wlr.OutputLayout,
|
||||
|
||||
views: std.HashMap(u64, *View, std.hash_map.AutoContext(u64), 80),
|
||||
|
||||
pub fn init(self: *Root) void {
|
||||
std.log.info("Creating root of mezzaluna\n", .{});
|
||||
|
||||
|
|
@ -36,22 +37,36 @@ pub fn init(self: *Root) void {
|
|||
.output_layout = output_layout,
|
||||
.xdg_toplevel_decoration_manager = try wlr.XdgDecorationManagerV1.create(server.wl_server),
|
||||
.scene_output_layout = try scene.attachOutputLayout(output_layout),
|
||||
.views = .init(gpa)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Root) void {
|
||||
var views_it = self.views.iterator();
|
||||
while(views_it.next()) |entry| {
|
||||
entry.value_ptr.*.deinit();
|
||||
}
|
||||
var it = self.scene.tree.children.iterator(.forward);
|
||||
|
||||
self.views.deinit();
|
||||
while(it.next()) |node| {
|
||||
if(node.data == null) continue;
|
||||
|
||||
const view: *View = @ptrCast(@alignCast(node.data.?));
|
||||
view.deinit();
|
||||
}
|
||||
|
||||
self.output_layout.destroy();
|
||||
self.scene.tree.node.destroy();
|
||||
}
|
||||
|
||||
pub fn viewById(self: *Root, id: u64) ?*View {
|
||||
var it = self.scene.tree.children.iterator(.forward);
|
||||
|
||||
while(it.next()) |node| {
|
||||
if(node.data == null) continue;
|
||||
|
||||
const view: *View = @as(*View, @ptrCast(@alignCast(node.data.?)));
|
||||
if(view.id == id) return 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);
|
||||
|
|
|
|||
|
|
@ -73,15 +73,6 @@ pub fn focusOutput(self: *Seat, output: *Output) void {
|
|||
self.focused_output = output;
|
||||
}
|
||||
|
||||
// TODO: Should focusing a view, automaticall focus the output containing it
|
||||
pub fn focusView(self: *Seat, view: *View) void {
|
||||
if(self.focused_view) |prev_view| {
|
||||
prev_view.setFocus(false);
|
||||
}
|
||||
|
||||
self.focused_view = view;
|
||||
}
|
||||
|
||||
fn handleRequestSetCursor(
|
||||
_: *wl.Listener(*wlr.Seat.event.RequestSetCursor),
|
||||
event: *wlr.Seat.event.RequestSetCursor,
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ fn handleNewInput(
|
|||
},
|
||||
}
|
||||
|
||||
// We should really only set true capabilities
|
||||
server.seat.wlr_seat.setCapabilities(.{
|
||||
.pointer = true,
|
||||
.keyboard = true,
|
||||
|
|
@ -171,30 +172,13 @@ fn handleNewOutput(
|
|||
_: *wl.Listener(*wlr.Output),
|
||||
wlr_output: *wlr.Output
|
||||
) void {
|
||||
std.log.info("Handling a new output - {s}", .{wlr_output.name});
|
||||
|
||||
if (!wlr_output.initRender(server.allocator, server.renderer)) return;
|
||||
|
||||
var state = wlr.Output.State.init();
|
||||
defer state.finish();
|
||||
|
||||
state.setEnabled(true);
|
||||
|
||||
if (wlr_output.preferredMode()) |mode| {
|
||||
state.setMode(mode);
|
||||
}
|
||||
if (!wlr_output.commitState(&state)) return;
|
||||
|
||||
const new_output = Output.create(wlr_output);
|
||||
|
||||
server.root.addOutput(new_output);
|
||||
_ = Output.init(wlr_output);
|
||||
}
|
||||
|
||||
fn handleNewXdgToplevel(
|
||||
_: *wl.Listener(*wlr.XdgToplevel),
|
||||
xdg_toplevel: *wlr.XdgToplevel
|
||||
) void {
|
||||
std.log.debug("Request for new toplevel", .{});
|
||||
_ = View.initFromTopLevel(xdg_toplevel);
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +187,7 @@ fn handleNewXdgToplevelDecoration(
|
|||
decoration: *wlr.XdgToplevelDecorationV1
|
||||
) void {
|
||||
std.log.debug("Request for decorations", .{});
|
||||
if(server.root.views.get(@intFromPtr(decoration.toplevel))) |view| {
|
||||
if(server.root.viewById(@intFromPtr(decoration.toplevel))) |view| {
|
||||
view.xdg_toplevel_decoration = decoration;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
32
src/tag.zig
32
src/tag.zig
|
|
@ -1,32 +0,0 @@
|
|||
const Tag = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const wl = @import("wayland").server.wl;
|
||||
const wlr = @import("wlroots");
|
||||
|
||||
const Output = @import("output.zig");
|
||||
const View = @import("view.zig");
|
||||
const Utils = @import("utils.zig");
|
||||
|
||||
const server = @import("main.zig").server;
|
||||
const gpa = std.heap.c_allocator;
|
||||
|
||||
output: *Output,
|
||||
scene_tree: *wlr.SceneTree,
|
||||
|
||||
views: std.ArrayList(*View),
|
||||
|
||||
pub fn init(output: *Output) Tag {
|
||||
errdefer Utils.oomPanic();
|
||||
return .{
|
||||
.output = output,
|
||||
.scene_tree = try server.root.scene.tree.createSceneTree(),
|
||||
.views = .initCapacity(gpa, 2), // Probably shouldn't be a magic number
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Tag) void {
|
||||
for(self.views.items) |view| {
|
||||
view
|
||||
}
|
||||
}
|
||||
41
src/view.zig
41
src/view.zig
|
|
@ -51,20 +51,19 @@ pub fn initFromTopLevel(xdg_toplevel: *wlr.XdgToplevel) *View {
|
|||
errdefer gpa.destroy(self);
|
||||
|
||||
self.* = .{
|
||||
.xdg_toplevel = xdg_toplevel,
|
||||
.focused = false,
|
||||
.scene_tree = undefined,
|
||||
.xdg_toplevel_decoration = null,
|
||||
.mapped = false,
|
||||
.id = @intFromPtr(xdg_toplevel),
|
||||
|
||||
.xdg_toplevel = xdg_toplevel,
|
||||
.scene_tree = undefined,
|
||||
.xdg_toplevel_decoration = null,
|
||||
};
|
||||
|
||||
self.xdg_toplevel.base.surface.events.unmap.add(&self.unmap);
|
||||
|
||||
// Add new Toplevel to focused output instead of some random shit
|
||||
// This is where we find out where to tile the widow, but not NOW
|
||||
// We need lua for that
|
||||
// self.scene_tree = try server.root.workspaces.items[0].createSceneXdgSurface(xdg_toplevel.base);
|
||||
// Add new Toplevel to root of the tree
|
||||
// Later add to spesified output
|
||||
self.scene_tree = try server.root.scene.tree.createSceneXdgSurface(xdg_toplevel.base);
|
||||
|
||||
self.scene_tree.node.data = self;
|
||||
|
|
@ -75,8 +74,6 @@ pub fn initFromTopLevel(xdg_toplevel: *wlr.XdgToplevel) *View {
|
|||
self.xdg_toplevel.base.surface.events.commit.add(&self.commit);
|
||||
self.xdg_toplevel.base.events.new_popup.add(&self.new_popup);
|
||||
|
||||
try server.root.views.put(self.id, self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
@ -90,9 +87,25 @@ pub fn deinit(self: *View) void {
|
|||
self.request_resize.link.remove();
|
||||
}
|
||||
|
||||
// Handle borders to appropriate colros make necessary notifications
|
||||
pub fn setFocus(self: *View, focus: bool) void {
|
||||
self.focused = focus;
|
||||
pub fn setFocused(self: *View) void {
|
||||
if(server.seat.focused_view) |prev_view| {
|
||||
prev_view.focused = false;
|
||||
}
|
||||
server.seat.focused_view = self;
|
||||
self.focused = true;
|
||||
}
|
||||
|
||||
pub fn raiseToTop(self: *View) void {
|
||||
self.scene_tree.node.raiseToTop();
|
||||
}
|
||||
|
||||
pub fn setPosition(self: *View, x: i32, y: i32) void {
|
||||
self.scene_tree.node.setPosition(x, y);
|
||||
}
|
||||
|
||||
pub fn setSize(self: *View, width: i32, height: i32) void {
|
||||
// This returns a configure serial for verifying the configure
|
||||
_ = self.xdg_toplevel.setSize(width, height);
|
||||
}
|
||||
|
||||
// --------- XdgTopLevel event handlers ---------
|
||||
|
|
@ -159,8 +172,6 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
|
|||
view.scene_tree.node.destroy();
|
||||
// Destroy popups
|
||||
|
||||
_ = server.root.views.remove(view.id);
|
||||
|
||||
gpa.destroy(view);
|
||||
}
|
||||
|
||||
|
|
@ -169,7 +180,7 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
|||
|
||||
// On the first commit, send a configure to tell the client it can proceed
|
||||
if (view.xdg_toplevel.base.initial_commit) {
|
||||
_ = view.xdg_toplevel.setSize(640, 360); // 0,0 means "you decide the size"
|
||||
view.setSize(640, 360);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue