mirror of
https://github.com/MezzalunaWM/Mezzaluna.git
synced 2026-03-07 19:49:53 -05:00
reformatted with zig fmt
This commit is contained in:
parent
e6a45f91b6
commit
6be66b6a71
32 changed files with 2108 additions and 2237 deletions
|
|
@ -6,11 +6,6 @@ root = true
|
|||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.zig]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.lua]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
|
|
|||
142
build.zig
142
build.zig
|
|
@ -4,89 +4,89 @@ const builtin = @import("builtin");
|
|||
const Scanner = @import("wayland").Scanner;
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
// TODO: this will probably change based on the install paths, make this a var
|
||||
// that can be passed at comptime?
|
||||
const runtime_path_prefix = switch (builtin.mode) {
|
||||
.Debug => "runtime/",
|
||||
else => "/usr/share",
|
||||
};
|
||||
// TODO: this will probably change based on the install paths, make this a var
|
||||
// that can be passed at comptime?
|
||||
const runtime_path_prefix = switch (builtin.mode) {
|
||||
.Debug => "runtime/",
|
||||
else => "/usr/share",
|
||||
};
|
||||
|
||||
// Add protocol xml files
|
||||
const scanner = Scanner.create(b, .{});
|
||||
scanner.addSystemProtocol("stable/xdg-shell/xdg-shell.xml");
|
||||
scanner.addSystemProtocol("stable/tablet/tablet-v2.xml");
|
||||
scanner.addSystemProtocol("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml");
|
||||
scanner.addCustomProtocol(b.path("protocols/wlr-layer-shell-unstable-v1.xml"));
|
||||
scanner.addCustomProtocol(b.path("protocols/mez-remote-lua-unstable-v1.xml"));
|
||||
// Add protocol xml files
|
||||
const scanner = Scanner.create(b, .{});
|
||||
scanner.addSystemProtocol("stable/xdg-shell/xdg-shell.xml");
|
||||
scanner.addSystemProtocol("stable/tablet/tablet-v2.xml");
|
||||
scanner.addSystemProtocol("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml");
|
||||
scanner.addCustomProtocol(b.path("protocols/wlr-layer-shell-unstable-v1.xml"));
|
||||
scanner.addCustomProtocol(b.path("protocols/mez-remote-lua-unstable-v1.xml"));
|
||||
|
||||
// Generate protocol code
|
||||
scanner.generate("zmez_remote_lua_manager_v1", 1);
|
||||
scanner.generate("wl_compositor", 6);
|
||||
scanner.generate("wl_subcompositor", 1);
|
||||
scanner.generate("wl_shm", 2);
|
||||
scanner.generate("wl_output", 4);
|
||||
scanner.generate("wl_seat", 9);
|
||||
scanner.generate("wl_data_device_manager", 3);
|
||||
scanner.generate("zxdg_decoration_manager_v1", 1);
|
||||
scanner.generate("xdg_wm_base", 7);
|
||||
scanner.generate("zwp_tablet_manager_v2", 2);
|
||||
scanner.generate("zwlr_layer_shell_v1", 5);
|
||||
// Generate protocol code
|
||||
scanner.generate("zmez_remote_lua_manager_v1", 1);
|
||||
scanner.generate("wl_compositor", 6);
|
||||
scanner.generate("wl_subcompositor", 1);
|
||||
scanner.generate("wl_shm", 2);
|
||||
scanner.generate("wl_output", 4);
|
||||
scanner.generate("wl_seat", 9);
|
||||
scanner.generate("wl_data_device_manager", 3);
|
||||
scanner.generate("zxdg_decoration_manager_v1", 1);
|
||||
scanner.generate("xdg_wm_base", 7);
|
||||
scanner.generate("zwp_tablet_manager_v2", 2);
|
||||
scanner.generate("zwlr_layer_shell_v1", 5);
|
||||
|
||||
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
||||
const xkbcommon = b.dependency("xkbcommon", .{}).module("xkbcommon");
|
||||
const pixman = b.dependency("pixman", .{}).module("pixman");
|
||||
const wlroots = b.dependency("wlroots", .{}).module("wlroots");
|
||||
const zlua = b.dependency("zlua", .{ .optimize = optimize, .target = target, .lang = .lua51 }).module("zlua");
|
||||
const clap = b.dependency("clap", .{}).module("clap");
|
||||
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
||||
const xkbcommon = b.dependency("xkbcommon", .{}).module("xkbcommon");
|
||||
const pixman = b.dependency("pixman", .{}).module("pixman");
|
||||
const wlroots = b.dependency("wlroots", .{}).module("wlroots");
|
||||
const zlua = b.dependency("zlua", .{ .optimize = optimize, .target = target, .lang = .lua51 }).module("zlua");
|
||||
const clap = b.dependency("clap", .{}).module("clap");
|
||||
|
||||
wlroots.addImport("wayland", wayland);
|
||||
wlroots.addImport("xkbcommon", xkbcommon);
|
||||
wlroots.addImport("pixman", pixman);
|
||||
wlroots.addImport("wayland", wayland);
|
||||
wlroots.addImport("xkbcommon", xkbcommon);
|
||||
wlroots.addImport("pixman", pixman);
|
||||
|
||||
wlroots.resolved_target = target;
|
||||
wlroots.linkSystemLibrary("wlroots-0.19", .{});
|
||||
wlroots.resolved_target = target;
|
||||
wlroots.linkSystemLibrary("wlroots-0.19", .{});
|
||||
|
||||
const mez = b.addExecutable(.{
|
||||
.name = "mez",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}),
|
||||
});
|
||||
const mez = b.addExecutable(.{
|
||||
.name = "mez",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}),
|
||||
});
|
||||
|
||||
mez.root_module.link_libc = true;
|
||||
mez.root_module.link_libc = true;
|
||||
|
||||
mez.root_module.addImport("wayland", wayland);
|
||||
mez.root_module.addImport("xkbcommon", xkbcommon);
|
||||
mez.root_module.addImport("wlroots", wlroots);
|
||||
mez.root_module.addImport("zlua", zlua);
|
||||
mez.root_module.addImport("clap", clap);
|
||||
mez.root_module.addImport("wayland", wayland);
|
||||
mez.root_module.addImport("xkbcommon", xkbcommon);
|
||||
mez.root_module.addImport("wlroots", wlroots);
|
||||
mez.root_module.addImport("zlua", zlua);
|
||||
mez.root_module.addImport("clap", clap);
|
||||
|
||||
mez.root_module.linkSystemLibrary("wayland-server", .{});
|
||||
mez.root_module.linkSystemLibrary("xkbcommon", .{});
|
||||
mez.root_module.linkSystemLibrary("pixman-1", .{});
|
||||
mez.root_module.linkSystemLibrary("libevdev", .{});
|
||||
mez.root_module.linkSystemLibrary("wayland-server", .{});
|
||||
mez.root_module.linkSystemLibrary("xkbcommon", .{});
|
||||
mez.root_module.linkSystemLibrary("pixman-1", .{});
|
||||
mez.root_module.linkSystemLibrary("libevdev", .{});
|
||||
|
||||
var ret: u8 = undefined;
|
||||
const version = b.runAllowFail(
|
||||
&.{"git", "-C", b.build_root.path orelse ".", "describe", "--tags", "--dirty"},
|
||||
&ret,
|
||||
.Inherit,
|
||||
) catch "dev\n";
|
||||
var ret: u8 = undefined;
|
||||
const version = b.runAllowFail(
|
||||
&.{ "git", "-C", b.build_root.path orelse ".", "describe", "--tags", "--dirty" },
|
||||
&ret,
|
||||
.Inherit,
|
||||
) catch "dev\n";
|
||||
|
||||
const options = b.addOptions();
|
||||
options.addOption([]const u8, "runtime_path_prefix", runtime_path_prefix);
|
||||
options.addOption([]const u8, "version", version);
|
||||
mez.root_module.addOptions("config", options);
|
||||
const options = b.addOptions();
|
||||
options.addOption([]const u8, "runtime_path_prefix", runtime_path_prefix);
|
||||
options.addOption([]const u8, "version", version);
|
||||
mez.root_module.addOptions("config", options);
|
||||
|
||||
b.installArtifact(mez);
|
||||
b.installArtifact(mez);
|
||||
|
||||
const run_step = b.step("run", "Run the compositor");
|
||||
const run_cmd = b.addRunArtifact(mez);
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
const run_step = b.step("run", "Run the compositor");
|
||||
const run_cmd = b.addRunArtifact(mez);
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
}
|
||||
|
|
|
|||
339
src/Cursor.zig
339
src/Cursor.zig
|
|
@ -30,245 +30,198 @@ mode: enum { normal, drag } = .normal,
|
|||
|
||||
// Drag information
|
||||
drag: ?struct {
|
||||
event_code: u32,
|
||||
start: struct {
|
||||
x: c_int,
|
||||
y: c_int
|
||||
},
|
||||
view: ?struct {
|
||||
view: *View,
|
||||
dims: struct { width: c_int, height: c_int },
|
||||
offset: struct { x: c_int, y: c_int, }
|
||||
},
|
||||
event_code: u32,
|
||||
start: struct { x: c_int, y: c_int },
|
||||
view: ?struct { view: *View, dims: struct { width: c_int, height: c_int }, offset: struct {
|
||||
x: c_int,
|
||||
y: c_int,
|
||||
} },
|
||||
},
|
||||
|
||||
pub fn init(self: *Cursor) void {
|
||||
errdefer Utils.oomPanic();
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
self.* = .{
|
||||
.wlr_cursor = try wlr.Cursor.create(),
|
||||
.x_cursor_manager = try wlr.XcursorManager.create(null, 24),
|
||||
.drag = null
|
||||
};
|
||||
self.* = .{
|
||||
.wlr_cursor = try wlr.Cursor.create(),
|
||||
.x_cursor_manager = try wlr.XcursorManager.create(null, 24),
|
||||
.drag = null,
|
||||
};
|
||||
|
||||
try self.x_cursor_manager.load(1);
|
||||
try self.x_cursor_manager.load(1);
|
||||
|
||||
self.wlr_cursor.attachOutputLayout(server.root.output_layout);
|
||||
self.wlr_cursor.attachOutputLayout(server.root.output_layout);
|
||||
|
||||
self.wlr_cursor.events.motion.add(&self.motion);
|
||||
self.wlr_cursor.events.motion_absolute.add(&self.motion_absolute);
|
||||
self.wlr_cursor.events.button.add(&self.button);
|
||||
self.wlr_cursor.events.axis.add(&self.axis);
|
||||
self.wlr_cursor.events.frame.add(&self.frame);
|
||||
self.wlr_cursor.events.hold_begin.add(&self.hold_begin);
|
||||
self.wlr_cursor.events.hold_end.add(&self.hold_end);
|
||||
self.wlr_cursor.events.motion.add(&self.motion);
|
||||
self.wlr_cursor.events.motion_absolute.add(&self.motion_absolute);
|
||||
self.wlr_cursor.events.button.add(&self.button);
|
||||
self.wlr_cursor.events.axis.add(&self.axis);
|
||||
self.wlr_cursor.events.frame.add(&self.frame);
|
||||
self.wlr_cursor.events.hold_begin.add(&self.hold_begin);
|
||||
self.wlr_cursor.events.hold_end.add(&self.hold_end);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Cursor) void {
|
||||
self.motion.link.remove();
|
||||
self.motion_absolute.link.remove();
|
||||
self.button.link.remove();
|
||||
self.axis.link.remove();
|
||||
self.frame.link.remove();
|
||||
self.hold_begin.link.remove();
|
||||
self.hold_end.link.remove();
|
||||
self.motion.link.remove();
|
||||
self.motion_absolute.link.remove();
|
||||
self.button.link.remove();
|
||||
self.axis.link.remove();
|
||||
self.frame.link.remove();
|
||||
self.hold_begin.link.remove();
|
||||
self.hold_end.link.remove();
|
||||
|
||||
self.wlr_cursor.destroy();
|
||||
self.x_cursor_manager.destroy();
|
||||
self.wlr_cursor.destroy();
|
||||
self.x_cursor_manager.destroy();
|
||||
}
|
||||
|
||||
pub fn processCursorMotion(self: *Cursor, time_msec: u32) void {
|
||||
var passthrough = true;
|
||||
var passthrough = true;
|
||||
|
||||
if (self.mode == .drag) {
|
||||
const modifiers = server.seat.keyboard_group.wlr_group.keyboard.getModifiers();
|
||||
if (self.mode == .drag) {
|
||||
const modifiers = server.seat.keyboard_group.wlr_group.keyboard.getModifiers();
|
||||
|
||||
std.debug.assert(self.drag != null);
|
||||
std.debug.assert(self.drag != null);
|
||||
|
||||
// Proceed if mousemap for current mouse and modifier state's exist
|
||||
if (server.mousemaps.get(Mousemap.hash(modifiers, @bitCast(self.drag.?.event_code)))) |map| {
|
||||
if(map.options.lua_drag_ref_idx > 0) {
|
||||
passthrough = map.callback(.drag, .{
|
||||
.{
|
||||
.x = @as(c_int, @intFromFloat(self.wlr_cursor.x)),
|
||||
.y = @as(c_int, @intFromFloat(self.wlr_cursor.y))
|
||||
},
|
||||
.{
|
||||
.start = self.drag.?.start,
|
||||
.view = if (self.drag.?.view != null) .{
|
||||
.id = self.drag.?.view.?.view.id,
|
||||
.dims = self.drag.?.view.?.dims,
|
||||
.offset = self.drag.?.view.?.offset
|
||||
} else null
|
||||
}
|
||||
});
|
||||
}
|
||||
// Proceed if mousemap for current mouse and modifier state's exist
|
||||
if (server.mousemaps.get(Mousemap.hash(modifiers, @bitCast(self.drag.?.event_code)))) |map| {
|
||||
if (map.options.lua_drag_ref_idx > 0) {
|
||||
passthrough = map.callback(.drag, .{ .{ .x = @as(c_int, @intFromFloat(self.wlr_cursor.x)), .y = @as(c_int, @intFromFloat(self.wlr_cursor.y)) }, .{ .start = self.drag.?.start, .view = if (self.drag.?.view != null) .{ .id = self.drag.?.view.?.view.id, .dims = self.drag.?.view.?.dims, .offset = self.drag.?.view.?.offset } else null } });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(passthrough) {
|
||||
const output = server.seat.focused_output;
|
||||
// Exit the switch if no focused output exists
|
||||
std.debug.assert(output != null);
|
||||
if (passthrough) {
|
||||
const output = server.seat.focused_output;
|
||||
// Exit the switch if no focused output exists
|
||||
std.debug.assert(output != null);
|
||||
|
||||
const surfaceAtResult = output.?.surfaceAt(self.wlr_cursor.x, self.wlr_cursor.y);
|
||||
if (surfaceAtResult) |surface| {
|
||||
if(surface.scene_node_data.* == .view) {
|
||||
server.events.exec("ViewPointerMotion", .{
|
||||
surface.scene_node_data.view.id,
|
||||
@as(c_int, @intFromFloat(self.wlr_cursor.x)),
|
||||
@as(c_int, @intFromFloat(self.wlr_cursor.y))
|
||||
});
|
||||
}
|
||||
const surfaceAtResult = output.?.surfaceAt(self.wlr_cursor.x, self.wlr_cursor.y);
|
||||
if (surfaceAtResult) |surface| {
|
||||
if (surface.scene_node_data.* == .view) {
|
||||
server.events.exec("ViewPointerMotion", .{ surface.scene_node_data.view.id, @as(c_int, @intFromFloat(self.wlr_cursor.x)), @as(c_int, @intFromFloat(self.wlr_cursor.y)) });
|
||||
}
|
||||
|
||||
server.seat.wlr_seat.pointerNotifyEnter(surfaceAtResult.?.surface, surfaceAtResult.?.sx, surfaceAtResult.?.sy);
|
||||
server.seat.wlr_seat.pointerNotifyMotion(time_msec, surfaceAtResult.?.sx, surfaceAtResult.?.sy);
|
||||
} else {
|
||||
// This may not be necessary, remove if no bugs
|
||||
server.seat.wlr_seat.pointerClearFocus();
|
||||
self.wlr_cursor.setXcursor(self.x_cursor_manager, "default");
|
||||
server.seat.wlr_seat.pointerNotifyEnter(surfaceAtResult.?.surface, surfaceAtResult.?.sx, surfaceAtResult.?.sy);
|
||||
server.seat.wlr_seat.pointerNotifyMotion(time_msec, surfaceAtResult.?.sx, surfaceAtResult.?.sy);
|
||||
} else {
|
||||
// This may not be necessary, remove if no bugs
|
||||
server.seat.wlr_seat.pointerClearFocus();
|
||||
self.wlr_cursor.setXcursor(self.x_cursor_manager, "default");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------- WLR Cursor event handlers ---------
|
||||
fn handleMotion(
|
||||
_: *wl.Listener(*wlr.Pointer.event.Motion),
|
||||
event: *wlr.Pointer.event.Motion,
|
||||
_: *wl.Listener(*wlr.Pointer.event.Motion),
|
||||
event: *wlr.Pointer.event.Motion,
|
||||
) void {
|
||||
server.cursor.wlr_cursor.move(event.device, event.delta_x, event.delta_y);
|
||||
server.cursor.processCursorMotion(event.time_msec);
|
||||
server.cursor.wlr_cursor.move(event.device, event.delta_x, event.delta_y);
|
||||
server.cursor.processCursorMotion(event.time_msec);
|
||||
}
|
||||
|
||||
fn handleMotionAbsolute(
|
||||
_: *wl.Listener(*wlr.Pointer.event.MotionAbsolute),
|
||||
event: *wlr.Pointer.event.MotionAbsolute,
|
||||
_: *wl.Listener(*wlr.Pointer.event.MotionAbsolute),
|
||||
event: *wlr.Pointer.event.MotionAbsolute,
|
||||
) void {
|
||||
server.cursor.wlr_cursor.warpAbsolute(event.device, event.x, event.y);
|
||||
server.cursor.processCursorMotion(event.time_msec);
|
||||
server.cursor.wlr_cursor.warpAbsolute(event.device, event.x, event.y);
|
||||
server.cursor.processCursorMotion(event.time_msec);
|
||||
}
|
||||
|
||||
fn handleButton(
|
||||
listener: *wl.Listener(*wlr.Pointer.event.Button),
|
||||
event: *wlr.Pointer.event.Button
|
||||
) void {
|
||||
const cursor: *Cursor = @fieldParentPtr("button", listener);
|
||||
fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.Pointer.event.Button) void {
|
||||
const cursor: *Cursor = @fieldParentPtr("button", listener);
|
||||
|
||||
switch (event.state) {
|
||||
.pressed => {
|
||||
cursor.mode = .drag;
|
||||
|
||||
cursor.drag = .{
|
||||
.event_code = event.button,
|
||||
.start = .{
|
||||
.x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)),
|
||||
.y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y))
|
||||
},
|
||||
.view = null
|
||||
};
|
||||
|
||||
// Keep track of where the drag started
|
||||
if(server.seat.focused_surface) |fs| {
|
||||
if(fs == .view) {
|
||||
cursor.drag.?.view = .{
|
||||
.view = fs.view,
|
||||
.dims = .{
|
||||
.width = fs.view.xdg_toplevel.base.geometry.width,
|
||||
.height = fs.view.xdg_toplevel.base.geometry.height
|
||||
},
|
||||
.offset = .{
|
||||
.x = cursor.drag.?.start.x - fs.view.scene_tree.node.x,
|
||||
.y = cursor.drag.?.start.y - fs.view.scene_tree.node.y
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
.released => {
|
||||
cursor.mode = .normal;
|
||||
|
||||
// How do we do this on the lua side
|
||||
// if(cursor.drag.view) |view| {
|
||||
// _ = view.xdg_toplevel.setResizing(false);
|
||||
// }
|
||||
|
||||
cursor.drag.?.view = null;
|
||||
},
|
||||
else => {
|
||||
std.log.err("Invalid/Unimplemented pointer button event type", .{});
|
||||
}
|
||||
}
|
||||
|
||||
var passthrough = true;
|
||||
const modifiers = server.seat.keyboard_group.wlr_group.keyboard.getModifiers();
|
||||
|
||||
// Proceed if mousemap for current mouse and modifier state's exist
|
||||
if (server.mousemaps.get(Mousemap.hash(modifiers, @bitCast(event.button)))) |map| {
|
||||
switch (event.state) {
|
||||
.pressed => {
|
||||
// Only make callback if a callback function exists
|
||||
if(map.options.lua_press_ref_idx > 0) {
|
||||
passthrough = map.callback(.press, .{
|
||||
.{
|
||||
.x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)),
|
||||
.y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y))
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
.released => {
|
||||
if(map.options.lua_press_ref_idx > 0) {
|
||||
passthrough = map.callback(.release, .{
|
||||
.{
|
||||
.x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)),
|
||||
.y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y))
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
else => { unreachable; }
|
||||
.pressed => {
|
||||
cursor.mode = .drag;
|
||||
|
||||
cursor.drag = .{ .event_code = event.button, .start = .{ .x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)), .y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)) }, .view = null };
|
||||
|
||||
// Keep track of where the drag started
|
||||
if (server.seat.focused_surface) |fs| {
|
||||
if (fs == .view) {
|
||||
cursor.drag.?.view = .{
|
||||
.view = fs.view,
|
||||
.dims = .{ .width = fs.view.xdg_toplevel.base.geometry.width, .height = fs.view.xdg_toplevel.base.geometry.height },
|
||||
.offset = .{ .x = cursor.drag.?.start.x - fs.view.scene_tree.node.x, .y = cursor.drag.?.start.y - fs.view.scene_tree.node.y },
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
.released => {
|
||||
cursor.mode = .normal;
|
||||
|
||||
// How do we do this on the lua side
|
||||
// if(cursor.drag.view) |view| {
|
||||
// _ = view.xdg_toplevel.setResizing(false);
|
||||
// }
|
||||
|
||||
cursor.drag.?.view = null;
|
||||
},
|
||||
else => {
|
||||
std.log.err("Invalid/Unimplemented pointer button event type", .{});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// If no keymap exists for button event, forward it to a surface
|
||||
// TODO: Allow for transparent mousemaps that pass mouse button events anyways
|
||||
if(passthrough) {
|
||||
_ = server.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
|
||||
}
|
||||
var passthrough = true;
|
||||
const modifiers = server.seat.keyboard_group.wlr_group.keyboard.getModifiers();
|
||||
|
||||
// Proceed if mousemap for current mouse and modifier state's exist
|
||||
if (server.mousemaps.get(Mousemap.hash(modifiers, @bitCast(event.button)))) |map| {
|
||||
switch (event.state) {
|
||||
.pressed => {
|
||||
// Only make callback if a callback function exists
|
||||
if (map.options.lua_press_ref_idx > 0) {
|
||||
passthrough = map.callback(.press, .{
|
||||
.{ .x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)), .y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)) },
|
||||
});
|
||||
}
|
||||
},
|
||||
.released => {
|
||||
if (map.options.lua_press_ref_idx > 0) {
|
||||
passthrough = map.callback(.release, .{
|
||||
.{ .x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)), .y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)) },
|
||||
});
|
||||
}
|
||||
},
|
||||
else => {
|
||||
unreachable;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// If no keymap exists for button event, forward it to a surface
|
||||
// TODO: Allow for transparent mousemaps that pass mouse button events anyways
|
||||
if (passthrough) {
|
||||
_ = server.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
|
||||
}
|
||||
}
|
||||
|
||||
fn handleHoldBegin(
|
||||
listener: *wl.Listener(*wlr.Pointer.event.HoldBegin),
|
||||
event: *wlr.Pointer.event.HoldBegin
|
||||
) void {
|
||||
_ = listener;
|
||||
_ = event;
|
||||
std.log.err("Unimplemented cursor start hold", .{});
|
||||
fn handleHoldBegin(listener: *wl.Listener(*wlr.Pointer.event.HoldBegin), event: *wlr.Pointer.event.HoldBegin) void {
|
||||
_ = listener;
|
||||
_ = event;
|
||||
std.log.err("Unimplemented cursor start hold", .{});
|
||||
}
|
||||
|
||||
fn handleHoldEnd(
|
||||
listener: *wl.Listener(*wlr.Pointer.event.HoldEnd),
|
||||
event: *wlr.Pointer.event.HoldEnd
|
||||
) void {
|
||||
_ = listener;
|
||||
_ = event;
|
||||
std.log.err("Unimplemented cursor end hold", .{});
|
||||
fn handleHoldEnd(listener: *wl.Listener(*wlr.Pointer.event.HoldEnd), event: *wlr.Pointer.event.HoldEnd) void {
|
||||
_ = listener;
|
||||
_ = event;
|
||||
std.log.err("Unimplemented cursor end hold", .{});
|
||||
}
|
||||
|
||||
fn handleAxis(
|
||||
_: *wl.Listener(*wlr.Pointer.event.Axis),
|
||||
event: *wlr.Pointer.event.Axis,
|
||||
_: *wl.Listener(*wlr.Pointer.event.Axis),
|
||||
event: *wlr.Pointer.event.Axis,
|
||||
) void {
|
||||
server.seat.wlr_seat.pointerNotifyAxis(
|
||||
event.time_msec,
|
||||
event.orientation,
|
||||
event.delta,
|
||||
event.delta_discrete,
|
||||
event.source,
|
||||
event.relative_direction,
|
||||
);
|
||||
server.seat.wlr_seat.pointerNotifyAxis(
|
||||
event.time_msec,
|
||||
event.orientation,
|
||||
event.delta,
|
||||
event.delta_discrete,
|
||||
event.source,
|
||||
event.relative_direction,
|
||||
);
|
||||
}
|
||||
|
||||
fn handleFrame(_: *wl.Listener(*wlr.Cursor), _: *wlr.Cursor) void {
|
||||
server.seat.wlr_seat.pointerNotifyFrame();
|
||||
server.seat.wlr_seat.pointerNotifyFrame();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,15 +31,10 @@ fn printNode(node: *wlr.SceneNode, depth: usize) void {
|
|||
const type_name = switch (node.type) {
|
||||
.tree => "TREE",
|
||||
.rect => "RECT",
|
||||
.buffer => "BUFFER"
|
||||
.buffer => "BUFFER",
|
||||
};
|
||||
|
||||
writer.print("{s} @ ({d}, {d}) enabled={}", .{
|
||||
type_name,
|
||||
node.x,
|
||||
node.y,
|
||||
node.enabled
|
||||
}) catch unreachable;
|
||||
writer.print("{s} @ ({d}, {d}) enabled={}", .{ type_name, node.x, node.y, node.enabled }) catch unreachable;
|
||||
|
||||
// Add associated data if present
|
||||
if (node.data) |data| {
|
||||
|
|
@ -56,7 +51,7 @@ fn printNode(node: *wlr.SceneNode, depth: usize) void {
|
|||
}) catch unreachable;
|
||||
},
|
||||
.output_layer => {
|
||||
writer.print(" → Output Layer", .{}) catch unreachable;
|
||||
writer.print(" → Output Layer", .{}) catch unreachable;
|
||||
},
|
||||
.view => |view| {
|
||||
writer.print(" → View: id={} mapped={} focused={}", .{
|
||||
|
|
@ -84,7 +79,7 @@ fn printNode(node: *wlr.SceneNode, depth: usize) void {
|
|||
if (namespace.len > 0) {
|
||||
writer.print(" namespace=\"{s}\"", .{namespace}) catch unreachable;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
160
src/Keyboard.zig
160
src/Keyboard.zig
|
|
@ -26,120 +26,114 @@ modifiers: wl.Listener(*wlr.Keyboard) = .init(handleModifiers),
|
|||
destroy: wl.Listener(*wlr.InputDevice) = .init(handleDestroy),
|
||||
|
||||
pub fn init(device: *wlr.InputDevice) *Keyboard {
|
||||
const self = gpa.create(Keyboard) catch Utils.oomPanic();
|
||||
const self = gpa.create(Keyboard) catch Utils.oomPanic();
|
||||
|
||||
errdefer {
|
||||
std.log.err("Unable to initialize new keyboard, exiting", .{});
|
||||
std.process.exit(6);
|
||||
}
|
||||
errdefer {
|
||||
std.log.err("Unable to initialize new keyboard, exiting", .{});
|
||||
std.process.exit(6);
|
||||
}
|
||||
|
||||
self.* = .{
|
||||
.context = xkb.Context.new(.no_flags) orelse return error.ContextFailed,
|
||||
.wlr_keyboard = device.toKeyboard(),
|
||||
.device = device,
|
||||
};
|
||||
self.* = .{
|
||||
.context = xkb.Context.new(.no_flags) orelse return error.ContextFailed,
|
||||
.wlr_keyboard = device.toKeyboard(),
|
||||
.device = device,
|
||||
};
|
||||
|
||||
// TODO: configure this via lua later
|
||||
// Should handle this error here
|
||||
if (!self.wlr_keyboard.setKeymap(server.seat.keymap)) return error.SetKeymapFailed;
|
||||
self.wlr_keyboard.setRepeatInfo(25, 600);
|
||||
// TODO: configure this via lua later
|
||||
// Should handle this error here
|
||||
if (!self.wlr_keyboard.setKeymap(server.seat.keymap)) return error.SetKeymapFailed;
|
||||
self.wlr_keyboard.setRepeatInfo(25, 600);
|
||||
|
||||
self.wlr_keyboard.events.modifiers.add(&self.modifiers);
|
||||
self.wlr_keyboard.events.key.add(&self.key);
|
||||
self.wlr_keyboard.events.keymap.add(&self.key_map);
|
||||
self.wlr_keyboard.events.modifiers.add(&self.modifiers);
|
||||
self.wlr_keyboard.events.key.add(&self.key);
|
||||
self.wlr_keyboard.events.keymap.add(&self.key_map);
|
||||
|
||||
device.events.destroy.add(&self.destroy);
|
||||
device.events.destroy.add(&self.destroy);
|
||||
|
||||
self.wlr_keyboard.data = self;
|
||||
self.wlr_keyboard.data = self;
|
||||
|
||||
std.log.err("Adding new keyboard {s}", .{device.name orelse "(unnamed)"});
|
||||
if(!server.seat.keyboard_group.wlr_group.addKeyboard(self.wlr_keyboard)) {
|
||||
std.log.err("Adding new keyboard {s} failed", .{device.name orelse "(unnamed)"});
|
||||
}
|
||||
std.log.err("Adding new keyboard {s}", .{device.name orelse "(unnamed)"});
|
||||
if (!server.seat.keyboard_group.wlr_group.addKeyboard(self.wlr_keyboard)) {
|
||||
std.log.err("Adding new keyboard {s} failed", .{device.name orelse "(unnamed)"});
|
||||
}
|
||||
|
||||
return self;
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit (self: *Keyboard) void {
|
||||
self.key.link.remove();
|
||||
self.key_map.link.remove();
|
||||
self.modifiers.link.remove();
|
||||
pub fn deinit(self: *Keyboard) void {
|
||||
self.key.link.remove();
|
||||
self.key_map.link.remove();
|
||||
self.modifiers.link.remove();
|
||||
}
|
||||
|
||||
fn handleModifiers(_: *wl.Listener(*wlr.Keyboard), wlr_keyboard: *wlr.Keyboard) void {
|
||||
server.seat.wlr_seat.setKeyboard(wlr_keyboard);
|
||||
server.seat.wlr_seat.keyboardNotifyModifiers(&wlr_keyboard.modifiers);
|
||||
server.seat.wlr_seat.setKeyboard(wlr_keyboard);
|
||||
server.seat.wlr_seat.keyboardNotifyModifiers(&wlr_keyboard.modifiers);
|
||||
}
|
||||
|
||||
fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboard.event.Key) void {
|
||||
const keyboard: *Keyboard = @fieldParentPtr("key", listener);
|
||||
// Translate libinput keycode -> xkbcommon
|
||||
const keycode = event.keycode + 8;
|
||||
const keyboard: *Keyboard = @fieldParentPtr("key", listener);
|
||||
// Translate libinput keycode -> xkbcommon
|
||||
const keycode = event.keycode + 8;
|
||||
|
||||
var handled: bool = false;
|
||||
const modifiers = server.seat.keyboard_group.wlr_group.keyboard.getModifiers();
|
||||
if (server.seat.keyboard_group.wlr_group.keyboard.xkb_state) |xkb_state| {
|
||||
const keysyms = xkb_state.keyGetSyms(keycode);
|
||||
for (keysyms) |sym| {
|
||||
handled = keypress(modifiers, sym, event.state);
|
||||
var handled: bool = false;
|
||||
const modifiers = server.seat.keyboard_group.wlr_group.keyboard.getModifiers();
|
||||
if (server.seat.keyboard_group.wlr_group.keyboard.xkb_state) |xkb_state| {
|
||||
const keysyms = xkb_state.keyGetSyms(keycode);
|
||||
for (keysyms) |sym| {
|
||||
handled = keypress(modifiers, sym, event.state);
|
||||
}
|
||||
|
||||
// give the keyboard group information about what to repeat and update it
|
||||
if (handled and keyboard.wlr_keyboard.repeat_info.delay > 0) {
|
||||
server.seat.keyboard_group.modifiers = modifiers;
|
||||
server.seat.keyboard_group.keysyms = keysyms;
|
||||
server.seat.keyboard_group.repeat_source.?.timerUpdate(
|
||||
keyboard.wlr_keyboard.repeat_info.delay,
|
||||
) catch {
|
||||
std.log.warn("failed to update keyboard repeat timer", .{});
|
||||
};
|
||||
} else {
|
||||
server.seat.keyboard_group.modifiers = null;
|
||||
server.seat.keyboard_group.keysyms = null;
|
||||
}
|
||||
}
|
||||
|
||||
// give the keyboard group information about what to repeat and update it
|
||||
if (handled and keyboard.wlr_keyboard.repeat_info.delay > 0) {
|
||||
server.seat.keyboard_group.modifiers = modifiers;
|
||||
server.seat.keyboard_group.keysyms = keysyms;
|
||||
server.seat.keyboard_group.repeat_source.?.timerUpdate(
|
||||
keyboard.wlr_keyboard.repeat_info.delay,
|
||||
) catch {
|
||||
std.log.warn("failed to update keyboard repeat timer", .{});
|
||||
};
|
||||
} else {
|
||||
server.seat.keyboard_group.modifiers = null;
|
||||
server.seat.keyboard_group.keysyms = null;
|
||||
if (handled and keyboard.wlr_keyboard.repeat_info.delay > 0) {}
|
||||
|
||||
if (!handled) {
|
||||
server.seat.wlr_seat.setKeyboard(&server.seat.keyboard_group.wlr_group.keyboard);
|
||||
server.seat.wlr_seat.keyboardNotifyKey(event.time_msec, event.keycode, event.state);
|
||||
}
|
||||
}
|
||||
|
||||
if (handled and keyboard.wlr_keyboard.repeat_info.delay > 0) {
|
||||
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
server.seat.wlr_seat.setKeyboard(&server.seat.keyboard_group.wlr_group.keyboard);
|
||||
server.seat.wlr_seat.keyboardNotifyKey(event.time_msec, event.keycode, event.state);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keypress(
|
||||
modifiers: wlr.Keyboard.ModifierMask,
|
||||
sym: xkb.Keysym,
|
||||
state: wl.Keyboard.KeyState
|
||||
) bool {
|
||||
if (server.keymaps.get(Keymap.hash(modifiers, sym))) |map| {
|
||||
if (state == .pressed and map.options.lua_press_ref_idx > 0) {
|
||||
map.callback(false);
|
||||
return true;
|
||||
} else if (state == .released and map.options.lua_release_ref_idx > 0) {
|
||||
map.callback(true);
|
||||
return true;
|
||||
pub fn keypress(modifiers: wlr.Keyboard.ModifierMask, sym: xkb.Keysym, state: wl.Keyboard.KeyState) bool {
|
||||
if (server.keymaps.get(Keymap.hash(modifiers, sym))) |map| {
|
||||
if (state == .pressed and map.options.lua_press_ref_idx > 0) {
|
||||
map.callback(false);
|
||||
return true;
|
||||
} else if (state == .released and map.options.lua_release_ref_idx > 0) {
|
||||
map.callback(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
fn handleKeyMap(_: *wl.Listener(*wlr.Keyboard), _: *wlr.Keyboard) void {
|
||||
std.log.err("Unimplemented handle keyboard keymap", .{});
|
||||
std.log.err("Unimplemented handle keyboard keymap", .{});
|
||||
}
|
||||
|
||||
pub fn handleDestroy(listener: *wl.Listener(*wlr.InputDevice), _: *wlr.InputDevice) void {
|
||||
const keyboard: *Keyboard = @fieldParentPtr("destroy", listener);
|
||||
const keyboard: *Keyboard = @fieldParentPtr("destroy", listener);
|
||||
|
||||
std.log.debug("removing keyboard: {s}", .{keyboard.device.name orelse "(null)"});
|
||||
std.log.debug("removing keyboard: {s}", .{keyboard.device.name orelse "(null)"});
|
||||
|
||||
keyboard.modifiers.link.remove();
|
||||
keyboard.key.link.remove();
|
||||
keyboard.key_map.link.remove();
|
||||
keyboard.destroy.link.remove();
|
||||
keyboard.modifiers.link.remove();
|
||||
keyboard.key.link.remove();
|
||||
keyboard.key_map.link.remove();
|
||||
keyboard.destroy.link.remove();
|
||||
|
||||
gpa.destroy(keyboard);
|
||||
gpa.destroy(keyboard);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const wlr = @import("wlroots");
|
|||
const xkb = @import("xkbcommon");
|
||||
|
||||
const Keyboard = @import("Keyboard.zig");
|
||||
const Utils = @import("Utils.zig");
|
||||
const Utils = @import("Utils.zig");
|
||||
|
||||
const server = &@import("main.zig").server;
|
||||
const gpa = std.heap.c_allocator;
|
||||
|
|
@ -17,47 +17,48 @@ modifiers: ?wlr.Keyboard.ModifierMask,
|
|||
keysyms: ?[]const xkb.Keysym,
|
||||
|
||||
pub fn init() *KeyboardGroup {
|
||||
errdefer Utils.oomPanic();
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
const self = try gpa.create(KeyboardGroup);
|
||||
self.* = .{
|
||||
.wlr_group = wlr.KeyboardGroup.create() catch Utils.oomPanic(),
|
||||
.repeat_source = blk: {
|
||||
break :blk server.event_loop.addTimer(?*KeyboardGroup, handleRepeat, self) catch {
|
||||
std.log.err("Failed to create event loop timer, keyboard repeating will not work!", .{});
|
||||
break :blk null;
|
||||
};
|
||||
},
|
||||
.modifiers = null,
|
||||
.keysyms = null,
|
||||
};
|
||||
const self = try gpa.create(KeyboardGroup);
|
||||
self.* = .{
|
||||
.wlr_group = wlr.KeyboardGroup.create() catch Utils.oomPanic(),
|
||||
.repeat_source = blk: {
|
||||
break :blk server.event_loop.addTimer(?*KeyboardGroup, handleRepeat, self) catch {
|
||||
std.log.err("Failed to create event loop timer, keyboard repeating will not work!", .{});
|
||||
break :blk null;
|
||||
};
|
||||
},
|
||||
.modifiers = null,
|
||||
.keysyms = null,
|
||||
};
|
||||
|
||||
return self;
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *KeyboardGroup) void {
|
||||
self.wlr_group.destroy();
|
||||
gpa.destroy(self);
|
||||
self.wlr_group.destroy();
|
||||
gpa.destroy(self);
|
||||
}
|
||||
|
||||
fn handleRepeat(data: ?*KeyboardGroup) c_int {
|
||||
// we failed to create the event loop timer, which means we can't repeat keys
|
||||
if (data.?.repeat_source == null) return 0;
|
||||
// we failed to create the event loop timer, which means we can't repeat keys
|
||||
if (data.?.repeat_source == null) return 0;
|
||||
|
||||
if (data == null or data.?.keysyms == null or data.?.modifiers == null or
|
||||
data.?.wlr_group.keyboard.repeat_info.rate <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
data.?.repeat_source.?.timerUpdate(
|
||||
@divTrunc(1000, data.?.wlr_group.keyboard.repeat_info.rate),
|
||||
) catch {
|
||||
// not sure how big of a deal it is if we miss a timer update
|
||||
std.log.warn("failed to update keyboard repeat timer", .{});
|
||||
};
|
||||
for (data.?.keysyms.?) |sym| {
|
||||
_ = Keyboard.keypress(data.?.modifiers.?, sym, .pressed);
|
||||
}
|
||||
|
||||
if (data == null or data.?.keysyms == null or data.?.modifiers == null or
|
||||
data.?.wlr_group.keyboard.repeat_info.rate <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
data.?.repeat_source.?.timerUpdate(
|
||||
@divTrunc(1000, data.?.wlr_group.keyboard.repeat_info.rate),
|
||||
) catch {
|
||||
// not sure how big of a deal it is if we miss a timer update
|
||||
std.log.warn("failed to update keyboard repeat timer", .{});
|
||||
};
|
||||
for (data.?.keysyms.?) |sym| {
|
||||
_ = Keyboard.keypress(data.?.modifiers.?, sym, .pressed);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,109 +23,97 @@ commit: wl.Listener(*wlr.Surface) = .init(handleCommit),
|
|||
// new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup),
|
||||
|
||||
pub fn init(wlr_layer_surface: *wlr.LayerSurfaceV1) *LayerSurface {
|
||||
errdefer Utils.oomPanic();
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
const self = try gpa.create(LayerSurface);
|
||||
const self = try gpa.create(LayerSurface);
|
||||
|
||||
self.* = .{
|
||||
.output = undefined,
|
||||
.wlr_layer_surface = wlr_layer_surface,
|
||||
.scene_layer_surface = undefined,
|
||||
.scene_node_data = .{ .layer_surface = self }
|
||||
};
|
||||
|
||||
if(wlr_layer_surface.output.?.data == null) {
|
||||
std.log.err("Wlr_output arbitrary data not assigned", .{});
|
||||
unreachable;
|
||||
}
|
||||
self.output = @ptrCast(@alignCast(wlr_layer_surface.output.?.data));
|
||||
|
||||
if(server.seat.focused_output) |output| {
|
||||
self.scene_layer_surface = switch (wlr_layer_surface.current.layer) {
|
||||
.background => try output.layers.background.createSceneLayerSurfaceV1(wlr_layer_surface),
|
||||
.bottom => try output.layers.bottom.createSceneLayerSurfaceV1(wlr_layer_surface),
|
||||
.top => try output.layers.top.createSceneLayerSurfaceV1(wlr_layer_surface),
|
||||
.overlay => try output.layers.overlay.createSceneLayerSurfaceV1(wlr_layer_surface),
|
||||
else => {
|
||||
std.log.err("New layer surface of unidentified type", .{});
|
||||
unreachable;
|
||||
}
|
||||
self.* = .{
|
||||
.output = undefined,
|
||||
.wlr_layer_surface = wlr_layer_surface,
|
||||
.scene_layer_surface = undefined,
|
||||
.scene_node_data = .{ .layer_surface = self },
|
||||
};
|
||||
}
|
||||
|
||||
self.wlr_layer_surface.surface.data = &self.scene_node_data;
|
||||
self.scene_layer_surface.tree.node.data = &self.scene_node_data;
|
||||
if (wlr_layer_surface.output.?.data == null) {
|
||||
std.log.err("Wlr_output arbitrary data not assigned", .{});
|
||||
unreachable;
|
||||
}
|
||||
self.output = @ptrCast(@alignCast(wlr_layer_surface.output.?.data));
|
||||
|
||||
self.wlr_layer_surface.events.destroy.add(&self.destroy);
|
||||
self.wlr_layer_surface.surface.events.map.add(&self.map);
|
||||
self.wlr_layer_surface.surface.events.unmap.add(&self.unmap);
|
||||
self.wlr_layer_surface.surface.events.commit.add(&self.commit);
|
||||
if (server.seat.focused_output) |output| {
|
||||
self.scene_layer_surface = switch (wlr_layer_surface.current.layer) {
|
||||
.background => try output.layers.background.createSceneLayerSurfaceV1(wlr_layer_surface),
|
||||
.bottom => try output.layers.bottom.createSceneLayerSurfaceV1(wlr_layer_surface),
|
||||
.top => try output.layers.top.createSceneLayerSurfaceV1(wlr_layer_surface),
|
||||
.overlay => try output.layers.overlay.createSceneLayerSurfaceV1(wlr_layer_surface),
|
||||
else => {
|
||||
std.log.err("New layer surface of unidentified type", .{});
|
||||
unreachable;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return self;
|
||||
self.wlr_layer_surface.surface.data = &self.scene_node_data;
|
||||
self.scene_layer_surface.tree.node.data = &self.scene_node_data;
|
||||
|
||||
self.wlr_layer_surface.events.destroy.add(&self.destroy);
|
||||
self.wlr_layer_surface.surface.events.map.add(&self.map);
|
||||
self.wlr_layer_surface.surface.events.unmap.add(&self.unmap);
|
||||
self.wlr_layer_surface.surface.events.commit.add(&self.commit);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *LayerSurface) void {
|
||||
self.destroy.link.remove();
|
||||
self.map.link.remove();
|
||||
self.unmap.link.remove();
|
||||
self.commit.link.remove();
|
||||
self.destroy.link.remove();
|
||||
self.map.link.remove();
|
||||
self.unmap.link.remove();
|
||||
self.commit.link.remove();
|
||||
|
||||
self.wlr_layer_surface.surface.data = null;
|
||||
self.wlr_layer_surface.surface.data = null;
|
||||
|
||||
gpa.destroy(self);
|
||||
gpa.destroy(self);
|
||||
}
|
||||
|
||||
pub fn allowKeyboard(self: *LayerSurface) void {
|
||||
const keyboard_interactive = self.wlr_layer_surface.current.keyboard_interactive;
|
||||
if(keyboard_interactive == .exclusive or keyboard_interactive == .on_demand) {
|
||||
server.seat.wlr_seat.keyboardNotifyEnter(
|
||||
self.wlr_layer_surface.surface,
|
||||
&server.seat.keyboard_group.wlr_group.keyboard.keycodes,
|
||||
&server.seat.keyboard_group.wlr_group.keyboard.modifiers
|
||||
);
|
||||
}
|
||||
const keyboard_interactive = self.wlr_layer_surface.current.keyboard_interactive;
|
||||
if (keyboard_interactive == .exclusive or keyboard_interactive == .on_demand) {
|
||||
server.seat.wlr_seat.keyboardNotifyEnter(self.wlr_layer_surface.surface, &server.seat.keyboard_group.wlr_group.keyboard.keycodes, &server.seat.keyboard_group.wlr_group.keyboard.modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
// --------- LayerSurface event handlers ---------
|
||||
fn handleDestroy(
|
||||
listener: *wl.Listener(*wlr.LayerSurfaceV1),
|
||||
_: *wlr.LayerSurfaceV1
|
||||
) void {
|
||||
const layer: *LayerSurface = @fieldParentPtr("destroy", listener);
|
||||
layer.deinit();
|
||||
fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), _: *wlr.LayerSurfaceV1) void {
|
||||
const layer: *LayerSurface = @fieldParentPtr("destroy", listener);
|
||||
layer.deinit();
|
||||
}
|
||||
|
||||
fn handleMap(
|
||||
listener: *wl.Listener(void)
|
||||
) void {
|
||||
const layer_suraface: *LayerSurface = @fieldParentPtr("map", listener);
|
||||
std.log.debug("layer surface mapped", .{});
|
||||
layer_suraface.output.arrangeLayers();
|
||||
layer_suraface.allowKeyboard();
|
||||
fn handleMap(listener: *wl.Listener(void)) void {
|
||||
const layer_suraface: *LayerSurface = @fieldParentPtr("map", listener);
|
||||
std.log.debug("layer surface mapped", .{});
|
||||
layer_suraface.output.arrangeLayers();
|
||||
layer_suraface.allowKeyboard();
|
||||
}
|
||||
|
||||
fn handleUnmap(listener: *wl.Listener(void)) void {
|
||||
const layer_surface: *LayerSurface = @fieldParentPtr("unmap", listener);
|
||||
const layer_surface: *LayerSurface = @fieldParentPtr("unmap", listener);
|
||||
|
||||
if (server.seat.focused_surface) |fs| {
|
||||
if (fs == .layer_surface and fs.layer_surface == layer_surface) {
|
||||
server.seat.focusSurface(null);
|
||||
if (server.seat.focused_surface) |fs| {
|
||||
if (fs == .layer_surface and fs.layer_surface == layer_surface) {
|
||||
server.seat.focusSurface(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: this crashes mez when killing mez
|
||||
layer_surface.output.arrangeLayers();
|
||||
// FIXME: this crashes mez when killing mez
|
||||
layer_surface.output.arrangeLayers();
|
||||
|
||||
// TODO: Idk if this should be deiniting the layer surface entirely
|
||||
layer_surface.deinit();
|
||||
// TODO: Idk if this should be deiniting the layer surface entirely
|
||||
layer_surface.deinit();
|
||||
}
|
||||
|
||||
fn handleCommit(
|
||||
listener: *wl.Listener(*wlr.Surface),
|
||||
_: *wlr.Surface
|
||||
) void {
|
||||
const layer_surface: *LayerSurface = @fieldParentPtr("commit", listener);
|
||||
fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||
const layer_surface: *LayerSurface = @fieldParentPtr("commit", listener);
|
||||
|
||||
if (!layer_surface.wlr_layer_surface.initial_commit) return;
|
||||
layer_surface.output.arrangeLayers();
|
||||
if (!layer_surface.wlr_layer_surface.initial_commit) return;
|
||||
layer_surface.output.arrangeLayers();
|
||||
}
|
||||
|
|
|
|||
470
src/Output.zig
470
src/Output.zig
|
|
@ -5,10 +5,10 @@ const zwlr = @import("wayland").server.zwlr;
|
|||
const wlr = @import("wlroots");
|
||||
const std = @import("std");
|
||||
|
||||
const Utils = @import("Utils.zig");
|
||||
const Utils = @import("Utils.zig");
|
||||
|
||||
const Server = @import("Server.zig");
|
||||
const View = @import("View.zig");
|
||||
const View = @import("View.zig");
|
||||
const LayerSurface = @import("LayerSurface.zig");
|
||||
|
||||
const SceneNodeData = @import("SceneNodeData.zig").SceneNodeData;
|
||||
|
|
@ -28,168 +28,167 @@ scene_node_data: SceneNodeData,
|
|||
scene_output: *wlr.SceneOutput,
|
||||
|
||||
layers: struct {
|
||||
background: *wlr.SceneTree,
|
||||
bottom: *wlr.SceneTree,
|
||||
content: *wlr.SceneTree,
|
||||
top: *wlr.SceneTree,
|
||||
fullscreen: *wlr.SceneTree,
|
||||
overlay: *wlr.SceneTree
|
||||
background: *wlr.SceneTree,
|
||||
bottom: *wlr.SceneTree,
|
||||
content: *wlr.SceneTree,
|
||||
top: *wlr.SceneTree,
|
||||
fullscreen: *wlr.SceneTree,
|
||||
overlay: *wlr.SceneTree,
|
||||
},
|
||||
|
||||
layer_scene_node_data: struct {
|
||||
background: SceneNodeData,
|
||||
bottom: SceneNodeData,
|
||||
content: SceneNodeData,
|
||||
top: SceneNodeData,
|
||||
fullscreen: SceneNodeData,
|
||||
overlay: SceneNodeData
|
||||
background: SceneNodeData,
|
||||
bottom: SceneNodeData,
|
||||
content: SceneNodeData,
|
||||
top: SceneNodeData,
|
||||
fullscreen: SceneNodeData,
|
||||
overlay: SceneNodeData,
|
||||
},
|
||||
|
||||
frame: wl.Listener(*wlr.Output) = .init(handleFrame),
|
||||
request_state: wl.Listener(*wlr.Output.event.RequestState) = .init(handleRequestState),
|
||||
destroy: wl.Listener(*wlr.Output) = .init(handleDestroy),
|
||||
|
||||
|
||||
// The wlr.Output should be destroyed by the caller on failure to trigger cleanup.
|
||||
pub fn init(wlr_output: *wlr.Output) ?*Output {
|
||||
errdefer Utils.oomPanic();
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
const self = try gpa.create(Output);
|
||||
const self = try gpa.create(Output);
|
||||
|
||||
self.* = .{
|
||||
.focused = false,
|
||||
.id = @intFromPtr(wlr_output),
|
||||
.wlr_output = wlr_output,
|
||||
.tree = try server.root.scene.tree.createSceneTree(),
|
||||
.fullscreen = null,
|
||||
.layers = .{
|
||||
.background = try self.tree.createSceneTree(),
|
||||
.bottom = try self.tree.createSceneTree(),
|
||||
.content = try self.tree.createSceneTree(),
|
||||
.top = try self.tree.createSceneTree(),
|
||||
.fullscreen = try self.tree.createSceneTree(),
|
||||
.overlay = try self.tree.createSceneTree(),
|
||||
},
|
||||
.layer_scene_node_data = .{
|
||||
.background = .{ .output_layer = self.layers.background },
|
||||
.bottom = .{ .output_layer = self.layers.bottom },
|
||||
.content = .{ .output_layer = self.layers.content },
|
||||
.top = .{ .output_layer = self.layers.top },
|
||||
.fullscreen = .{ .output_layer = self.layers.fullscreen },
|
||||
.overlay = .{ .output_layer = self.layers.overlay }
|
||||
},
|
||||
.scene_output = try server.root.scene.createSceneOutput(wlr_output),
|
||||
.scene_node_data = SceneNodeData{ .output = self },
|
||||
.state = wlr.Output.State.init()
|
||||
};
|
||||
self.* = .{
|
||||
.focused = false,
|
||||
.id = @intFromPtr(wlr_output),
|
||||
.wlr_output = wlr_output,
|
||||
.tree = try server.root.scene.tree.createSceneTree(),
|
||||
.fullscreen = null,
|
||||
|
||||
wlr_output.events.frame.add(&self.frame);
|
||||
wlr_output.events.request_state.add(&self.request_state);
|
||||
wlr_output.events.destroy.add(&self.destroy);
|
||||
.layers = .{
|
||||
.background = try self.tree.createSceneTree(),
|
||||
.bottom = try self.tree.createSceneTree(),
|
||||
.content = try self.tree.createSceneTree(),
|
||||
.top = try self.tree.createSceneTree(),
|
||||
.fullscreen = try self.tree.createSceneTree(),
|
||||
.overlay = try self.tree.createSceneTree(),
|
||||
},
|
||||
|
||||
errdefer deinit(self);
|
||||
.layer_scene_node_data = .{
|
||||
.background = .{ .output_layer = self.layers.background },
|
||||
.bottom = .{ .output_layer = self.layers.bottom },
|
||||
.content = .{ .output_layer = self.layers.content },
|
||||
.top = .{ .output_layer = self.layers.top },
|
||||
.fullscreen = .{ .output_layer = self.layers.fullscreen },
|
||||
.overlay = .{ .output_layer = self.layers.overlay },
|
||||
},
|
||||
|
||||
if(!wlr_output.initRender(server.allocator, server.renderer)) {
|
||||
std.log.err("Unable to start output {s}", .{wlr_output.name});
|
||||
return null;
|
||||
}
|
||||
.scene_output = try server.root.scene.createSceneOutput(wlr_output),
|
||||
.scene_node_data = SceneNodeData{ .output = self },
|
||||
.state = wlr.Output.State.init()
|
||||
};
|
||||
|
||||
self.state.setEnabled(true);
|
||||
wlr_output.events.frame.add(&self.frame);
|
||||
wlr_output.events.request_state.add(&self.request_state);
|
||||
wlr_output.events.destroy.add(&self.destroy);
|
||||
|
||||
if (wlr_output.preferredMode()) |mode| {
|
||||
self.state.setMode(mode);
|
||||
}
|
||||
errdefer deinit(self);
|
||||
|
||||
if(!wlr_output.commitState(&self.state)) {
|
||||
std.log.err("Unable to commit state to output {s}", .{wlr_output.name});
|
||||
return null;
|
||||
}
|
||||
if (!wlr_output.initRender(server.allocator, server.renderer)) {
|
||||
std.log.err("Unable to start output {s}", .{wlr_output.name});
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Allow user to define output positions
|
||||
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();
|
||||
self.state.setEnabled(true);
|
||||
|
||||
self.wlr_output.data = self;
|
||||
self.tree.node.data = &self.scene_node_data;
|
||||
if (wlr_output.preferredMode()) |mode| {
|
||||
self.state.setMode(mode);
|
||||
}
|
||||
|
||||
self.layers.background.node.data = &self.layer_scene_node_data.background;
|
||||
self.layers.bottom.node.data = &self.layer_scene_node_data.bottom;
|
||||
self.layers.content.node.data = &self.layer_scene_node_data.content;
|
||||
self.layers.top.node.data = &self.layer_scene_node_data.top;
|
||||
self.layers.fullscreen.node.data = &self.layer_scene_node_data.fullscreen;
|
||||
self.layers.overlay.node.data = &self.layer_scene_node_data.overlay;
|
||||
if (!wlr_output.commitState(&self.state)) {
|
||||
std.log.err("Unable to commit state to output {s}", .{wlr_output.name});
|
||||
return null;
|
||||
}
|
||||
|
||||
server.events.exec("OutputInitPost", .{self.id});
|
||||
// TODO: Allow user to define output positions
|
||||
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 self;
|
||||
self.wlr_output.data = self;
|
||||
self.tree.node.data = &self.scene_node_data;
|
||||
|
||||
self.layers.background.node.data = &self.layer_scene_node_data.background;
|
||||
self.layers.bottom.node.data = &self.layer_scene_node_data.bottom;
|
||||
self.layers.content.node.data = &self.layer_scene_node_data.content;
|
||||
self.layers.top.node.data = &self.layer_scene_node_data.top;
|
||||
self.layers.fullscreen.node.data = &self.layer_scene_node_data.fullscreen;
|
||||
self.layers.overlay.node.data = &self.layer_scene_node_data.overlay;
|
||||
|
||||
server.events.exec("OutputInitPost", .{self.id});
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Output) void {
|
||||
server.events.exec("OutputDeinitPre", .{self.id});
|
||||
server.events.exec("OutputDeinitPre", .{self.id});
|
||||
|
||||
self.frame.link.remove();
|
||||
self.request_state.link.remove();
|
||||
self.destroy.link.remove();
|
||||
self.frame.link.remove();
|
||||
self.request_state.link.remove();
|
||||
self.destroy.link.remove();
|
||||
|
||||
self.state.finish();
|
||||
self.state.finish();
|
||||
|
||||
self.wlr_output.destroy();
|
||||
self.wlr_output.destroy();
|
||||
|
||||
server.events.exec("OutputDeinitPost", .{});
|
||||
server.events.exec("OutputDeinitPost", .{});
|
||||
|
||||
gpa.destroy(self);
|
||||
gpa.destroy(self);
|
||||
}
|
||||
|
||||
pub fn setFocused(self: *Output) void {
|
||||
if(server.seat.focused_output) |prev_output| {
|
||||
prev_output.focused = false;
|
||||
}
|
||||
if (server.seat.focused_output) |prev_output| {
|
||||
prev_output.focused = false;
|
||||
}
|
||||
|
||||
server.seat.focused_output = self;
|
||||
self.focused = true;
|
||||
server.seat.focused_output = self;
|
||||
self.focused = true;
|
||||
}
|
||||
|
||||
pub fn configureLayers(self: *Output) void {
|
||||
var output_box: wlr.Box = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = undefined,
|
||||
.height = undefined,
|
||||
};
|
||||
self.wlr_output.effectiveResolution(&output_box.width, &output_box.height);
|
||||
|
||||
// Should calculate usable area here for LUA view positioning
|
||||
for ([_]zwlr.LayerShellV1.Layer{ .background, .bottom, .top, .overlay }) |layer| {
|
||||
const tree = blk: {
|
||||
const trees = [_]*wlr.SceneTree{
|
||||
self.layers.background,
|
||||
self.layers.bottom,
|
||||
self.layers.top,
|
||||
self.layers.overlay,
|
||||
};
|
||||
break :blk trees[@intCast(@intFromEnum(layer))];
|
||||
var output_box: wlr.Box = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = undefined,
|
||||
.height = undefined,
|
||||
};
|
||||
self.wlr_output.effectiveResolution(&output_box.width, &output_box.height);
|
||||
|
||||
var it = tree.children.iterator(.forward);
|
||||
while(it.next()) |node| {
|
||||
if(node.data == null) continue;
|
||||
// Should calculate usable area here for LUA view positioning
|
||||
for ([_]zwlr.LayerShellV1.Layer{ .background, .bottom, .top, .overlay }) |layer| {
|
||||
const tree = blk: {
|
||||
const trees = [_]*wlr.SceneTree{
|
||||
self.layers.background,
|
||||
self.layers.bottom,
|
||||
self.layers.top,
|
||||
self.layers.overlay,
|
||||
};
|
||||
break :blk trees[@intCast(@intFromEnum(layer))];
|
||||
};
|
||||
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
|
||||
switch (scene_node_data.*) {
|
||||
.layer_surface => {
|
||||
_ = scene_node_data.layer_surface.wlr_layer_surface.configured(
|
||||
@intCast(output_box.width),
|
||||
@intCast(output_box.height)
|
||||
);
|
||||
},
|
||||
else => {
|
||||
std.log.err("Something other than a layer surface found in layer surface scene trees", .{});
|
||||
unreachable;
|
||||
var it = tree.children.iterator(.forward);
|
||||
while (it.next()) |node| {
|
||||
if (node.data == null) continue;
|
||||
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
|
||||
switch (scene_node_data.*) {
|
||||
.layer_surface => {
|
||||
_ = scene_node_data.layer_surface.wlr_layer_surface.configured(@intCast(output_box.width), @intCast(output_box.height));
|
||||
},
|
||||
else => {
|
||||
std.log.err("Something other than a layer surface found in layer surface scene trees", .{});
|
||||
unreachable;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SurfaceAtResult = struct {
|
||||
|
|
@ -200,165 +199,152 @@ const SurfaceAtResult = struct {
|
|||
};
|
||||
|
||||
pub fn surfaceAt(self: *Output, lx: f64, ly: f64) ?SurfaceAtResult {
|
||||
var sx: f64 = undefined;
|
||||
var sy: f64 = undefined;
|
||||
var sx: f64 = undefined;
|
||||
var sy: f64 = undefined;
|
||||
|
||||
const layers = [_]*wlr.SceneTree{
|
||||
self.layers.top,
|
||||
self.layers.overlay,
|
||||
self.layers.fullscreen,
|
||||
self.layers.content,
|
||||
self.layers.bottom,
|
||||
self.layers.background
|
||||
};
|
||||
const layers = [_]*wlr.SceneTree{ self.layers.top, self.layers.overlay, self.layers.fullscreen, self.layers.content, self.layers.bottom, self.layers.background };
|
||||
|
||||
for(layers) |layer| {
|
||||
const node = layer.node.at(lx, ly, &sx, &sy);
|
||||
if(node == null) continue;
|
||||
for (layers) |layer| {
|
||||
const node = layer.node.at(lx, ly, &sx, &sy);
|
||||
if (node == null) continue;
|
||||
|
||||
const surface: ?*wlr.Surface = blk: {
|
||||
if (node.?.type == .buffer) {
|
||||
const scene_buffer = wlr.SceneBuffer.fromNode(node.?);
|
||||
if (wlr.SceneSurface.tryFromBuffer(scene_buffer)) |scene_surface| {
|
||||
break :blk scene_surface.surface;
|
||||
}
|
||||
}
|
||||
break :blk null;
|
||||
};
|
||||
if(surface == null) continue;
|
||||
|
||||
const scene_node_data: *SceneNodeData = blk: {
|
||||
var n = node.?;
|
||||
while (true) {
|
||||
if (@as(?*SceneNodeData, @ptrCast(@alignCast(n.data)))) |snd| {
|
||||
break :blk snd;
|
||||
}
|
||||
if (n.parent) |parent_tree| {
|
||||
n = &parent_tree.node;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
switch (scene_node_data.*) {
|
||||
.layer_surface, .view => {
|
||||
return SurfaceAtResult{
|
||||
.scene_node_data = scene_node_data,
|
||||
.surface = surface.?,
|
||||
.sx = sx,
|
||||
.sy = sy,
|
||||
const surface: ?*wlr.Surface = blk: {
|
||||
if (node.?.type == .buffer) {
|
||||
const scene_buffer = wlr.SceneBuffer.fromNode(node.?);
|
||||
if (wlr.SceneSurface.tryFromBuffer(scene_buffer)) |scene_surface| {
|
||||
break :blk scene_surface.surface;
|
||||
}
|
||||
}
|
||||
break :blk null;
|
||||
};
|
||||
},
|
||||
else => continue
|
||||
}
|
||||
}
|
||||
if (surface == null) continue;
|
||||
|
||||
return null;
|
||||
const scene_node_data: *SceneNodeData = blk: {
|
||||
var n = node.?;
|
||||
while (true) {
|
||||
if (@as(?*SceneNodeData, @ptrCast(@alignCast(n.data)))) |snd| {
|
||||
break :blk snd;
|
||||
}
|
||||
if (n.parent) |parent_tree| {
|
||||
n = &parent_tree.node;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
switch (scene_node_data.*) {
|
||||
.layer_surface, .view => {
|
||||
return SurfaceAtResult{
|
||||
.scene_node_data = scene_node_data,
|
||||
.surface = surface.?,
|
||||
.sx = sx,
|
||||
.sy = sy,
|
||||
};
|
||||
},
|
||||
else => continue,
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn getFullscreenedView(self: *Output) ?*View {
|
||||
if(self.layers.fullscreen.children.length() != 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var it = self.layers.fullscreen.children.iterator(.forward);
|
||||
if(it.next().?.data) |data| {
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(data));
|
||||
if(scene_node_data.* == .view) {
|
||||
return scene_node_data.view;
|
||||
if (self.layers.fullscreen.children.length() != 1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
var it = self.layers.fullscreen.children.iterator(.forward);
|
||||
if (it.next().?.data) |data| {
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(data));
|
||||
if (scene_node_data.* == .view) {
|
||||
return scene_node_data.view;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// --------- WlrOutput Event Handlers ---------
|
||||
fn handleRequestState(
|
||||
listener: *wl.Listener(*wlr.Output.event.RequestState),
|
||||
event: *wlr.Output.event.RequestState,
|
||||
listener: *wl.Listener(*wlr.Output.event.RequestState),
|
||||
event: *wlr.Output.event.RequestState,
|
||||
) void {
|
||||
const output: *Output = @fieldParentPtr("request_state", listener);
|
||||
const output: *Output = @fieldParentPtr("request_state", listener);
|
||||
|
||||
if (!output.wlr_output.commitState(event.state)) {
|
||||
std.log.warn("failed to set output state {}", .{event.state});
|
||||
}
|
||||
if (!output.wlr_output.commitState(event.state)) {
|
||||
std.log.warn("failed to set output state {}", .{event.state});
|
||||
}
|
||||
|
||||
server.events.exec("OutputStateChange", .{});
|
||||
server.events.exec("OutputStateChange", .{});
|
||||
}
|
||||
|
||||
fn handleFrame(
|
||||
_: *wl.Listener(*wlr.Output),
|
||||
wlr_output: *wlr.Output
|
||||
) void {
|
||||
const scene_output = server.root.scene.getSceneOutput(wlr_output);
|
||||
fn handleFrame(_: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void {
|
||||
const scene_output = server.root.scene.getSceneOutput(wlr_output);
|
||||
|
||||
if(scene_output == null) {
|
||||
std.log.err("Unable to get scene output to render", .{});
|
||||
return;
|
||||
}
|
||||
if (scene_output == null) {
|
||||
std.log.err("Unable to get scene output to render", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
// std.log.info("Rendering commited scene output\n", .{});
|
||||
_ = scene_output.?.commit(null);
|
||||
// std.log.info("Rendering commited scene output\n", .{});
|
||||
_ = scene_output.?.commit(null);
|
||||
|
||||
var now = posix.clock_gettime(posix.CLOCK.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
|
||||
scene_output.?.sendFrameDone(&now);
|
||||
var now = posix.clock_gettime(posix.CLOCK.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
|
||||
scene_output.?.sendFrameDone(&now);
|
||||
}
|
||||
|
||||
fn handleDestroy(
|
||||
listener: *wl.Listener(*wlr.Output),
|
||||
_: *wlr.Output
|
||||
) void {
|
||||
std.log.debug("Handling destroy", .{});
|
||||
const output: *Output = @fieldParentPtr("destroy", listener);
|
||||
fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
||||
std.log.debug("Handling destroy", .{});
|
||||
const output: *Output = @fieldParentPtr("destroy", listener);
|
||||
|
||||
std.log.debug("removing output: {s}", .{output.wlr_output.name});
|
||||
std.log.debug("removing output: {s}", .{output.wlr_output.name});
|
||||
|
||||
output.frame.link.remove();
|
||||
output.request_state.link.remove();
|
||||
output.destroy.link.remove();
|
||||
output.frame.link.remove();
|
||||
output.request_state.link.remove();
|
||||
output.destroy.link.remove();
|
||||
|
||||
server.root.output_layout.remove(output.wlr_output);
|
||||
server.root.output_layout.remove(output.wlr_output);
|
||||
|
||||
gpa.destroy(output);
|
||||
gpa.destroy(output);
|
||||
}
|
||||
|
||||
pub fn arrangeLayers(self: *Output) void {
|
||||
var full_box: wlr.Box = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = undefined,
|
||||
.height = undefined,
|
||||
};
|
||||
self.wlr_output.effectiveResolution(&full_box.width, &full_box.height);
|
||||
var full_box: wlr.Box = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = undefined,
|
||||
.height = undefined,
|
||||
};
|
||||
self.wlr_output.effectiveResolution(&full_box.width, &full_box.height);
|
||||
|
||||
inline for (@typeInfo(zwlr.LayerShellV1.Layer).@"enum".fields) |comptime_layer| {
|
||||
const layer: *wlr.SceneTree = @field(self.layers, comptime_layer.name);
|
||||
var it = layer.children.safeIterator(.forward);
|
||||
inline for (@typeInfo(zwlr.LayerShellV1.Layer).@"enum".fields) |comptime_layer| {
|
||||
const layer: *wlr.SceneTree = @field(self.layers, comptime_layer.name);
|
||||
var it = layer.children.safeIterator(.forward);
|
||||
|
||||
while (it.next()) |node| {
|
||||
if(node.data == null) continue;
|
||||
while (it.next()) |node| {
|
||||
if (node.data == null) continue;
|
||||
|
||||
// if (@as(?*SceneNodeData, @alignCast(@ptrCast(node.data)))) |node_data| {
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
|
||||
// if (@as(?*SceneNodeData, @alignCast(@ptrCast(node.data)))) |node_data| {
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
|
||||
|
||||
const layer_surface: *LayerSurface = switch(scene_node_data.*) {
|
||||
.layer_surface => @fieldParentPtr("scene_node_data", scene_node_data),
|
||||
else => continue
|
||||
};
|
||||
const layer_surface: *LayerSurface = switch (scene_node_data.*) {
|
||||
.layer_surface => @fieldParentPtr("scene_node_data", scene_node_data),
|
||||
else => continue,
|
||||
};
|
||||
|
||||
if (!layer_surface.wlr_layer_surface.initialized) continue;
|
||||
if (!layer_surface.wlr_layer_surface.initialized) continue;
|
||||
|
||||
// TEST: river seems to try and prevent clients from taking an
|
||||
// exclusive size greater than half the screen by killing them. Do we
|
||||
// need to? Clients can do quite a bit of nasty stuff and taking
|
||||
// exclusive focus isn't even that bad.
|
||||
// TEST: river seems to try and prevent clients from taking an
|
||||
// exclusive size greater than half the screen by killing them. Do we
|
||||
// need to? Clients can do quite a bit of nasty stuff and taking
|
||||
// exclusive focus isn't even that bad.
|
||||
|
||||
layer_surface.scene_layer_surface.configure(&full_box, &full_box);
|
||||
layer_surface.scene_layer_surface.configure(&full_box, &full_box);
|
||||
|
||||
// TEST: are these calls useless?
|
||||
// const x = layer_surface.scene_layer_surface.tree.node.x;
|
||||
// const y = layer_surface.scene_layer_surface.tree.node.y;
|
||||
// layer_surface.scene_layer_surface.tree.node.setPosition(x, y);
|
||||
// TEST: are these calls useless?
|
||||
// const x = layer_surface.scene_layer_surface.tree.node.x;
|
||||
// const y = layer_surface.scene_layer_surface.tree.node.y;
|
||||
// layer_surface.scene_layer_surface.tree.node.setPosition(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,75 +23,75 @@ new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNe
|
|||
reposition: wl.Listener(void) = wl.Listener(void).init(handleReposition),
|
||||
|
||||
pub fn init(
|
||||
xdg_popup: *wlr.XdgPopup,
|
||||
parent: *wlr.SceneTree,
|
||||
xdg_popup: *wlr.XdgPopup,
|
||||
parent: *wlr.SceneTree,
|
||||
) *Popup {
|
||||
errdefer Utils.oomPanic();
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
const self = try gpa.create(Popup);
|
||||
errdefer gpa.destroy(self);
|
||||
const self = try gpa.create(Popup);
|
||||
errdefer gpa.destroy(self);
|
||||
|
||||
self.* = .{
|
||||
.id = @intFromPtr(xdg_popup),
|
||||
.xdg_popup = xdg_popup,
|
||||
.tree = try parent.createSceneXdgSurface(xdg_popup.base),
|
||||
};
|
||||
self.* = .{
|
||||
.id = @intFromPtr(xdg_popup),
|
||||
.xdg_popup = xdg_popup,
|
||||
.tree = try parent.createSceneXdgSurface(xdg_popup.base),
|
||||
};
|
||||
|
||||
xdg_popup.events.destroy.add(&self.destroy);
|
||||
xdg_popup.base.surface.events.commit.add(&self.commit);
|
||||
xdg_popup.base.events.new_popup.add(&self.new_popup);
|
||||
xdg_popup.events.reposition.add(&self.reposition);
|
||||
xdg_popup.events.destroy.add(&self.destroy);
|
||||
xdg_popup.base.surface.events.commit.add(&self.commit);
|
||||
xdg_popup.base.events.new_popup.add(&self.new_popup);
|
||||
xdg_popup.events.reposition.add(&self.reposition);
|
||||
|
||||
return self;
|
||||
return self;
|
||||
}
|
||||
|
||||
fn handleDestroy(listener: *wl.Listener(void)) void {
|
||||
const popup: *Popup = @fieldParentPtr("destroy", listener);
|
||||
const popup: *Popup = @fieldParentPtr("destroy", listener);
|
||||
|
||||
popup.destroy.link.remove();
|
||||
popup.commit.link.remove();
|
||||
popup.new_popup.link.remove();
|
||||
popup.reposition.link.remove();
|
||||
popup.destroy.link.remove();
|
||||
popup.commit.link.remove();
|
||||
popup.new_popup.link.remove();
|
||||
popup.reposition.link.remove();
|
||||
|
||||
gpa.destroy(popup);
|
||||
gpa.destroy(popup);
|
||||
}
|
||||
|
||||
fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||
const popup: *Popup = @fieldParentPtr("commit", listener);
|
||||
if (popup.xdg_popup.base.initial_commit) {
|
||||
handleReposition(&popup.reposition);
|
||||
}
|
||||
const popup: *Popup = @fieldParentPtr("commit", listener);
|
||||
if (popup.xdg_popup.base.initial_commit) {
|
||||
handleReposition(&popup.reposition);
|
||||
}
|
||||
}
|
||||
|
||||
fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), xdg_popup: *wlr.XdgPopup) void {
|
||||
const popup: *Popup = @fieldParentPtr("new_popup", listener);
|
||||
const popup: *Popup = @fieldParentPtr("new_popup", listener);
|
||||
|
||||
_ = Popup.init(xdg_popup, popup.tree);
|
||||
_ = Popup.init(xdg_popup, popup.tree);
|
||||
}
|
||||
|
||||
fn handleReposition(listener: *wl.Listener(void)) void {
|
||||
const popup: *Popup = @fieldParentPtr("reposition", listener);
|
||||
const popup: *Popup = @fieldParentPtr("reposition", listener);
|
||||
|
||||
var box: wlr.Box = undefined;
|
||||
var box: wlr.Box = undefined;
|
||||
|
||||
// TODO: figure this out to prevent popups from rendering outside of the
|
||||
// current monitor
|
||||
//
|
||||
// if (SceneNodeData.getFromNode(&popup.tree.node)) |node| {
|
||||
// const output = switch (node.data) {
|
||||
// .view => |view| view.output orelse return,
|
||||
// .layer_surface => |layer_surface| layer_surface.output,
|
||||
// };
|
||||
//
|
||||
// server.root.output_layout.getBox(output.wlr_output, &box);
|
||||
// }
|
||||
// TODO: figure this out to prevent popups from rendering outside of the
|
||||
// current monitor
|
||||
//
|
||||
// if (SceneNodeData.getFromNode(&popup.tree.node)) |node| {
|
||||
// const output = switch (node.data) {
|
||||
// .view => |view| view.output orelse return,
|
||||
// .layer_surface => |layer_surface| layer_surface.output,
|
||||
// };
|
||||
//
|
||||
// server.root.output_layout.getBox(output.wlr_output, &box);
|
||||
// }
|
||||
|
||||
var root_lx: c_int = undefined;
|
||||
var root_ly: c_int = undefined;
|
||||
_ = popup.tree.node.coords(&root_lx, &root_ly);
|
||||
var root_lx: c_int = undefined;
|
||||
var root_ly: c_int = undefined;
|
||||
_ = popup.tree.node.coords(&root_lx, &root_ly);
|
||||
|
||||
box.x -= root_lx;
|
||||
box.y -= root_ly;
|
||||
box.x -= root_lx;
|
||||
box.y -= root_ly;
|
||||
|
||||
popup.xdg_popup.unconstrainFromBox(&box);
|
||||
popup.xdg_popup.unconstrainFromBox(&box);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,90 +17,92 @@ remote_lua_v1: *mez.RemoteLuaV1,
|
|||
L: *zlua.Lua,
|
||||
|
||||
pub fn sendNewLogEntry(str: [*:0]const u8) void {
|
||||
var node = server.remote_lua_clients.first;
|
||||
while (node) |n| {
|
||||
const data: ?*RemoteLua = @fieldParentPtr("node", n);
|
||||
if (data) |d| d.remote_lua_v1.sendNewLogEntry(str);
|
||||
node = n.next;
|
||||
}
|
||||
var node = server.remote_lua_clients.first;
|
||||
while (node) |n| {
|
||||
const data: ?*RemoteLua = @fieldParentPtr("node", n);
|
||||
if (data) |d| d.remote_lua_v1.sendNewLogEntry(str);
|
||||
node = n.next;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(client: *wl.Client, version: u32, id: u32) !void {
|
||||
const remote_lua_v1 = try mez.RemoteLuaV1.create(client, version, id);
|
||||
const remote_lua_v1 = try mez.RemoteLuaV1.create(client, version, id);
|
||||
|
||||
const node = try gpa.create(RemoteLua);
|
||||
errdefer gpa.destroy(node);
|
||||
node.* = .{
|
||||
.remote_lua_v1 = remote_lua_v1,
|
||||
.node = .{},
|
||||
.L = try zlua.Lua.init(gpa),
|
||||
};
|
||||
errdefer node.L.deinit();
|
||||
node.L.openLibs();
|
||||
Lua.openLibs(node.L);
|
||||
Lua.loadRuntimeDir(node.L) catch |err| if (err == error.LuaRuntime) {
|
||||
std.log.warn("{s}", .{try node.L.toString(-1)});
|
||||
};
|
||||
// TODO: replace stdout and stderr with buffers we can send to the clients
|
||||
const node = try gpa.create(RemoteLua);
|
||||
errdefer gpa.destroy(node);
|
||||
node.* = .{
|
||||
.remote_lua_v1 = remote_lua_v1,
|
||||
.node = .{},
|
||||
.L = try zlua.Lua.init(gpa),
|
||||
};
|
||||
errdefer node.L.deinit();
|
||||
node.L.openLibs();
|
||||
Lua.openLibs(node.L);
|
||||
Lua.loadRuntimeDir(node.L) catch |err| if (err == error.LuaRuntime) {
|
||||
std.log.warn("{s}", .{try node.L.toString(-1)});
|
||||
};
|
||||
// TODO: replace stdout and stderr with buffers we can send to the clients
|
||||
|
||||
server.remote_lua_clients.prepend(&node.node);
|
||||
server.remote_lua_clients.prepend(&node.node);
|
||||
|
||||
remote_lua_v1.setHandler(*RemoteLua, handleRequest, handleDestroy, node);
|
||||
remote_lua_v1.setHandler(*RemoteLua, handleRequest, handleDestroy, node);
|
||||
}
|
||||
|
||||
fn handleRequest(
|
||||
remote_lua_v1: *mez.RemoteLuaV1,
|
||||
request: mez.RemoteLuaV1.Request,
|
||||
remote: *RemoteLua,
|
||||
remote_lua_v1: *mez.RemoteLuaV1,
|
||||
request: mez.RemoteLuaV1.Request,
|
||||
remote: *RemoteLua,
|
||||
) void {
|
||||
const L = remote.L;
|
||||
switch (request) {
|
||||
.destroy => remote_lua_v1.destroy(),
|
||||
.push_lua => |req| {
|
||||
const chunk: [:0]const u8 = std.mem.sliceTo(req.lua_chunk, 0);
|
||||
const L = remote.L;
|
||||
switch (request) {
|
||||
.destroy => remote_lua_v1.destroy(),
|
||||
.push_lua => |req| {
|
||||
const chunk: [:0]const u8 = std.mem.sliceTo(req.lua_chunk, 0);
|
||||
|
||||
const str = std.mem.concatWithSentinel(gpa, u8, &[_][]const u8{
|
||||
"return ",
|
||||
chunk,
|
||||
";",
|
||||
}, 0) catch return catchLuaFail(remote);
|
||||
defer gpa.free(str);
|
||||
const str = std.mem.concatWithSentinel(gpa, u8, &[_][]const u8{
|
||||
"return ",
|
||||
chunk,
|
||||
";",
|
||||
}, 0) catch return catchLuaFail(remote);
|
||||
defer gpa.free(str);
|
||||
|
||||
zlua.Lua.loadBuffer(L, str, "=repl") catch {
|
||||
L.pop(L.getTop());
|
||||
L.loadString(chunk) catch {
|
||||
catchLuaFail(remote);
|
||||
L.pop(-1);
|
||||
};
|
||||
return;
|
||||
};
|
||||
zlua.Lua.loadBuffer(L, str, "=repl") catch {
|
||||
L.pop(L.getTop());
|
||||
L.loadString(chunk) catch {
|
||||
catchLuaFail(remote);
|
||||
L.pop(-1);
|
||||
};
|
||||
return;
|
||||
};
|
||||
|
||||
L.protectedCall(.{ .results = zlua.mult_return, }) catch {
|
||||
catchLuaFail(remote);
|
||||
L.pop(1);
|
||||
};
|
||||
L.protectedCall(.{
|
||||
.results = zlua.mult_return,
|
||||
}) catch {
|
||||
catchLuaFail(remote);
|
||||
L.pop(1);
|
||||
};
|
||||
|
||||
var i: i32 = 1;
|
||||
const nresults = L.getTop();
|
||||
while (i <= nresults) : (i += 1) {
|
||||
sendNewLogEntry(LuaUtils.toStringEx(L));
|
||||
L.pop(-1);
|
||||
}
|
||||
},
|
||||
}
|
||||
var i: i32 = 1;
|
||||
const nresults = L.getTop();
|
||||
while (i <= nresults) : (i += 1) {
|
||||
sendNewLogEntry(LuaUtils.toStringEx(L));
|
||||
L.pop(-1);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn handleDestroy(_: *mez.RemoteLuaV1, remote_lua: *RemoteLua) void {
|
||||
if (remote_lua.node.prev) |p| {
|
||||
if (remote_lua.node.next) |n| n.prev.? = p;
|
||||
p.next = remote_lua.node.next;
|
||||
} else server.remote_lua_clients.first = remote_lua.node.next;
|
||||
if (remote_lua.node.prev) |p| {
|
||||
if (remote_lua.node.next) |n| n.prev.? = p;
|
||||
p.next = remote_lua.node.next;
|
||||
} else server.remote_lua_clients.first = remote_lua.node.next;
|
||||
|
||||
remote_lua.L.deinit();
|
||||
gpa.destroy(remote_lua);
|
||||
remote_lua.L.deinit();
|
||||
gpa.destroy(remote_lua);
|
||||
}
|
||||
|
||||
fn catchLuaFail(remote: *RemoteLua) void {
|
||||
const err: [:0]const u8 = LuaUtils.toStringEx(remote.L);
|
||||
sendNewLogEntry(std.mem.sliceTo(err, 0));
|
||||
const err: [:0]const u8 = LuaUtils.toStringEx(remote.L);
|
||||
sendNewLogEntry(std.mem.sliceTo(err, 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,37 +13,37 @@ const server = &@import("main.zig").server;
|
|||
global: *wl.Global,
|
||||
|
||||
pub fn init() !?*RemoteLuaManager {
|
||||
const self = try gpa.create(RemoteLuaManager);
|
||||
const self = try gpa.create(RemoteLuaManager);
|
||||
|
||||
self.global = try wl.Global.create(server.wl_server, mez.RemoteLuaManagerV1, 1, ?*anyopaque, null, bind);
|
||||
self.global = try wl.Global.create(server.wl_server, mez.RemoteLuaManagerV1, 1, ?*anyopaque, null, bind);
|
||||
|
||||
return self;
|
||||
return self;
|
||||
}
|
||||
|
||||
fn bind(client: *wl.Client, _: ?*anyopaque, version: u32, id: u32) void {
|
||||
const remote_lua_manager_v1 = mez.RemoteLuaManagerV1.create(client, version, id) catch {
|
||||
client.postNoMemory();
|
||||
Utils.oomPanic();
|
||||
};
|
||||
remote_lua_manager_v1.setHandler(?*anyopaque, handleRequest, null, null);
|
||||
const remote_lua_manager_v1 = mez.RemoteLuaManagerV1.create(client, version, id) catch {
|
||||
client.postNoMemory();
|
||||
Utils.oomPanic();
|
||||
};
|
||||
remote_lua_manager_v1.setHandler(?*anyopaque, handleRequest, null, null);
|
||||
}
|
||||
|
||||
fn handleRequest(
|
||||
remote_lua_manager_v1: *mez.RemoteLuaManagerV1,
|
||||
request: mez.RemoteLuaManagerV1.Request,
|
||||
_: ?*anyopaque,
|
||||
remote_lua_manager_v1: *mez.RemoteLuaManagerV1,
|
||||
request: mez.RemoteLuaManagerV1.Request,
|
||||
_: ?*anyopaque,
|
||||
) void {
|
||||
switch (request) {
|
||||
.destroy => remote_lua_manager_v1.destroy(),
|
||||
.get_remote => |req| {
|
||||
RemoteLua.create(
|
||||
remote_lua_manager_v1.getClient(),
|
||||
remote_lua_manager_v1.getVersion(),
|
||||
req.id,
|
||||
) catch {
|
||||
remote_lua_manager_v1.getClient().postNoMemory();
|
||||
Utils.oomPanic();
|
||||
};
|
||||
},
|
||||
}
|
||||
switch (request) {
|
||||
.destroy => remote_lua_manager_v1.destroy(),
|
||||
.get_remote => |req| {
|
||||
RemoteLua.create(
|
||||
remote_lua_manager_v1.getClient(),
|
||||
remote_lua_manager_v1.getVersion(),
|
||||
req.id,
|
||||
) catch {
|
||||
remote_lua_manager_v1.getClient().postNoMemory();
|
||||
Utils.oomPanic();
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
127
src/Root.zig
127
src/Root.zig
|
|
@ -1,5 +1,4 @@
|
|||
/// The root of Mezzaluna is, you guessed it, the root of many of the systems mez needs:
|
||||
|
||||
const Root = @This();
|
||||
|
||||
const std = @import("std");
|
||||
|
|
@ -26,92 +25,92 @@ scene_output_layout: *wlr.SceneOutputLayout,
|
|||
output_layout: *wlr.OutputLayout,
|
||||
|
||||
pub fn init(self: *Root) void {
|
||||
std.log.info("Creating root of mezzaluna\n", .{});
|
||||
std.log.info("Creating root of mezzaluna\n", .{});
|
||||
|
||||
errdefer Utils.oomPanic();
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
const output_layout = try wlr.OutputLayout.create(server.wl_server);
|
||||
errdefer output_layout.destroy();
|
||||
const output_layout = try wlr.OutputLayout.create(server.wl_server);
|
||||
errdefer output_layout.destroy();
|
||||
|
||||
const scene = try wlr.Scene.create();
|
||||
errdefer scene.tree.node.destroy();
|
||||
const scene = try wlr.Scene.create();
|
||||
errdefer scene.tree.node.destroy();
|
||||
|
||||
self.* = .{
|
||||
.scene = scene,
|
||||
.scene_node_data = .{ .root = self },
|
||||
.output_layout = output_layout,
|
||||
.xdg_toplevel_decoration_manager = try wlr.XdgDecorationManagerV1.create(server.wl_server),
|
||||
.scene_output_layout = try scene.attachOutputLayout(output_layout),
|
||||
};
|
||||
self.* = .{
|
||||
.scene = scene,
|
||||
.scene_node_data = .{ .root = self },
|
||||
.output_layout = output_layout,
|
||||
.xdg_toplevel_decoration_manager = try wlr.XdgDecorationManagerV1.create(server.wl_server),
|
||||
.scene_output_layout = try scene.attachOutputLayout(output_layout),
|
||||
};
|
||||
|
||||
self.scene.tree.node.data = &self.scene_node_data;
|
||||
self.scene.tree.node.data = &self.scene_node_data;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Root) void {
|
||||
var it = self.scene.tree.children.iterator(.forward);
|
||||
var it = self.scene.tree.children.iterator(.forward);
|
||||
|
||||
while(it.next()) |node| {
|
||||
if(node.data == null) continue;
|
||||
while (it.next()) |node| {
|
||||
if (node.data == null) continue;
|
||||
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
|
||||
switch(scene_node_data.*) {
|
||||
.output => {
|
||||
scene_node_data.output.deinit();
|
||||
},
|
||||
else => {
|
||||
std.log.debug("The root has a child that is not an output", .{});
|
||||
unreachable;
|
||||
}
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
|
||||
switch (scene_node_data.*) {
|
||||
.output => {
|
||||
scene_node_data.output.deinit();
|
||||
},
|
||||
else => {
|
||||
std.log.debug("The root has a child that is not an output", .{});
|
||||
unreachable;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.output_layout.destroy();
|
||||
self.scene.tree.node.destroy();
|
||||
self.output_layout.destroy();
|
||||
self.scene.tree.node.destroy();
|
||||
}
|
||||
|
||||
// Search output_layout's ouputs, and each outputs views
|
||||
pub fn viewById(self: *Root, id: u64) ?*View {
|
||||
var output_it = self.output_layout.outputs.iterator(.forward);
|
||||
var output_it = self.output_layout.outputs.iterator(.forward);
|
||||
|
||||
while(output_it.next()) |o| {
|
||||
if(o.output.data == null) {
|
||||
std.log.err("Wlr_output arbitrary data not assigned", .{});
|
||||
unreachable;
|
||||
while (output_it.next()) |o| {
|
||||
if (o.output.data == null) {
|
||||
std.log.err("Wlr_output arbitrary data not assigned", .{});
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const output: *Output = @ptrCast(@alignCast(o.output.data.?));
|
||||
var node_it = output.layers.content.children.iterator(.forward);
|
||||
|
||||
while (node_it.next()) |node| {
|
||||
if (node.data == null) continue;
|
||||
|
||||
const view_snd: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
|
||||
|
||||
// TODO: Should we assert that we want only views to be here
|
||||
// -- Basically should we use switch statements for snd interactions
|
||||
// -- Or if statements, for simplicity
|
||||
if (view_snd.* == .view and view_snd.view.id == id) {
|
||||
return view_snd.view;
|
||||
}
|
||||
}
|
||||
|
||||
if (output.fullscreen) |fullscreen| {
|
||||
if (fullscreen.id == id) return fullscreen;
|
||||
}
|
||||
}
|
||||
|
||||
const output: *Output = @ptrCast(@alignCast(o.output.data.?));
|
||||
var node_it = output.layers.content.children.iterator(.forward);
|
||||
|
||||
while(node_it.next()) |node| {
|
||||
if(node.data == null) continue;
|
||||
|
||||
const view_snd: *SceneNodeData = @ptrCast(@alignCast(node.data.?));
|
||||
|
||||
// TODO: Should we assert that we want only views to be here
|
||||
// -- Basically should we use switch statements for snd interactions
|
||||
// -- Or if statements, for simplicity
|
||||
if(view_snd.* == .view and view_snd.view.id == id) {
|
||||
return view_snd.view;
|
||||
}
|
||||
}
|
||||
|
||||
if(output.fullscreen) |fullscreen| {
|
||||
if(fullscreen.id == id) return fullscreen;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn outputById(self: *Root, id: u64) ?*Output {
|
||||
var it = self.scene.outputs.iterator(.forward);
|
||||
var it = self.scene.outputs.iterator(.forward);
|
||||
|
||||
while(it.next()) |scene_output| {
|
||||
if(scene_output.output.data == null) continue;
|
||||
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;
|
||||
}
|
||||
const output: *Output = @as(*Output, @ptrCast(@alignCast(scene_output.output.data.?)));
|
||||
if (output.id == id) return output;
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,4 @@ const LayerSurface = @import("LayerSurface.zig");
|
|||
const Output = @import("Output.zig");
|
||||
const Root = @import("Root.zig");
|
||||
|
||||
pub const SceneNodeData = union(enum) {
|
||||
view: *View,
|
||||
layer_surface: *LayerSurface,
|
||||
output: *Output,
|
||||
output_layer: *wlr.SceneTree,
|
||||
root: *Root
|
||||
};
|
||||
pub const SceneNodeData = union(enum) { view: *View, layer_surface: *LayerSurface, output: *Output, output_layer: *wlr.SceneTree, root: *Root };
|
||||
|
|
|
|||
221
src/Seat.zig
221
src/Seat.zig
|
|
@ -6,24 +6,24 @@ const wl = @import("wayland").server.wl;
|
|||
const xkb = @import("xkbcommon");
|
||||
|
||||
const KeyboardGroup = @import("KeyboardGroup.zig");
|
||||
const Utils = @import("Utils.zig");
|
||||
const Utils = @import("Utils.zig");
|
||||
const Popup = @import("Popup.zig");
|
||||
const View = @import("View.zig");
|
||||
const View = @import("View.zig");
|
||||
const LayerSurface = @import("LayerSurface.zig");
|
||||
const Output = @import("Output.zig");
|
||||
|
||||
const server = &@import("main.zig").server;
|
||||
|
||||
pub const FocusData = union(enum) {
|
||||
view: *View,
|
||||
layer_surface: *LayerSurface,
|
||||
view: *View,
|
||||
layer_surface: *LayerSurface,
|
||||
|
||||
pub fn getSurface(self: FocusData) *wlr.Surface {
|
||||
return switch (self) {
|
||||
.view => |*v| v.*.xdg_toplevel.base.surface,
|
||||
.layer_surface => |*ls| ls.*.wlr_layer_surface.surface,
|
||||
};
|
||||
}
|
||||
pub fn getSurface(self: FocusData) *wlr.Surface {
|
||||
return switch (self) {
|
||||
.view => |*v| v.*.xdg_toplevel.base.surface,
|
||||
.layer_surface => |*ls| ls.*.wlr_layer_surface.surface,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
wlr_seat: *wlr.Seat,
|
||||
|
|
@ -40,144 +40,139 @@ request_set_primary_selection: wl.Listener(*wlr.Seat.event.RequestSetPrimarySele
|
|||
// request_start_drage
|
||||
|
||||
pub fn init(self: *Seat) void {
|
||||
errdefer Utils.oomPanic();
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
const xkb_context = xkb.Context.new(.no_flags) orelse {
|
||||
std.log.err("Unable to create a xkb context, exiting", .{});
|
||||
std.process.exit(7);
|
||||
};
|
||||
defer xkb_context.unref();
|
||||
const xkb_context = xkb.Context.new(.no_flags) orelse {
|
||||
std.log.err("Unable to create a xkb context, exiting", .{});
|
||||
std.process.exit(7);
|
||||
};
|
||||
defer xkb_context.unref();
|
||||
|
||||
const keymap = xkb.Keymap.newFromNames(xkb_context, null, .no_flags) orelse {
|
||||
std.log.err("Unable to create a xkb keymap, exiting", .{});
|
||||
std.process.exit(8);
|
||||
};
|
||||
defer keymap.unref();
|
||||
const keymap = xkb.Keymap.newFromNames(xkb_context, null, .no_flags) orelse {
|
||||
std.log.err("Unable to create a xkb keymap, exiting", .{});
|
||||
std.process.exit(8);
|
||||
};
|
||||
defer keymap.unref();
|
||||
|
||||
self.* = .{
|
||||
.wlr_seat = try wlr.Seat.create(server.wl_server, "default"),
|
||||
.focused_surface = null,
|
||||
.focused_output = null,
|
||||
.keyboard_group = .init(),
|
||||
.keymap = keymap.ref(),
|
||||
};
|
||||
errdefer {
|
||||
self.keyboard_group.deinit();
|
||||
self.wlr_seat.destroy();
|
||||
}
|
||||
self.* = .{
|
||||
.wlr_seat = try wlr.Seat.create(server.wl_server, "default"),
|
||||
.focused_surface = null,
|
||||
.focused_output = null,
|
||||
.keyboard_group = .init(),
|
||||
.keymap = keymap.ref(),
|
||||
};
|
||||
errdefer {
|
||||
self.keyboard_group.deinit();
|
||||
self.wlr_seat.destroy();
|
||||
}
|
||||
|
||||
_ = self.keyboard_group.wlr_group.keyboard.setKeymap(self.keymap);
|
||||
self.wlr_seat.setKeyboard(&self.keyboard_group.wlr_group.keyboard);
|
||||
_ = self.keyboard_group.wlr_group.keyboard.setKeymap(self.keymap);
|
||||
self.wlr_seat.setKeyboard(&self.keyboard_group.wlr_group.keyboard);
|
||||
|
||||
self.wlr_seat.events.request_set_cursor.add(&self.request_set_cursor);
|
||||
self.wlr_seat.events.request_set_selection.add(&self.request_set_selection);
|
||||
self.wlr_seat.events.request_set_primary_selection.add(&self.request_set_primary_selection);
|
||||
self.wlr_seat.events.request_set_cursor.add(&self.request_set_cursor);
|
||||
self.wlr_seat.events.request_set_selection.add(&self.request_set_selection);
|
||||
self.wlr_seat.events.request_set_primary_selection.add(&self.request_set_primary_selection);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Seat) void {
|
||||
self.request_set_cursor.link.remove();
|
||||
self.request_set_selection.link.remove();
|
||||
self.request_set_primary_selection.link.remove();
|
||||
self.request_set_cursor.link.remove();
|
||||
self.request_set_selection.link.remove();
|
||||
self.request_set_primary_selection.link.remove();
|
||||
|
||||
self.keyboard_group.deinit();
|
||||
self.wlr_seat.destroy();
|
||||
self.keyboard_group.deinit();
|
||||
self.wlr_seat.destroy();
|
||||
}
|
||||
|
||||
pub fn focusSurface(self: *Seat, to_focus: ?FocusData) void {
|
||||
const surface: ?*wlr.Surface = blk: {
|
||||
if (to_focus != null) {
|
||||
break :blk to_focus.?.getSurface();
|
||||
} else {
|
||||
break :blk null;
|
||||
}
|
||||
};
|
||||
const surface: ?*wlr.Surface = blk: {
|
||||
if (to_focus != null) {
|
||||
break :blk to_focus.?.getSurface();
|
||||
} else {
|
||||
break :blk null;
|
||||
}
|
||||
};
|
||||
|
||||
// Remove focus from the current surface unless:
|
||||
// - current and to focus are the same surface
|
||||
// - current layer has exclusive keyboard interactivity
|
||||
// - current is fullscreen and to focus is content
|
||||
// - current is fullscreen and layer is bottom or background
|
||||
if (self.focused_surface) |current_focus| {
|
||||
const current_surface = current_focus.getSurface();
|
||||
if (current_surface == surface) return; // Same surface
|
||||
// Remove focus from the current surface unless:
|
||||
// - current and to focus are the same surface
|
||||
// - current layer has exclusive keyboard interactivity
|
||||
// - current is fullscreen and to focus is content
|
||||
// - current is fullscreen and layer is bottom or background
|
||||
if (self.focused_surface) |current_focus| {
|
||||
const current_surface = current_focus.getSurface();
|
||||
if (current_surface == surface) return; // Same surface
|
||||
|
||||
if(to_focus != null) {
|
||||
switch (current_focus) {
|
||||
.layer_surface => |*current_layer_surface| {
|
||||
if(current_layer_surface.*.wlr_layer_surface.current.keyboard_interactive == .exclusive) return;
|
||||
},
|
||||
.view => |*current_view| {
|
||||
if(current_view.*.fullscreen) {
|
||||
switch (to_focus.?) {
|
||||
.layer_surface => |*layer_surface| {
|
||||
const layer = layer_surface.*.wlr_layer_surface.current.layer;
|
||||
if(layer == .background or layer == .bottom) return;
|
||||
},
|
||||
.view => |*view| {
|
||||
if(!view.*.fullscreen) return;
|
||||
}
|
||||
if (to_focus != null) {
|
||||
switch (current_focus) {
|
||||
.layer_surface => |*current_layer_surface| {
|
||||
if (current_layer_surface.*.wlr_layer_surface.current.keyboard_interactive == .exclusive) return;
|
||||
},
|
||||
.view => |*current_view| {
|
||||
if (current_view.*.fullscreen) {
|
||||
switch (to_focus.?) {
|
||||
.layer_surface => |*layer_surface| {
|
||||
const layer = layer_surface.*.wlr_layer_surface.current.layer;
|
||||
if (layer == .background or layer == .bottom) return;
|
||||
},
|
||||
.view => |*view| {
|
||||
if (!view.*.fullscreen) return;
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
} else if (current_focus == .view and current_focus.view.fullscreen) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if(current_focus == .view and current_focus.view.fullscreen){
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the focus if applicable
|
||||
switch (current_focus) {
|
||||
.layer_surface => {}, // IDK if we actually have to clear any focus here
|
||||
else => {
|
||||
if(wlr.XdgSurface.tryFromWlrSurface(current_surface)) |xdg_surface| {
|
||||
_ = xdg_surface.role_data.toplevel.?.setActivated(false);
|
||||
// Clear the focus if applicable
|
||||
switch (current_focus) {
|
||||
.layer_surface => {}, // IDK if we actually have to clear any focus here
|
||||
else => {
|
||||
if (wlr.XdgSurface.tryFromWlrSurface(current_surface)) |xdg_surface| {
|
||||
_ = xdg_surface.role_data.toplevel.?.setActivated(false);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(to_focus != null) {
|
||||
server.seat.wlr_seat.keyboardNotifyEnter(
|
||||
surface.?,
|
||||
&server.seat.keyboard_group.wlr_group.keyboard.keycodes,
|
||||
&server.seat.keyboard_group.wlr_group.keyboard.modifiers
|
||||
);
|
||||
if(to_focus.? != .layer_surface) {
|
||||
if(to_focus.? == .view) to_focus.?.view.focused = true;
|
||||
if(wlr.XdgSurface.tryFromWlrSurface(surface.?)) |xdg_surface| {
|
||||
_ = xdg_surface.role_data.toplevel.?.setActivated(true);
|
||||
}
|
||||
if (to_focus != null) {
|
||||
server.seat.wlr_seat.keyboardNotifyEnter(surface.?, &server.seat.keyboard_group.wlr_group.keyboard.keycodes, &server.seat.keyboard_group.wlr_group.keyboard.modifiers);
|
||||
if (to_focus.? != .layer_surface) {
|
||||
if (to_focus.? == .view) to_focus.?.view.focused = true;
|
||||
if (wlr.XdgSurface.tryFromWlrSurface(surface.?)) |xdg_surface| {
|
||||
_ = xdg_surface.role_data.toplevel.?.setActivated(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.focused_surface = to_focus;
|
||||
self.focused_surface = to_focus;
|
||||
}
|
||||
|
||||
pub fn focusOutput(self: *Seat, output: *Output) void {
|
||||
if(server.seat.focused_output) |prev_output| {
|
||||
prev_output.focused = false;
|
||||
}
|
||||
if (server.seat.focused_output) |prev_output| {
|
||||
prev_output.focused = false;
|
||||
}
|
||||
|
||||
self.focused_output = output;
|
||||
self.focused_output = output;
|
||||
}
|
||||
|
||||
fn handleRequestSetCursor(
|
||||
_: *wl.Listener(*wlr.Seat.event.RequestSetCursor),
|
||||
event: *wlr.Seat.event.RequestSetCursor,
|
||||
_: *wl.Listener(*wlr.Seat.event.RequestSetCursor),
|
||||
event: *wlr.Seat.event.RequestSetCursor,
|
||||
) void {
|
||||
if (event.seat_client == server.seat.wlr_seat.pointer_state.focused_client)
|
||||
server.cursor.wlr_cursor.setSurface(event.surface, event.hotspot_x, event.hotspot_y);
|
||||
if (event.seat_client == server.seat.wlr_seat.pointer_state.focused_client)
|
||||
server.cursor.wlr_cursor.setSurface(event.surface, event.hotspot_x, event.hotspot_y);
|
||||
}
|
||||
|
||||
fn handleRequestSetSelection(
|
||||
_: *wl.Listener(*wlr.Seat.event.RequestSetSelection),
|
||||
event: *wlr.Seat.event.RequestSetSelection,
|
||||
_: *wl.Listener(*wlr.Seat.event.RequestSetSelection),
|
||||
event: *wlr.Seat.event.RequestSetSelection,
|
||||
) void {
|
||||
server.seat.wlr_seat.setSelection(event.source, event.serial);
|
||||
server.seat.wlr_seat.setSelection(event.source, event.serial);
|
||||
}
|
||||
|
||||
fn handleRequestSetPrimarySelection(
|
||||
_: *wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection),
|
||||
event: *wlr.Seat.event.RequestSetPrimarySelection,
|
||||
_: *wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection),
|
||||
event: *wlr.Seat.event.RequestSetPrimarySelection,
|
||||
) void {
|
||||
server.seat.wlr_seat.setPrimarySelection(event.source, event.serial);
|
||||
server.seat.wlr_seat.setPrimarySelection(event.source, event.serial);
|
||||
}
|
||||
|
|
|
|||
308
src/Server.zig
308
src/Server.zig
|
|
@ -4,22 +4,22 @@ const std = @import("std");
|
|||
const wl = @import("wayland").server.wl;
|
||||
const wlr = @import("wlroots");
|
||||
|
||||
const Root = @import("Root.zig");
|
||||
const Seat = @import("Seat.zig");
|
||||
const Cursor = @import("Cursor.zig");
|
||||
const Keyboard = @import("Keyboard.zig");
|
||||
const LayerSurface = @import("LayerSurface.zig");
|
||||
const Output = @import("Output.zig");
|
||||
const View = @import("View.zig");
|
||||
const Keymap = @import("types/Keymap.zig");
|
||||
const Mousemap = @import("types/Mousemap.zig");
|
||||
const Hook = @import("types/Hook.zig");
|
||||
const Events = @import("types/Events.zig");
|
||||
const Popup = @import("Popup.zig");
|
||||
const RemoteLua = @import("RemoteLua.zig");
|
||||
const Root = @import("Root.zig");
|
||||
const Seat = @import("Seat.zig");
|
||||
const Cursor = @import("Cursor.zig");
|
||||
const Keyboard = @import("Keyboard.zig");
|
||||
const LayerSurface = @import("LayerSurface.zig");
|
||||
const Output = @import("Output.zig");
|
||||
const View = @import("View.zig");
|
||||
const Keymap = @import("types/Keymap.zig");
|
||||
const Mousemap = @import("types/Mousemap.zig");
|
||||
const Hook = @import("types/Hook.zig");
|
||||
const Events = @import("types/Events.zig");
|
||||
const Popup = @import("Popup.zig");
|
||||
const RemoteLua = @import("RemoteLua.zig");
|
||||
const RemoteLuaManager = @import("RemoteLuaManager.zig");
|
||||
const Utils = @import("Utils.zig");
|
||||
const SceneNodeData = @import("SceneNodeData.zig").SceneNodeData;
|
||||
const Utils = @import("Utils.zig");
|
||||
const SceneNodeData = @import("SceneNodeData.zig").SceneNodeData;
|
||||
|
||||
const gpa = std.heap.c_allocator;
|
||||
const server = &@import("main.zig").server;
|
||||
|
|
@ -62,195 +62,177 @@ new_layer_surface: wl.Listener(*wlr.LayerSurfaceV1) = .init(handleNewLayerSurfac
|
|||
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate) = .init(handleRequestActivate),
|
||||
|
||||
pub fn init(self: *Server) void {
|
||||
errdefer Utils.oomPanic();
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
const wl_server = wl.Server.create() catch {
|
||||
std.log.err("Server create failed, exiting with 2", .{});
|
||||
std.process.exit(2);
|
||||
};
|
||||
const wl_server = wl.Server.create() catch {
|
||||
std.log.err("Server create failed, exiting with 2", .{});
|
||||
std.process.exit(2);
|
||||
};
|
||||
|
||||
const event_loop = wl_server.getEventLoop();
|
||||
const event_loop = wl_server.getEventLoop();
|
||||
|
||||
var session: ?*wlr.Session = undefined;
|
||||
const backend = wlr.Backend.autocreate(event_loop, &session) catch {
|
||||
std.log.err("Backend create failed, exiting with 3", .{});
|
||||
std.process.exit(3);
|
||||
};
|
||||
var session: ?*wlr.Session = undefined;
|
||||
const backend = wlr.Backend.autocreate(event_loop, &session) catch {
|
||||
std.log.err("Backend create failed, exiting with 3", .{});
|
||||
std.process.exit(3);
|
||||
};
|
||||
|
||||
const renderer = wlr.Renderer.autocreate(backend) catch {
|
||||
std.log.err("Renderer create failed, exiting with 4", .{});
|
||||
std.process.exit(4);
|
||||
};
|
||||
const renderer = wlr.Renderer.autocreate(backend) catch {
|
||||
std.log.err("Renderer create failed, exiting with 4", .{});
|
||||
std.process.exit(4);
|
||||
};
|
||||
|
||||
self.* = .{
|
||||
.wl_server = wl_server,
|
||||
.backend = backend,
|
||||
.renderer = renderer,
|
||||
.allocator = wlr.Allocator.autocreate(backend, renderer) catch {
|
||||
std.log.err("Allocator create failed, exiting with 5", .{});
|
||||
std.process.exit(5);
|
||||
},
|
||||
.xdg_shell = try wlr.XdgShell.create(wl_server, 2),
|
||||
.layer_shell = try wlr.LayerShellV1.create(wl_server, 4),
|
||||
.xdg_toplevel_decoration_manager = try wlr.XdgDecorationManagerV1.create(self.wl_server),
|
||||
.xdg_activation = try wlr.XdgActivationV1.create(self.wl_server),
|
||||
.event_loop = event_loop,
|
||||
.session = session,
|
||||
.compositor = try wlr.Compositor.create(wl_server, 6, renderer),
|
||||
.shm = try wlr.Shm.createWithRenderer(wl_server, 1, renderer),
|
||||
// TODO: let the user configure a cursor theme and side lua
|
||||
.root = undefined,
|
||||
.seat = undefined,
|
||||
.cursor = undefined,
|
||||
.remote_lua_manager = RemoteLuaManager.init() catch Utils.oomPanic(),
|
||||
.keymaps = .init(gpa),
|
||||
.mousemaps = .init(gpa),
|
||||
.hooks = .init(gpa),
|
||||
.events = try .init(gpa),
|
||||
.remote_lua_clients = .{},
|
||||
};
|
||||
self.* = .{
|
||||
.wl_server = wl_server,
|
||||
.backend = backend,
|
||||
.renderer = renderer,
|
||||
.allocator = wlr.Allocator.autocreate(backend, renderer) catch {
|
||||
std.log.err("Allocator create failed, exiting with 5", .{});
|
||||
std.process.exit(5);
|
||||
},
|
||||
.xdg_shell = try wlr.XdgShell.create(wl_server, 2),
|
||||
.layer_shell = try wlr.LayerShellV1.create(wl_server, 4),
|
||||
.xdg_toplevel_decoration_manager = try wlr.XdgDecorationManagerV1.create(self.wl_server),
|
||||
.xdg_activation = try wlr.XdgActivationV1.create(self.wl_server),
|
||||
.event_loop = event_loop,
|
||||
.session = session,
|
||||
.compositor = try wlr.Compositor.create(wl_server, 6, renderer),
|
||||
.shm = try wlr.Shm.createWithRenderer(wl_server, 1, renderer),
|
||||
// TODO: let the user configure a cursor theme and side lua
|
||||
.root = undefined,
|
||||
.seat = undefined,
|
||||
.cursor = undefined,
|
||||
.remote_lua_manager = RemoteLuaManager.init() catch Utils.oomPanic(),
|
||||
.keymaps = .init(gpa),
|
||||
.mousemaps = .init(gpa),
|
||||
.hooks = .init(gpa),
|
||||
.events = try .init(gpa),
|
||||
.remote_lua_clients = .{},
|
||||
};
|
||||
|
||||
self.renderer.initServer(wl_server) catch {
|
||||
std.log.err("Renderer init failed, exiting with 6", .{});
|
||||
std.process.exit(6);
|
||||
};
|
||||
self.renderer.initServer(wl_server) catch {
|
||||
std.log.err("Renderer init failed, exiting with 6", .{});
|
||||
std.process.exit(6);
|
||||
};
|
||||
|
||||
self.root.init();
|
||||
self.seat.init();
|
||||
self.cursor.init();
|
||||
self.root.init();
|
||||
self.seat.init();
|
||||
self.cursor.init();
|
||||
|
||||
_ = try wlr.Subcompositor.create(self.wl_server);
|
||||
_ = try wlr.DataDeviceManager.create(self.wl_server);
|
||||
_ = try wlr.ExportDmabufManagerV1.create(self.wl_server);
|
||||
_ = try wlr.Viewporter.create(self.wl_server);
|
||||
_ = try wlr.Presentation.create(self.wl_server, self.backend, 2);
|
||||
_ = try wlr.ScreencopyManagerV1.create(self.wl_server);
|
||||
_ = try wlr.AlphaModifierV1.create(self.wl_server);
|
||||
_ = try wlr.DataControlManagerV1.create(self.wl_server);
|
||||
_ = try wlr.PrimarySelectionDeviceManagerV1.create(self.wl_server);
|
||||
_ = try wlr.SinglePixelBufferManagerV1.create(self.wl_server);
|
||||
_ = try wlr.FractionalScaleManagerV1.create(self.wl_server, 1);
|
||||
_ = try wlr.XdgOutputManagerV1.create(self.wl_server, self.root.output_layout);
|
||||
self.root.scene.setGammaControlManagerV1(try wlr.GammaControlManagerV1.create(self.wl_server));
|
||||
_ = try wlr.Subcompositor.create(self.wl_server);
|
||||
_ = try wlr.DataDeviceManager.create(self.wl_server);
|
||||
_ = try wlr.ExportDmabufManagerV1.create(self.wl_server);
|
||||
_ = try wlr.Viewporter.create(self.wl_server);
|
||||
_ = try wlr.Presentation.create(self.wl_server, self.backend, 2);
|
||||
_ = try wlr.ScreencopyManagerV1.create(self.wl_server);
|
||||
_ = try wlr.AlphaModifierV1.create(self.wl_server);
|
||||
_ = try wlr.DataControlManagerV1.create(self.wl_server);
|
||||
_ = try wlr.PrimarySelectionDeviceManagerV1.create(self.wl_server);
|
||||
_ = try wlr.SinglePixelBufferManagerV1.create(self.wl_server);
|
||||
_ = try wlr.FractionalScaleManagerV1.create(self.wl_server, 1);
|
||||
_ = try wlr.XdgOutputManagerV1.create(self.wl_server, self.root.output_layout);
|
||||
self.root.scene.setGammaControlManagerV1(try wlr.GammaControlManagerV1.create(self.wl_server));
|
||||
|
||||
// Add event listeners to events
|
||||
self.backend.events.new_input.add(&self.new_input);
|
||||
self.backend.events.new_output.add(&self.new_output);
|
||||
self.xdg_shell.events.new_toplevel.add(&self.new_xdg_toplevel);
|
||||
self.xdg_shell.events.new_popup.add(&self.new_xdg_popup);
|
||||
self.xdg_toplevel_decoration_manager.events.new_toplevel_decoration.add(&self.new_xdg_toplevel_decoration);
|
||||
self.layer_shell.events.new_surface.add(&self.new_layer_surface);
|
||||
self.xdg_activation.events.request_activate.add(&self.request_activate);
|
||||
// Add event listeners to events
|
||||
self.backend.events.new_input.add(&self.new_input);
|
||||
self.backend.events.new_output.add(&self.new_output);
|
||||
self.xdg_shell.events.new_toplevel.add(&self.new_xdg_toplevel);
|
||||
self.xdg_shell.events.new_popup.add(&self.new_xdg_popup);
|
||||
self.xdg_toplevel_decoration_manager.events.new_toplevel_decoration.add(&self.new_xdg_toplevel_decoration);
|
||||
self.layer_shell.events.new_surface.add(&self.new_layer_surface);
|
||||
self.xdg_activation.events.request_activate.add(&self.request_activate);
|
||||
|
||||
self.events.exec("ServerStartPost", .{});
|
||||
self.events.exec("ServerStartPost", .{});
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Server) noreturn {
|
||||
self.new_input.link.remove();
|
||||
self.new_output.link.remove();
|
||||
self.new_xdg_toplevel.link.remove();
|
||||
self.new_xdg_popup.link.remove();
|
||||
self.new_xdg_toplevel_decoration.link.remove();
|
||||
self.new_layer_surface.link.remove();
|
||||
self.new_input.link.remove();
|
||||
self.new_output.link.remove();
|
||||
self.new_xdg_toplevel.link.remove();
|
||||
self.new_xdg_popup.link.remove();
|
||||
self.new_xdg_toplevel_decoration.link.remove();
|
||||
self.new_layer_surface.link.remove();
|
||||
|
||||
self.seat.deinit();
|
||||
self.root.deinit();
|
||||
self.cursor.deinit();
|
||||
self.seat.deinit();
|
||||
self.root.deinit();
|
||||
self.cursor.deinit();
|
||||
|
||||
self.backend.destroy();
|
||||
self.backend.destroy();
|
||||
|
||||
self.wl_server.destroyClients();
|
||||
self.wl_server.destroy();
|
||||
self.wl_server.destroyClients();
|
||||
self.wl_server.destroy();
|
||||
|
||||
std.log.debug("Exiting mez succesfully", .{});
|
||||
std.process.exit(0);
|
||||
std.log.debug("Exiting mez succesfully", .{});
|
||||
std.process.exit(0);
|
||||
}
|
||||
|
||||
// --------- Backend event handlers ---------
|
||||
fn handleNewInput(
|
||||
_: *wl.Listener(*wlr.InputDevice),
|
||||
device: *wlr.InputDevice
|
||||
) void {
|
||||
switch (device.type) {
|
||||
.keyboard => _ = Keyboard.init(device),
|
||||
.pointer => server.cursor.wlr_cursor.attachInputDevice(device),
|
||||
else => {
|
||||
std.log.err(
|
||||
"New input request for input that is not a keyboard or pointer: {s}",
|
||||
.{device.name orelse "(null)"}
|
||||
);
|
||||
},
|
||||
}
|
||||
fn handleNewInput(_: *wl.Listener(*wlr.InputDevice), device: *wlr.InputDevice) void {
|
||||
switch (device.type) {
|
||||
.keyboard => _ = Keyboard.init(device),
|
||||
.pointer => server.cursor.wlr_cursor.attachInputDevice(device),
|
||||
else => {
|
||||
std.log.err("New input request for input that is not a keyboard or pointer: {s}", .{device.name orelse "(null)"});
|
||||
},
|
||||
}
|
||||
|
||||
// We should really only set true capabilities
|
||||
server.seat.wlr_seat.setCapabilities(.{
|
||||
.pointer = true,
|
||||
.keyboard = true,
|
||||
});
|
||||
// We should really only set true capabilities
|
||||
server.seat.wlr_seat.setCapabilities(.{
|
||||
.pointer = true,
|
||||
.keyboard = true,
|
||||
});
|
||||
}
|
||||
|
||||
fn handleNewOutput(
|
||||
_: *wl.Listener(*wlr.Output),
|
||||
wlr_output: *wlr.Output
|
||||
) void {
|
||||
_ = Output.init(wlr_output);
|
||||
fn handleNewOutput(_: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void {
|
||||
_ = Output.init(wlr_output);
|
||||
}
|
||||
|
||||
fn handleNewXdgToplevel(
|
||||
_: *wl.Listener(*wlr.XdgToplevel),
|
||||
xdg_toplevel: *wlr.XdgToplevel
|
||||
) void {
|
||||
_ = View.init(xdg_toplevel);
|
||||
fn handleNewXdgToplevel(_: *wl.Listener(*wlr.XdgToplevel), xdg_toplevel: *wlr.XdgToplevel) void {
|
||||
_ = View.init(xdg_toplevel);
|
||||
}
|
||||
|
||||
fn handleNewXdgToplevelDecoration(
|
||||
_: *wl.Listener(*wlr.XdgToplevelDecorationV1),
|
||||
decoration: *wlr.XdgToplevelDecorationV1
|
||||
) void {
|
||||
if(server.root.viewById(@intFromPtr(decoration.toplevel))) |view| {
|
||||
view.xdg_toplevel_decoration = decoration;
|
||||
}
|
||||
fn handleNewXdgToplevelDecoration(_: *wl.Listener(*wlr.XdgToplevelDecorationV1), decoration: *wlr.XdgToplevelDecorationV1) void {
|
||||
if (server.root.viewById(@intFromPtr(decoration.toplevel))) |view| {
|
||||
view.xdg_toplevel_decoration = decoration;
|
||||
}
|
||||
}
|
||||
|
||||
fn handleNewXdgPopup(_: *wl.Listener(*wlr.XdgPopup), _: *wlr.XdgPopup) void {
|
||||
std.log.debug("Unimplemented Server.handleNewXdgPopup\n", .{});
|
||||
std.log.debug("Unimplemented Server.handleNewXdgPopup\n", .{});
|
||||
}
|
||||
|
||||
fn handleNewLayerSurface(
|
||||
_: *wl.Listener(*wlr.LayerSurfaceV1),
|
||||
layer_surface: *wlr.LayerSurfaceV1
|
||||
) void {
|
||||
std.log.debug("requested layer shell\n", .{});
|
||||
if (layer_surface.output == null) {
|
||||
if (server.seat.focused_output == null) {
|
||||
std.log.err("No output available for new layer surface", .{});
|
||||
layer_surface.destroy();
|
||||
return;
|
||||
fn handleNewLayerSurface(_: *wl.Listener(*wlr.LayerSurfaceV1), layer_surface: *wlr.LayerSurfaceV1) void {
|
||||
std.log.debug("requested layer shell\n", .{});
|
||||
if (layer_surface.output == null) {
|
||||
if (server.seat.focused_output == null) {
|
||||
std.log.err("No output available for new layer surface", .{});
|
||||
layer_surface.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
layer_surface.output = server.seat.focused_output.?.wlr_output;
|
||||
}
|
||||
|
||||
layer_surface.output = server.seat.focused_output.?.wlr_output;
|
||||
}
|
||||
|
||||
_ = LayerSurface.init(layer_surface);
|
||||
_ = LayerSurface.init(layer_surface);
|
||||
}
|
||||
|
||||
fn handleRequestActivate(
|
||||
_: *wl.Listener(*wlr.XdgActivationV1.event.RequestActivate),
|
||||
event: *wlr.XdgActivationV1.event.RequestActivate,
|
||||
) void {
|
||||
if(event.surface.data == null) return;
|
||||
if (event.surface.data == null) return;
|
||||
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(event.surface.data.?));
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(event.surface.data.?));
|
||||
|
||||
if(scene_node_data.* == .view) {
|
||||
if(server.seat.focused_output) |output| {
|
||||
if(output.fullscreen) |fullscreen| {
|
||||
server.seat.focusSurface(.{ .view = fullscreen });
|
||||
return;
|
||||
}
|
||||
if (scene_node_data.* == .view) {
|
||||
if (server.seat.focused_output) |output| {
|
||||
if (output.fullscreen) |fullscreen| {
|
||||
server.seat.focusSurface(.{ .view = fullscreen });
|
||||
return;
|
||||
}
|
||||
}
|
||||
server.seat.focusSurface(Seat.FocusData{ .view = scene_node_data.view });
|
||||
} else {
|
||||
std.log.warn("Ignoring request to activate non-view", .{});
|
||||
}
|
||||
server.seat.focusSurface(Seat.FocusData{ .view = scene_node_data.view });
|
||||
} else {
|
||||
std.log.warn("Ignoring request to activate non-view", .{});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@ const Utils = @This();
|
|||
const std = @import("std");
|
||||
|
||||
pub fn oomPanic() noreturn {
|
||||
std.log.err("Out of memory error, exiting with 1", .{});
|
||||
std.process.exit(1);
|
||||
std.log.err("Out of memory error, exiting with 1", .{});
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
|
|
|||
372
src/View.zig
372
src/View.zig
|
|
@ -56,287 +56,273 @@ set_title: wl.Listener(void) = .init(handleSetTitle),
|
|||
// set_parent: wl.Listener(void) = .init(handleSetParent),
|
||||
|
||||
pub fn init(xdg_toplevel: *wlr.XdgToplevel) *View {
|
||||
errdefer Utils.oomPanic();
|
||||
errdefer Utils.oomPanic();
|
||||
|
||||
const self = try gpa.create(View);
|
||||
errdefer gpa.destroy(self);
|
||||
const self = try gpa.create(View);
|
||||
errdefer gpa.destroy(self);
|
||||
|
||||
self.* = .{
|
||||
.focused = false,
|
||||
.mapped = false,
|
||||
.fullscreen = false,
|
||||
.id = @intFromPtr(xdg_toplevel),
|
||||
.output = null,
|
||||
.geometry = .{ .width = 0, .height = 0, .x = 0, .y = 0 },
|
||||
self.* = .{
|
||||
.focused = false,
|
||||
.mapped = false,
|
||||
.fullscreen = false,
|
||||
.id = @intFromPtr(xdg_toplevel),
|
||||
.output = null,
|
||||
.geometry = .{ .width = 0, .height = 0, .x = 0, .y = 0 },
|
||||
.xdg_toplevel = xdg_toplevel,
|
||||
.scene_tree = undefined,
|
||||
.surface_tree = undefined,
|
||||
.xdg_toplevel_decoration = null,
|
||||
.borders = undefined,
|
||||
.border_width = 0,
|
||||
.scene_node_data = .{ .view = self },
|
||||
};
|
||||
|
||||
.xdg_toplevel = xdg_toplevel,
|
||||
.scene_tree = undefined,
|
||||
.surface_tree = undefined,
|
||||
.xdg_toplevel_decoration = null,
|
||||
.borders = undefined,
|
||||
.border_width = 0,
|
||||
// Add new Toplevel to root of the tree
|
||||
if (server.seat.focused_output) |output| {
|
||||
self.scene_tree = try output.layers.content.createSceneTree();
|
||||
self.surface_tree = try self.scene_tree.createSceneXdgSurface(xdg_toplevel.base);
|
||||
self.output = output;
|
||||
}
|
||||
|
||||
.scene_node_data = .{ .view = self }
|
||||
};
|
||||
self.scene_tree.node.data = &self.scene_node_data;
|
||||
self.xdg_toplevel.base.data = &self.scene_node_data;
|
||||
|
||||
// Add new Toplevel to root of the tree
|
||||
if(server.seat.focused_output) |output| {
|
||||
self.scene_tree = try output.layers.content.createSceneTree();
|
||||
self.surface_tree = try self.scene_tree.createSceneXdgSurface(xdg_toplevel.base);
|
||||
self.output = output;
|
||||
}
|
||||
self.xdg_toplevel.events.destroy.add(&self.destroy);
|
||||
self.xdg_toplevel.base.surface.events.map.add(&self.map);
|
||||
self.xdg_toplevel.base.surface.events.unmap.add(&self.unmap);
|
||||
self.xdg_toplevel.base.surface.events.commit.add(&self.commit);
|
||||
self.xdg_toplevel.base.events.new_popup.add(&self.new_popup);
|
||||
self.xdg_toplevel.base.events.ack_configure.add(&self.ack_configure);
|
||||
|
||||
self.scene_tree.node.data = &self.scene_node_data;
|
||||
self.xdg_toplevel.base.data = &self.scene_node_data;
|
||||
for (self.borders, 0..) |_, i| {
|
||||
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;
|
||||
}
|
||||
|
||||
self.xdg_toplevel.events.destroy.add(&self.destroy);
|
||||
self.xdg_toplevel.base.surface.events.map.add(&self.map);
|
||||
self.xdg_toplevel.base.surface.events.unmap.add(&self.unmap);
|
||||
self.xdg_toplevel.base.surface.events.commit.add(&self.commit);
|
||||
self.xdg_toplevel.base.events.new_popup.add(&self.new_popup);
|
||||
self.xdg_toplevel.base.events.ack_configure.add(&self.ack_configure);
|
||||
|
||||
for (self.borders, 0..) |_, i| {
|
||||
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;
|
||||
}
|
||||
|
||||
return self;
|
||||
return self;
|
||||
}
|
||||
|
||||
// Tell the client to close
|
||||
// It better behave!
|
||||
pub fn close(self: *View) void {
|
||||
self.xdg_toplevel.sendClose();
|
||||
self.xdg_toplevel.sendClose();
|
||||
}
|
||||
|
||||
pub fn setBorderColor(self: *View, color: *const [4]f32) void {
|
||||
for (self.borders) |border| border.setColor(color);
|
||||
for (self.borders) |border| border.setColor(color);
|
||||
}
|
||||
|
||||
pub fn toggleFullscreen(self: *View) void {
|
||||
self.fullscreen = !self.fullscreen;
|
||||
if(self.output) |output| {
|
||||
if(self.fullscreen and output.fullscreen != self) {
|
||||
// Check to see if another fullscreened view exists, if so replace it
|
||||
if(output.getFullscreenedView()) |view| {
|
||||
view.toggleFullscreen();
|
||||
}
|
||||
self.fullscreen = !self.fullscreen;
|
||||
if (self.output) |output| {
|
||||
if (self.fullscreen and output.fullscreen != self) {
|
||||
// Check to see if another fullscreened view exists, if so replace it
|
||||
if (output.getFullscreenedView()) |view| {
|
||||
view.toggleFullscreen();
|
||||
}
|
||||
|
||||
self.scene_tree.node.reparent(output.layers.fullscreen);
|
||||
self.setPosition(0, 0);
|
||||
self.setSize(output.wlr_output.width, output.wlr_output.height);
|
||||
output.fullscreen = self;
|
||||
} else {
|
||||
self.scene_tree.node.reparent(output.layers.content);
|
||||
output.fullscreen = null;
|
||||
self.scene_tree.node.reparent(output.layers.fullscreen);
|
||||
self.setPosition(0, 0);
|
||||
self.setSize(output.wlr_output.width, output.wlr_output.height);
|
||||
output.fullscreen = self;
|
||||
} else {
|
||||
self.scene_tree.node.reparent(output.layers.content);
|
||||
output.fullscreen = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = self.xdg_toplevel.setFullscreen(self.fullscreen);
|
||||
_ = self.xdg_toplevel.setFullscreen(self.fullscreen);
|
||||
}
|
||||
|
||||
pub fn setPosition(self: *View, x: i32, y: i32) void {
|
||||
if (self.output == null or !self.xdg_toplevel.base.surface.mapped) return;
|
||||
if (self.output == null or !self.xdg_toplevel.base.surface.mapped) return;
|
||||
|
||||
self.geometry.x = x;
|
||||
self.geometry.y = y;
|
||||
self.geometry.x = x;
|
||||
self.geometry.y = y;
|
||||
|
||||
self.scene_tree.node.setPosition(self.geometry.x, self.geometry.y);
|
||||
self.scene_tree.node.setPosition(self.geometry.x, self.geometry.y);
|
||||
|
||||
self.resizeBorders();
|
||||
self.resizeBorders();
|
||||
}
|
||||
|
||||
pub fn setSize(self: *View, width: i32, height: i32) void {
|
||||
if (self.output == null or !self.xdg_toplevel.base.surface.mapped) return;
|
||||
if (self.output == null or !self.xdg_toplevel.base.surface.mapped) return;
|
||||
|
||||
// at the very least the client must be big enough to have borders
|
||||
self.geometry.width = @max(1 + 2 * self.border_width, width);
|
||||
self.geometry.height = @max(1 + 2 * self.border_width, height);
|
||||
// at the very least the client must be big enough to have borders
|
||||
self.geometry.width = @max(1 + 2 * self.border_width, width);
|
||||
self.geometry.height = @max(1 + 2 * self.border_width, height);
|
||||
|
||||
// This returns a configure serial for verifying the configure
|
||||
_ = self.xdg_toplevel.setSize(
|
||||
self.geometry.width - 2 * self.border_width,
|
||||
self.geometry.height - 2 * self.border_width,
|
||||
);
|
||||
// This returns a configure serial for verifying the configure
|
||||
_ = self.xdg_toplevel.setSize(
|
||||
self.geometry.width - 2 * self.border_width,
|
||||
self.geometry.height - 2 * self.border_width,
|
||||
);
|
||||
|
||||
// clip the surface tree to the size of the view
|
||||
self.surface_tree.node.subsurfaceTreeSetClip(&wlr.Box{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = self.geometry.width,
|
||||
.height = self.geometry.height,
|
||||
});
|
||||
// clip the surface tree to the size of the view
|
||||
self.surface_tree.node.subsurfaceTreeSetClip(&wlr.Box{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = self.geometry.width,
|
||||
.height = self.geometry.height,
|
||||
});
|
||||
|
||||
self.resizeBorders();
|
||||
self.resizeBorders();
|
||||
}
|
||||
|
||||
/// this function handles all things related to sizing and positioning and
|
||||
/// should be called after something in the size or position is changed
|
||||
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);
|
||||
// set the position of the surface to not clip with the borders
|
||||
self.surface_tree.node.setPosition(self.border_width, self.border_width);
|
||||
|
||||
self.borders[0].setSize(self.geometry.width, self.border_width);
|
||||
self.borders[1].setSize(self.geometry.width, self.border_width);
|
||||
self.borders[2].setSize(self.border_width, self.geometry.height);
|
||||
self.borders[3].setSize(self.border_width, self.geometry.height);
|
||||
self.borders[1].node.setPosition(0, self.geometry.height - self.border_width);
|
||||
self.borders[2].node.setPosition(self.geometry.width - self.border_width, 0);
|
||||
self.borders[0].setSize(self.geometry.width, self.border_width);
|
||||
self.borders[1].setSize(self.geometry.width, self.border_width);
|
||||
self.borders[2].setSize(self.border_width, self.geometry.height);
|
||||
self.borders[3].setSize(self.border_width, self.geometry.height);
|
||||
self.borders[1].node.setPosition(0, self.geometry.height - self.border_width);
|
||||
self.borders[2].node.setPosition(self.geometry.width - self.border_width, 0);
|
||||
}
|
||||
|
||||
// --------- XdgTopLevel event handlers ---------
|
||||
fn handleMap(listener: *wl.Listener(void)) void {
|
||||
const view: *View = @fieldParentPtr("map", listener);
|
||||
const view: *View = @fieldParentPtr("map", listener);
|
||||
|
||||
server.events.exec("ViewMapPre", .{view.id});
|
||||
server.events.exec("ViewMapPre", .{view.id});
|
||||
|
||||
// we're gonna tell the client that it's tiled so it doesn't try anything
|
||||
// stupid
|
||||
_ = view.xdg_toplevel.setTiled(.{
|
||||
.top = true,
|
||||
.bottom = true,
|
||||
.left = true,
|
||||
.right = true,
|
||||
});
|
||||
// we're gonna tell the client that it's tiled so it doesn't try anything
|
||||
// stupid
|
||||
_ = view.xdg_toplevel.setTiled(.{
|
||||
.top = true,
|
||||
.bottom = true,
|
||||
.left = true,
|
||||
.right = true,
|
||||
});
|
||||
|
||||
view.xdg_toplevel.events.request_fullscreen.add(&view.request_fullscreen);
|
||||
view.xdg_toplevel.events.request_move.add(&view.request_move);
|
||||
view.xdg_toplevel.events.request_resize.add(&view.request_resize);
|
||||
view.xdg_toplevel.events.set_app_id.add(&view.set_app_id);
|
||||
view.xdg_toplevel.events.set_title.add(&view.set_title);
|
||||
// view.xdg_toplevel.events.set_parent.add(&view.set_parent);
|
||||
view.xdg_toplevel.events.request_fullscreen.add(&view.request_fullscreen);
|
||||
view.xdg_toplevel.events.request_move.add(&view.request_move);
|
||||
view.xdg_toplevel.events.request_resize.add(&view.request_resize);
|
||||
view.xdg_toplevel.events.set_app_id.add(&view.set_app_id);
|
||||
view.xdg_toplevel.events.set_title.add(&view.set_title);
|
||||
// view.xdg_toplevel.events.set_parent.add(&view.set_parent);
|
||||
|
||||
view.mapped = true;
|
||||
server.events.exec("ViewMapPost", .{view.id});
|
||||
view.mapped = true;
|
||||
server.events.exec("ViewMapPost", .{view.id});
|
||||
}
|
||||
|
||||
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)"});
|
||||
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.mapped = false; // we do this before any work is done so that nobody tries
|
||||
// any funny business
|
||||
server.events.exec("ViewUnmapPre", .{view.id});
|
||||
view.mapped = false; // we do this before any work is done so that nobody tries
|
||||
// any funny business
|
||||
|
||||
if (server.seat.focused_surface) |fs| {
|
||||
if (fs == .view and fs.view == view) {
|
||||
server.seat.focusSurface(null);
|
||||
if (server.seat.focused_surface) |fs| {
|
||||
if (fs == .view and fs.view == view) {
|
||||
server.seat.focusSurface(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view.request_fullscreen.link.remove();
|
||||
view.request_move.link.remove();
|
||||
view.request_resize.link.remove();
|
||||
view.set_title.link.remove();
|
||||
view.set_app_id.link.remove();
|
||||
view.ack_configure.link.remove();
|
||||
view.request_fullscreen.link.remove();
|
||||
view.request_move.link.remove();
|
||||
view.request_resize.link.remove();
|
||||
view.set_title.link.remove();
|
||||
view.set_app_id.link.remove();
|
||||
view.ack_configure.link.remove();
|
||||
|
||||
server.events.exec("ViewUnmapPost", .{view.id});
|
||||
server.events.exec("ViewUnmapPost", .{view.id});
|
||||
}
|
||||
|
||||
fn handleDestroy(listener: *wl.Listener(void)) void {
|
||||
const view: *View = @fieldParentPtr("destroy", listener);
|
||||
const view: *View = @fieldParentPtr("destroy", listener);
|
||||
|
||||
// Remove decorations
|
||||
// Remove decorations
|
||||
|
||||
view.map.link.remove();
|
||||
view.unmap.link.remove();
|
||||
view.commit.link.remove();
|
||||
view.destroy.link.remove();
|
||||
view.new_popup.link.remove();
|
||||
view.map.link.remove();
|
||||
view.unmap.link.remove();
|
||||
view.commit.link.remove();
|
||||
view.destroy.link.remove();
|
||||
view.new_popup.link.remove();
|
||||
|
||||
view.xdg_toplevel.base.surface.data = null;
|
||||
view.xdg_toplevel.base.surface.data = null;
|
||||
|
||||
view.scene_tree.node.destroy();
|
||||
// Destroy popups
|
||||
view.scene_tree.node.destroy();
|
||||
// Destroy popups
|
||||
|
||||
gpa.destroy(view);
|
||||
gpa.destroy(view);
|
||||
}
|
||||
|
||||
fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||
const view: *View = @fieldParentPtr("commit", listener);
|
||||
const view: *View = @fieldParentPtr("commit", listener);
|
||||
|
||||
// On the first commit, send a configure to tell the client it can proceed
|
||||
if (view.xdg_toplevel.base.initial_commit) {
|
||||
// On the first commit, send a configure to tell the client it can proceed
|
||||
if (view.xdg_toplevel.base.initial_commit) {
|
||||
|
||||
// 5 is the XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION, I'm just not sure where it is in the bindings
|
||||
if (view.xdg_toplevel.base.client.shell.version >= 5) {
|
||||
// the client should know that it can only fullscreen, nothing else
|
||||
_ = view.xdg_toplevel.setWmCapabilities(.{ .fullscreen = true, });
|
||||
// 5 is the XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION, I'm just not sure where it is in the bindings
|
||||
if (view.xdg_toplevel.base.client.shell.version >= 5) {
|
||||
// the client should know that it can only fullscreen, nothing else
|
||||
_ = view.xdg_toplevel.setWmCapabilities(.{
|
||||
.fullscreen = true,
|
||||
});
|
||||
}
|
||||
|
||||
// before committing we tell the client that we'll handle the decorations
|
||||
if (view.xdg_toplevel_decoration) |deco| _ = deco.setMode(.server_side);
|
||||
|
||||
// this tells the client that it can start doing things we don't use our
|
||||
// wrapper here cause we don't want to enforce any of our rules
|
||||
_ = view.xdg_toplevel.setSize(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// before committing we tell the client that we'll handle the decorations
|
||||
if (view.xdg_toplevel_decoration) |deco| _ = deco.setMode(.server_side);
|
||||
|
||||
// this tells the client that it can start doing things we don't use our
|
||||
// wrapper here cause we don't want to enforce any of our rules
|
||||
_ = view.xdg_toplevel.setSize(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// resize on every commit
|
||||
view.resizeBorders();
|
||||
// resize on every commit
|
||||
view.resizeBorders();
|
||||
}
|
||||
|
||||
// --------- XdgToplevel Event Handlers ---------
|
||||
fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), xdg_popup: *wlr.XdgPopup) void {
|
||||
const view: *View = @fieldParentPtr("new_popup", listener);
|
||||
_ = Popup.init(xdg_popup, view.scene_tree);
|
||||
const view: *View = @fieldParentPtr("new_popup", listener);
|
||||
_ = Popup.init(xdg_popup, view.scene_tree);
|
||||
}
|
||||
|
||||
fn handleRequestMove(
|
||||
listener: *wl.Listener(*wlr.XdgToplevel.event.Move),
|
||||
_: *wlr.XdgToplevel.event.Move
|
||||
) void {
|
||||
const view: *View = @fieldParentPtr("request_move", listener);
|
||||
server.events.exec("ViewRequestMove", .{view.id});
|
||||
fn handleRequestMove(listener: *wl.Listener(*wlr.XdgToplevel.event.Move), _: *wlr.XdgToplevel.event.Move) void {
|
||||
const view: *View = @fieldParentPtr("request_move", listener);
|
||||
server.events.exec("ViewRequestMove", .{view.id});
|
||||
}
|
||||
|
||||
fn handleRequestResize(
|
||||
listener: *wl.Listener(*wlr.XdgToplevel.event.Resize),
|
||||
_: *wlr.XdgToplevel.event.Resize
|
||||
) void {
|
||||
const view: *View = @fieldParentPtr("request_resize", listener);
|
||||
server.events.exec("ViewRequestResize", .{view.id});
|
||||
fn handleRequestResize(listener: *wl.Listener(*wlr.XdgToplevel.event.Resize), _: *wlr.XdgToplevel.event.Resize) void {
|
||||
const view: *View = @fieldParentPtr("request_resize", listener);
|
||||
server.events.exec("ViewRequestResize", .{view.id});
|
||||
}
|
||||
|
||||
fn handleAckConfigure(
|
||||
listener: *wl.Listener(*wlr.XdgSurface.Configure),
|
||||
_: *wlr.XdgSurface.Configure,
|
||||
listener: *wl.Listener(*wlr.XdgSurface.Configure),
|
||||
_: *wlr.XdgSurface.Configure,
|
||||
) void {
|
||||
const view: *View = @fieldParentPtr("ack_configure", listener);
|
||||
_ = view;
|
||||
std.log.err("Unimplemented ack configure", .{});
|
||||
const view: *View = @fieldParentPtr("ack_configure", listener);
|
||||
_ = view;
|
||||
std.log.err("Unimplemented ack configure", .{});
|
||||
}
|
||||
|
||||
fn handleRequestFullscreen(
|
||||
listener: *wl.Listener(void)
|
||||
) void {
|
||||
const view: *View = @fieldParentPtr("request_fullscreen", listener);
|
||||
server.events.exec("ViewRequestFullscreen", .{view.id});
|
||||
fn handleRequestFullscreen(listener: *wl.Listener(void)) void {
|
||||
const view: *View = @fieldParentPtr("request_fullscreen", listener);
|
||||
server.events.exec("ViewRequestFullscreen", .{view.id});
|
||||
}
|
||||
|
||||
fn handleRequestMinimize(
|
||||
listener: *wl.Listener(void)
|
||||
) void {
|
||||
const view: *View = @fieldParentPtr("request_minimize", listener);
|
||||
server.events.exec("ViewRequestMinimize", .{view.id});
|
||||
std.log.debug("request_minimize unimplemented", .{});
|
||||
fn handleRequestMinimize(listener: *wl.Listener(void)) void {
|
||||
const view: *View = @fieldParentPtr("request_minimize", listener);
|
||||
server.events.exec("ViewRequestMinimize", .{view.id});
|
||||
std.log.debug("request_minimize unimplemented", .{});
|
||||
}
|
||||
|
||||
fn handleSetAppId(
|
||||
listener: *wl.Listener(void)
|
||||
) void {
|
||||
const view: *View = @fieldParentPtr("set_app_id", listener);
|
||||
server.events.exec("ViewAppIdUpdate", .{view.id});
|
||||
std.log.debug("request_set_app_id unimplemented", .{});
|
||||
fn handleSetAppId(listener: *wl.Listener(void)) void {
|
||||
const view: *View = @fieldParentPtr("set_app_id", listener);
|
||||
server.events.exec("ViewAppIdUpdate", .{view.id});
|
||||
std.log.debug("request_set_app_id unimplemented", .{});
|
||||
}
|
||||
|
||||
fn handleSetTitle(
|
||||
listener: *wl.Listener(void)
|
||||
) void {
|
||||
const view: *View = @fieldParentPtr("set_title", listener);
|
||||
server.events.exec("ViewTitleUpdate", .{view.id});
|
||||
std.log.debug("request_set_title unimplemented", .{});
|
||||
fn handleSetTitle(listener: *wl.Listener(void)) void {
|
||||
const view: *View = @fieldParentPtr("set_title", listener);
|
||||
server.events.exec("ViewTitleUpdate", .{view.id});
|
||||
std.log.debug("request_set_title unimplemented", .{});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
const zlua = @import("zlua");
|
||||
const wlr = @import("wlroots");
|
||||
|
||||
const Utils = @import("../Utils.zig");
|
||||
const Utils = @import("../Utils.zig");
|
||||
const LuaUtils = @import("LuaUtils.zig");
|
||||
|
||||
const gpa = std.heap.c_allocator;
|
||||
|
|
@ -13,53 +13,53 @@ const server = &@import("../main.zig").server;
|
|||
/// ---Spawn new application via the shell command
|
||||
/// ---@param cmd string Command to be run by a shell
|
||||
pub fn spawn(L: *zlua.Lua) i32 {
|
||||
const cmd = L.checkString(1);
|
||||
const cmd = L.checkString(1);
|
||||
|
||||
var child = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", cmd }, gpa);
|
||||
child.env_map = env_map;
|
||||
child.spawn() catch |err| switch (err) {
|
||||
error.OutOfMemory => Utils.oomPanic(),
|
||||
else => L.raiseErrorStr("Unable to spawn process child process", .{}),
|
||||
};
|
||||
var child = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", cmd }, gpa);
|
||||
child.env_map = env_map;
|
||||
child.spawn() catch |err| switch (err) {
|
||||
error.OutOfMemory => Utils.oomPanic(),
|
||||
else => L.raiseErrorStr("Unable to spawn process child process", .{}),
|
||||
};
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Exit mezzaluna
|
||||
pub fn exit(L: *zlua.Lua) i32 {
|
||||
server.wl_server.terminate();
|
||||
server.wl_server.terminate();
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Change to a different virtual terminal
|
||||
/// ---@param vt_num integer virtual terminal number to switch to
|
||||
pub fn change_vt(L: *zlua.Lua) i32 {
|
||||
const vt_num = num: {
|
||||
const res = LuaUtils.coerceInteger(c_uint, L.checkInteger(1)) catch |err| break :num err;
|
||||
if (res < 1) break :num error.InvalidInteger;
|
||||
break :num res;
|
||||
} catch L.raiseErrorStr("The vt number must be >= 1 and < inf", .{});
|
||||
const vt_num = num: {
|
||||
const res = LuaUtils.coerceInteger(c_uint, L.checkInteger(1)) catch |err| break :num err;
|
||||
if (res < 1) break :num error.InvalidInteger;
|
||||
break :num res;
|
||||
} catch L.raiseErrorStr("The vt number must be >= 1 and < inf", .{});
|
||||
|
||||
if (server.session) |session| {
|
||||
std.log.debug("Changing virtual terminal to {d}", .{vt_num});
|
||||
wlr.Session.changeVt(session, vt_num) catch {
|
||||
L.raiseErrorStr("Failed to switch vt", .{});
|
||||
};
|
||||
} else {
|
||||
L.raiseErrorStr("Mez has not been initialized yet", .{});
|
||||
}
|
||||
if (server.session) |session| {
|
||||
std.log.debug("Changing virtual terminal to {d}", .{vt_num});
|
||||
wlr.Session.changeVt(session, vt_num) catch {
|
||||
L.raiseErrorStr("Failed to switch vt", .{});
|
||||
};
|
||||
} else {
|
||||
L.raiseErrorStr("Mez has not been initialized yet", .{});
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// --- Print the scene tree for debugging
|
||||
pub fn print_scene(L: *zlua.Lua) i32 {
|
||||
@import("../Debug.zig").debugPrintSceneTree();
|
||||
@import("../Debug.zig").debugPrintSceneTree();
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@ const zlua = @import("zlua");
|
|||
const gpa = std.heap.c_allocator;
|
||||
|
||||
pub fn getNestedField(L: *zlua.Lua, path: []u8) bool {
|
||||
var tokens = std.mem.tokenizeScalar(u8, path, '.');
|
||||
var first = true;
|
||||
var tokens = std.mem.tokenizeScalar(u8, path, '.');
|
||||
var first = true;
|
||||
|
||||
while (tokens.next()) |token| {
|
||||
const tok = gpa.dupeZ(u8, token) catch return false;
|
||||
if (first) {
|
||||
_ = L.getGlobal(tok) catch return false;
|
||||
first = false;
|
||||
} else {
|
||||
_ = L.getField(-1, tok);
|
||||
L.remove(-2);
|
||||
while (tokens.next()) |token| {
|
||||
const tok = gpa.dupeZ(u8, token) catch return false;
|
||||
if (first) {
|
||||
_ = L.getGlobal(tok) catch return false;
|
||||
first = false;
|
||||
} else {
|
||||
_ = L.getField(-1, tok);
|
||||
L.remove(-2);
|
||||
}
|
||||
|
||||
if (L.isNil(-1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (L.isNil(-1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const std = @import("std");
|
|||
const zlua = @import("zlua");
|
||||
|
||||
const Lua = @import("Lua.zig");
|
||||
const Utils = @import("../Utils.zig");
|
||||
const Utils = @import("../Utils.zig");
|
||||
|
||||
const gpa = std.heap.c_allocator;
|
||||
|
||||
|
|
@ -12,29 +12,29 @@ const gpa = std.heap.c_allocator;
|
|||
/// ---@vararg string paths to join
|
||||
/// ---@return string?
|
||||
pub fn joinpath(L: *zlua.Lua) i32 {
|
||||
const nargs: i32 = L.getTop();
|
||||
if (nargs < 2) {
|
||||
L.raiseErrorStr("Expected at least two paths to join", .{});
|
||||
return 0;
|
||||
}
|
||||
|
||||
var paths = std.ArrayList([:0]const u8).initCapacity(gpa, @intCast(nargs)) catch Utils.oomPanic();
|
||||
defer paths.deinit(gpa);
|
||||
|
||||
var i: u8 = 1;
|
||||
while (i <= nargs) : (i += 1) {
|
||||
if (!L.isString(i)) {
|
||||
L.raiseErrorStr("Expected string at argument %d", .{i});
|
||||
return 0;
|
||||
const nargs: i32 = L.getTop();
|
||||
if (nargs < 2) {
|
||||
L.raiseErrorStr("Expected at least two paths to join", .{});
|
||||
return 0;
|
||||
}
|
||||
|
||||
const partial_path = L.toString(i) catch unreachable;
|
||||
paths.append(gpa, partial_path) catch Utils.oomPanic();
|
||||
}
|
||||
var paths = std.ArrayList([:0]const u8).initCapacity(gpa, @intCast(nargs)) catch Utils.oomPanic();
|
||||
defer paths.deinit(gpa);
|
||||
|
||||
const final_path: []const u8 = std.fs.path.join(gpa, paths.items) catch Utils.oomPanic();
|
||||
defer gpa.free(final_path);
|
||||
var i: u8 = 1;
|
||||
while (i <= nargs) : (i += 1) {
|
||||
if (!L.isString(i)) {
|
||||
L.raiseErrorStr("Expected string at argument %d", .{i});
|
||||
return 0;
|
||||
}
|
||||
|
||||
_ = L.pushString(final_path);
|
||||
return 1;
|
||||
const partial_path = L.toString(i) catch unreachable;
|
||||
paths.append(gpa, partial_path) catch Utils.oomPanic();
|
||||
}
|
||||
|
||||
const final_path: []const u8 = std.fs.path.join(gpa, paths.items) catch Utils.oomPanic();
|
||||
defer gpa.free(final_path);
|
||||
|
||||
_ = L.pushString(final_path);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,60 +15,60 @@ const server = &@import("../main.zig").server;
|
|||
/// ---@param options table
|
||||
/// ---@return number id
|
||||
pub fn add(L: *zlua.Lua) i32 {
|
||||
L.checkType(2, .table);
|
||||
L.checkType(2, .table);
|
||||
|
||||
var hook: *THook = gpa.create(THook) catch Utils.oomPanic();
|
||||
var hook: *THook = gpa.create(THook) catch Utils.oomPanic();
|
||||
|
||||
// We support both a string and a table of strings as the first value of
|
||||
// add. Regardless of which type is passed in we create an arraylist of
|
||||
// []const u8's
|
||||
if (L.isTable(1)) {
|
||||
hook.events = gpa.alloc(comptime []const u8, L.objectLen(1)) catch Utils.oomPanic();
|
||||
var i: u32 = 0;
|
||||
L.pushNil();
|
||||
while (L.next(1)) {
|
||||
if (L.isString(-1)) {
|
||||
const s = L.checkString(-1);
|
||||
hook.events[i] = gpa.dupe(u8, s) catch Utils.oomPanic();
|
||||
i += 1;
|
||||
}
|
||||
L.pop(1);
|
||||
// We support both a string and a table of strings as the first value of
|
||||
// add. Regardless of which type is passed in we create an arraylist of
|
||||
// []const u8's
|
||||
if (L.isTable(1)) {
|
||||
hook.events = gpa.alloc(comptime []const u8, L.objectLen(1)) catch Utils.oomPanic();
|
||||
var i: u32 = 0;
|
||||
L.pushNil();
|
||||
while (L.next(1)) {
|
||||
if (L.isString(-1)) {
|
||||
const s = L.checkString(-1);
|
||||
hook.events[i] = gpa.dupe(u8, s) catch Utils.oomPanic();
|
||||
i += 1;
|
||||
}
|
||||
L.pop(1);
|
||||
}
|
||||
} else if (L.isString(1)) {
|
||||
hook.events = gpa.alloc(comptime []const u8, 1) catch Utils.oomPanic();
|
||||
const s = L.checkString(1);
|
||||
hook.events[0] = gpa.dupe(u8, s) catch Utils.oomPanic();
|
||||
}
|
||||
} else if (L.isString(1)) {
|
||||
hook.events = gpa.alloc(comptime []const u8, 1) catch Utils.oomPanic();
|
||||
const s = L.checkString(1);
|
||||
hook.events[0] = gpa.dupe(u8, s) catch Utils.oomPanic();
|
||||
}
|
||||
|
||||
_ = L.pushString("callback");
|
||||
_ = L.getTable(2);
|
||||
if (L.isFunction(-1)) {
|
||||
hook.options.lua_cb_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
_ = L.pushString("callback");
|
||||
_ = L.getTable(2);
|
||||
if (L.isFunction(-1)) {
|
||||
hook.options.lua_cb_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
|
||||
// TEST: this should be safe as the lua_cb_ref_idx's should never be the same
|
||||
// but that all really depends on the implementation of the hashmap
|
||||
server.hooks.put(hook.options.lua_cb_ref_idx, hook) catch Utils.oomPanic();
|
||||
// TEST: this should be safe as the lua_cb_ref_idx's should never be the same
|
||||
// but that all really depends on the implementation of the hashmap
|
||||
server.hooks.put(hook.options.lua_cb_ref_idx, hook) catch Utils.oomPanic();
|
||||
|
||||
for (hook.events) |value| {
|
||||
server.events.put(value, hook) catch Utils.oomPanic();
|
||||
}
|
||||
for (hook.events) |value| {
|
||||
server.events.put(value, hook) catch Utils.oomPanic();
|
||||
}
|
||||
|
||||
L.pushInteger(hook.options.lua_cb_ref_idx);
|
||||
return 1;
|
||||
L.pushInteger(hook.options.lua_cb_ref_idx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Create an existing hook
|
||||
/// ---@param id number
|
||||
/// ---@return boolean has it been deleted
|
||||
pub fn del(L: *zlua.Lua) i32 {
|
||||
const hook_id = LuaUtils.coerceInteger(i32, L.checkInteger(1)) catch L.raiseErrorStr("hook id must be a valid number", .{});
|
||||
const hook = server.hooks.get(hook_id);
|
||||
if (hook == null) L.raiseErrorStr("hook {} does not exist", .{hook_id});
|
||||
const hook_id = LuaUtils.coerceInteger(i32, L.checkInteger(1)) catch L.raiseErrorStr("hook id must be a valid number", .{});
|
||||
const hook = server.hooks.get(hook_id);
|
||||
if (hook == null) L.raiseErrorStr("hook {} does not exist", .{hook_id});
|
||||
|
||||
for (hook.?.events) |value| {
|
||||
server.events.del(value, hook.?);
|
||||
}
|
||||
L.pushBoolean(server.hooks.remove(hook_id));
|
||||
return 1;
|
||||
for (hook.?.events) |value| {
|
||||
server.events.del(value, hook.?);
|
||||
}
|
||||
L.pushBoolean(server.hooks.remove(hook_id));
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,17 +14,17 @@ const c = @import("../C.zig").c;
|
|||
const server = &@import("../main.zig").server;
|
||||
|
||||
fn parse_modkeys(modStr: []const u8) wlr.Keyboard.ModifierMask {
|
||||
var it = std.mem.splitScalar(u8, modStr, '|');
|
||||
var modifiers = wlr.Keyboard.ModifierMask{};
|
||||
while (it.next()) |m| {
|
||||
inline for (std.meta.fields(@TypeOf(modifiers))) |f| {
|
||||
if (f.type == bool and std.mem.eql(u8, m, f.name)) {
|
||||
@field(modifiers, f.name) = true;
|
||||
}
|
||||
var it = std.mem.splitScalar(u8, modStr, '|');
|
||||
var modifiers = wlr.Keyboard.ModifierMask{};
|
||||
while (it.next()) |m| {
|
||||
inline for (std.meta.fields(@TypeOf(modifiers))) |f| {
|
||||
if (f.type == bool and std.mem.eql(u8, m, f.name)) {
|
||||
@field(modifiers, f.name) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modifiers;
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
/// ---Create a new keymap
|
||||
|
|
@ -32,36 +32,36 @@ fn parse_modkeys(modStr: []const u8) wlr.Keyboard.ModifierMask {
|
|||
/// ---@param string keys
|
||||
/// ---@param table options
|
||||
pub fn add_keymap(L: *zlua.Lua) i32 {
|
||||
var keymap: Keymap = undefined;
|
||||
keymap.options.repeat = true;
|
||||
var keymap: Keymap = undefined;
|
||||
keymap.options.repeat = true;
|
||||
|
||||
const mod = L.checkString(1);
|
||||
keymap.modifier = parse_modkeys(mod);
|
||||
const mod = L.checkString(1);
|
||||
keymap.modifier = parse_modkeys(mod);
|
||||
|
||||
const key = L.checkString(2);
|
||||
keymap.keycode = xkb.Keysym.fromName(key, .no_flags);
|
||||
const key = L.checkString(2);
|
||||
keymap.keycode = xkb.Keysym.fromName(key, .no_flags);
|
||||
|
||||
_ = L.pushString("press");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
keymap.options.lua_press_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
_ = L.pushString("press");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
keymap.options.lua_press_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
|
||||
_ = L.pushString("release");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
keymap.options.lua_release_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
_ = L.pushString("release");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
keymap.options.lua_release_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
|
||||
_ = L.pushString("repeat");
|
||||
_ = L.getTable(3);
|
||||
keymap.options.repeat = L.isNil(-1) or L.toBoolean(-1);
|
||||
_ = L.pushString("repeat");
|
||||
_ = L.getTable(3);
|
||||
keymap.options.repeat = L.isNil(-1) or L.toBoolean(-1);
|
||||
|
||||
const hash = Keymap.hash(keymap.modifier, keymap.keycode);
|
||||
server.keymaps.put(hash, keymap) catch Utils.oomPanic();
|
||||
const hash = Keymap.hash(keymap.modifier, keymap.keycode);
|
||||
server.keymaps.put(hash, keymap) catch Utils.oomPanic();
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Create a new mousemap
|
||||
|
|
@ -69,113 +69,113 @@ pub fn add_keymap(L: *zlua.Lua) i32 {
|
|||
/// ---@param string libevdev button name (ex. "BTN_LEFT", "BTN_RIGHT")
|
||||
/// ---@param table options
|
||||
pub fn add_mousemap(L: *zlua.Lua) i32 {
|
||||
var mousemap: Mousemap = undefined;
|
||||
var mousemap: Mousemap = undefined;
|
||||
|
||||
const mod = L.checkString(1);
|
||||
mousemap.modifier = parse_modkeys(mod);
|
||||
const mod = L.checkString(1);
|
||||
mousemap.modifier = parse_modkeys(mod);
|
||||
|
||||
const button = L.checkString(2);
|
||||
mousemap.event_code = c.libevdev_event_code_from_name(c.EV_KEY, button);
|
||||
const button = L.checkString(2);
|
||||
mousemap.event_code = c.libevdev_event_code_from_name(c.EV_KEY, button);
|
||||
|
||||
_ = L.pushString("press");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
mousemap.options.lua_press_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
_ = L.pushString("press");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
mousemap.options.lua_press_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
|
||||
_ = L.pushString("release");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
mousemap.options.lua_release_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
_ = L.pushString("release");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
mousemap.options.lua_release_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
|
||||
_ = L.pushString("drag");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
mousemap.options.lua_drag_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
_ = L.pushString("drag");
|
||||
_ = L.getTable(3);
|
||||
if (L.isFunction(-1)) {
|
||||
mousemap.options.lua_drag_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic();
|
||||
}
|
||||
|
||||
const hash = Mousemap.hash(mousemap.modifier, mousemap.event_code);
|
||||
server.mousemaps.put(hash, mousemap) catch Utils.oomPanic();
|
||||
const hash = Mousemap.hash(mousemap.modifier, mousemap.event_code);
|
||||
server.mousemaps.put(hash, mousemap) catch Utils.oomPanic();
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Remove an existing keymap
|
||||
/// ---@param string modifiers
|
||||
/// ---@param string keys
|
||||
pub fn del_keymap(L: *zlua.Lua) i32 {
|
||||
L.checkType(1, .string);
|
||||
L.checkType(2, .string);
|
||||
L.checkType(1, .string);
|
||||
L.checkType(2, .string);
|
||||
|
||||
var keymap: Keymap = undefined;
|
||||
const mod = L.checkString(1);
|
||||
var keymap: Keymap = undefined;
|
||||
const mod = L.checkString(1);
|
||||
|
||||
keymap.modifier = parse_modkeys(mod);
|
||||
keymap.modifier = parse_modkeys(mod);
|
||||
|
||||
const key = L.checkString(2);
|
||||
const key = L.checkString(2);
|
||||
|
||||
keymap.keycode = xkb.Keysym.fromName(key, .no_flags);
|
||||
_ = server.keymaps.remove(Keymap.hash(keymap.modifier, keymap.keycode));
|
||||
keymap.keycode = xkb.Keysym.fromName(key, .no_flags);
|
||||
_ = server.keymaps.remove(Keymap.hash(keymap.modifier, keymap.keycode));
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Remove an existing mousemap
|
||||
/// ---@param string modifiers
|
||||
/// ---@param string button
|
||||
pub fn del_mousemap(L: *zlua.Lua) i32 {
|
||||
L.checkType(1, .string);
|
||||
L.checkType(2, .string);
|
||||
L.checkType(1, .string);
|
||||
L.checkType(2, .string);
|
||||
|
||||
var mousemap: Mousemap = undefined;
|
||||
const mod = L.checkString(1);
|
||||
mousemap.modifier = parse_modkeys(mod);
|
||||
var mousemap: Mousemap = undefined;
|
||||
const mod = L.checkString(1);
|
||||
mousemap.modifier = parse_modkeys(mod);
|
||||
|
||||
const button = L.checkString(2);
|
||||
mousemap.event_code = c.libevdev_event_code_from_name(c.EV_KEY, button);
|
||||
const button = L.checkString(2);
|
||||
mousemap.event_code = c.libevdev_event_code_from_name(c.EV_KEY, button);
|
||||
|
||||
_ = server.mousemaps.remove(Mousemap.hash(mousemap.modifier, mousemap.event_code));
|
||||
_ = server.mousemaps.remove(Mousemap.hash(mousemap.modifier, mousemap.event_code));
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Get the repeat information
|
||||
/// ---@return integer[2]
|
||||
pub fn get_repeat_info(L: *zlua.Lua) i32 {
|
||||
L.newTable();
|
||||
L.newTable();
|
||||
|
||||
L.pushInteger(server.seat.keyboard_group.wlr_group.keyboard.repeat_info.rate);
|
||||
L.setField(-2, "rate");
|
||||
L.pushInteger(server.seat.keyboard_group.wlr_group.keyboard.repeat_info.delay);
|
||||
L.setField(-2, "delay");
|
||||
L.pushInteger(server.seat.keyboard_group.wlr_group.keyboard.repeat_info.rate);
|
||||
L.setField(-2, "rate");
|
||||
L.pushInteger(server.seat.keyboard_group.wlr_group.keyboard.repeat_info.delay);
|
||||
L.setField(-2, "delay");
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Set the repeat information
|
||||
/// ---@param integer rate
|
||||
/// ---@param integer delay
|
||||
pub fn set_repeat_info(L: *zlua.Lua) i32 {
|
||||
const rate = LuaUtils.coerceInteger(i32, L.checkInteger(1)) catch {
|
||||
L.raiseErrorStr("The rate must be a valid number", .{});
|
||||
};
|
||||
const delay = LuaUtils.coerceInteger(i32, L.checkInteger(2)) catch {
|
||||
L.raiseErrorStr("The delay must be a valid number", .{});
|
||||
};
|
||||
const rate = LuaUtils.coerceInteger(i32, L.checkInteger(1)) catch {
|
||||
L.raiseErrorStr("The rate must be a valid number", .{});
|
||||
};
|
||||
const delay = LuaUtils.coerceInteger(i32, L.checkInteger(2)) catch {
|
||||
L.raiseErrorStr("The delay must be a valid number", .{});
|
||||
};
|
||||
|
||||
server.seat.keyboard_group.wlr_group.keyboard.setRepeatInfo(rate, delay);
|
||||
return 0;
|
||||
server.seat.keyboard_group.wlr_group.keyboard.setRepeatInfo(rate, delay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ---Set the cursor type
|
||||
/// ---@param string cursor name
|
||||
pub fn set_cursor_type(L: *zlua.Lua) i32 {
|
||||
const name = L.checkString(1);
|
||||
server.cursor.wlr_cursor.setXcursor(server.cursor.x_cursor_manager, name);
|
||||
const name = L.checkString(1);
|
||||
server.cursor.wlr_cursor.setXcursor(server.cursor.x_cursor_manager, name);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
279
src/lua/Lua.zig
279
src/lua/Lua.zig
|
|
@ -6,11 +6,11 @@ const zlua = @import("zlua");
|
|||
|
||||
const LuaUtils = @import("LuaUtils.zig");
|
||||
const Bridge = @import("Bridge.zig");
|
||||
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 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 Output = @import("Output.zig");
|
||||
const Remote = @import("Remote.zig");
|
||||
|
||||
|
|
@ -19,165 +19,168 @@ const gpa = std.heap.c_allocator;
|
|||
state: *zlua.Lua,
|
||||
|
||||
pub fn loadRuntimeDir(self: *zlua.Lua) !void {
|
||||
const path_dir = try std.fs.path.joinZ(gpa, &[_][]const u8{
|
||||
config.runtime_path_prefix,
|
||||
"share",
|
||||
"mezzaluna",
|
||||
});
|
||||
defer gpa.free(path_dir);
|
||||
const path_dir = try std.fs.path.joinZ(gpa, &[_][]const u8{
|
||||
config.runtime_path_prefix,
|
||||
"share",
|
||||
"mezzaluna",
|
||||
});
|
||||
defer gpa.free(path_dir);
|
||||
|
||||
{
|
||||
_ = try self.getGlobal("mez");
|
||||
_ = self.getField(-1, "path");
|
||||
defer self.pop(2);
|
||||
_ = self.pushString(path_dir);
|
||||
self.setField(-2, "runtime");
|
||||
}
|
||||
{
|
||||
_ = try self.getGlobal("mez");
|
||||
_ = self.getField(-1, "path");
|
||||
defer self.pop(2);
|
||||
_ = self.pushString(path_dir);
|
||||
self.setField(-2, "runtime");
|
||||
}
|
||||
|
||||
const path_full = try std.fs.path.joinZ(gpa, &[_][]const u8{
|
||||
path_dir,
|
||||
"init.lua",
|
||||
});
|
||||
defer gpa.free(path_full);
|
||||
const path_full = try std.fs.path.joinZ(gpa, &[_][]const u8{
|
||||
path_dir,
|
||||
"init.lua",
|
||||
});
|
||||
defer gpa.free(path_full);
|
||||
|
||||
self.doFile(path_full) catch {
|
||||
const err = try self.toString(-1);
|
||||
std.log.debug("Failed to run lua file: {s}", .{err});
|
||||
};
|
||||
self.doFile(path_full) catch {
|
||||
const err = try self.toString(-1);
|
||||
std.log.debug("Failed to run lua file: {s}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
pub fn setBaseConfig(self: *zlua.Lua, path: []const u8) !void {
|
||||
{
|
||||
_ = try self.getGlobal("mez");
|
||||
_ = self.getField(-1, "path");
|
||||
defer self.pop(2);
|
||||
const new_path = try std.fs.path.join(gpa, &[_][]const u8{path, "init.lua"});
|
||||
defer gpa.free(new_path);
|
||||
_ = self.pushString(new_path);
|
||||
self.setField(-2, "config");
|
||||
}
|
||||
{
|
||||
_ = try self.getGlobal("mez");
|
||||
_ = self.getField(-1, "path");
|
||||
defer self.pop(2);
|
||||
const cur_path = self.toString(-1) catch "";
|
||||
{
|
||||
_ = try self.getGlobal("mez");
|
||||
_ = self.getField(-1, "path");
|
||||
defer self.pop(2);
|
||||
const new_path = try std.fs.path.join(gpa, &[_][]const u8{ path, "init.lua" });
|
||||
defer gpa.free(new_path);
|
||||
_ = self.pushString(new_path);
|
||||
self.setField(-2, "config");
|
||||
}
|
||||
{
|
||||
_ = try self.getGlobal("mez");
|
||||
_ = self.getField(-1, "path");
|
||||
defer self.pop(2);
|
||||
const cur_path = self.toString(-1) catch "";
|
||||
|
||||
const unsentinel: []const u8 = std.mem.span(cur_path.ptr);
|
||||
const new_path = try std.mem.concat(gpa, u8, &[_][]const u8{
|
||||
unsentinel,
|
||||
";",
|
||||
path,
|
||||
});
|
||||
defer gpa.free(new_path);
|
||||
_ = self.pushString(new_path);
|
||||
_ = self.setField(-2, "path");
|
||||
}
|
||||
const unsentinel: []const u8 = std.mem.span(cur_path.ptr);
|
||||
const new_path = try std.mem.concat(gpa, u8, &[_][]const u8{
|
||||
unsentinel,
|
||||
";",
|
||||
path,
|
||||
});
|
||||
defer gpa.free(new_path);
|
||||
_ = self.pushString(new_path);
|
||||
_ = self.setField(-2, "path");
|
||||
}
|
||||
}
|
||||
|
||||
fn loadBaseConfig(self: *zlua.Lua) !void {
|
||||
const lua_path = "mez.path.base_config";
|
||||
if (!Bridge.getNestedField(self, @constCast(lua_path[0..]))) {
|
||||
std.log.err("Base config path not found. is your runtime dir setup?", .{});
|
||||
return;
|
||||
}
|
||||
const path = self.toString(-1) catch |err| {
|
||||
std.log.err("Failed to pop the base config path from the lua stack. {}", .{err});
|
||||
return;
|
||||
};
|
||||
self.pop(-1);
|
||||
try self.doFile(path);
|
||||
const lua_path = "mez.path.base_config";
|
||||
if (!Bridge.getNestedField(self, @constCast(lua_path[0..]))) {
|
||||
std.log.err("Base config path not found. is your runtime dir setup?", .{});
|
||||
return;
|
||||
}
|
||||
const path = self.toString(-1) catch |err| {
|
||||
std.log.err("Failed to pop the base config path from the lua stack. {}", .{err});
|
||||
return;
|
||||
};
|
||||
self.pop(-1);
|
||||
try self.doFile(path);
|
||||
}
|
||||
|
||||
fn loadConfigDir(self: *zlua.Lua) !void {
|
||||
const lua_path = "mez.path.config";
|
||||
if (!Bridge.getNestedField(self, @constCast(lua_path[0..]))) {
|
||||
std.log.err("Config path not found. is your runtime dir setup?", .{});
|
||||
return;
|
||||
}
|
||||
const path = self.toString(-1) catch |err| {
|
||||
std.log.err("Failed to pop the config path from the lua stack. {}", .{err});
|
||||
return;
|
||||
};
|
||||
self.pop(-1);
|
||||
try self.doFile(path);
|
||||
const lua_path = "mez.path.config";
|
||||
if (!Bridge.getNestedField(self, @constCast(lua_path[0..]))) {
|
||||
std.log.err("Config path not found. is your runtime dir setup?", .{});
|
||||
return;
|
||||
}
|
||||
const path = self.toString(-1) catch |err| {
|
||||
std.log.err("Failed to pop the config path from the lua stack. {}", .{err});
|
||||
return;
|
||||
};
|
||||
self.pop(-1);
|
||||
try self.doFile(path);
|
||||
}
|
||||
|
||||
pub fn openLibs(self: *zlua.Lua) void {
|
||||
{
|
||||
self.newTable();
|
||||
defer _ = self.setGlobal("mez");
|
||||
{
|
||||
self.newTable();
|
||||
defer _ = self.setField(-2, "path");
|
||||
self.newTable();
|
||||
defer _ = self.setGlobal("mez");
|
||||
{
|
||||
self.newTable();
|
||||
defer _ = self.setField(-2, "path");
|
||||
}
|
||||
{
|
||||
const fs_funcs = zlua.fnRegsFromType(Fs);
|
||||
LuaUtils.newLib(self, fs_funcs);
|
||||
self.setField(-2, "fs");
|
||||
}
|
||||
{
|
||||
const input_funcs = zlua.fnRegsFromType(Input);
|
||||
LuaUtils.newLib(self, input_funcs);
|
||||
self.setField(-2, "input");
|
||||
}
|
||||
{
|
||||
const hook_funcs = zlua.fnRegsFromType(Hook);
|
||||
LuaUtils.newLib(self, hook_funcs);
|
||||
self.setField(-2, "hook");
|
||||
}
|
||||
{
|
||||
const api_funcs = zlua.fnRegsFromType(Api);
|
||||
LuaUtils.newLib(self, api_funcs);
|
||||
self.setField(-2, "api");
|
||||
}
|
||||
{
|
||||
const view_funcs = zlua.fnRegsFromType(View);
|
||||
LuaUtils.newLib(self, view_funcs);
|
||||
self.setField(-2, "view");
|
||||
}
|
||||
{
|
||||
const output_funcs = zlua.fnRegsFromType(Output);
|
||||
LuaUtils.newLib(self, output_funcs);
|
||||
self.setField(-2, "output");
|
||||
}
|
||||
{
|
||||
const remote_funcs = zlua.fnRegsFromType(Remote);
|
||||
LuaUtils.newLib(self, remote_funcs);
|
||||
self.setField(-2, "remote");
|
||||
}
|
||||
}
|
||||
{
|
||||
const fs_funcs = zlua.fnRegsFromType(Fs);
|
||||
LuaUtils.newLib(self, fs_funcs);
|
||||
self.setField(-2, "fs");
|
||||
}
|
||||
{
|
||||
const input_funcs = zlua.fnRegsFromType(Input);
|
||||
LuaUtils.newLib(self, input_funcs);
|
||||
self.setField(-2, "input");
|
||||
}
|
||||
{
|
||||
const hook_funcs = zlua.fnRegsFromType(Hook);
|
||||
LuaUtils.newLib(self, hook_funcs);
|
||||
self.setField(-2, "hook");
|
||||
}
|
||||
{
|
||||
const api_funcs = zlua.fnRegsFromType(Api);
|
||||
LuaUtils.newLib(self, api_funcs);
|
||||
self.setField(-2, "api");
|
||||
}
|
||||
{
|
||||
const view_funcs = zlua.fnRegsFromType(View);
|
||||
LuaUtils.newLib(self, view_funcs);
|
||||
self.setField(-2, "view");
|
||||
}
|
||||
{
|
||||
const output_funcs = zlua.fnRegsFromType(Output);
|
||||
LuaUtils.newLib(self, output_funcs);
|
||||
self.setField(-2, "output");
|
||||
}
|
||||
{
|
||||
const remote_funcs = zlua.fnRegsFromType(Remote);
|
||||
LuaUtils.newLib(self, remote_funcs);
|
||||
self.setField(-2, "remote");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const Config = struct { str: ?[]const u8, enabled: bool, };
|
||||
pub const Config = struct {
|
||||
str: ?[]const u8,
|
||||
enabled: bool,
|
||||
};
|
||||
pub fn init(self: *Lua, cfg: Config) !void {
|
||||
self.state = try zlua.Lua.init(gpa);
|
||||
errdefer self.state.deinit();
|
||||
self.state.openLibs();
|
||||
self.state = try zlua.Lua.init(gpa);
|
||||
errdefer self.state.deinit();
|
||||
self.state.openLibs();
|
||||
|
||||
openLibs(self.state);
|
||||
openLibs(self.state);
|
||||
|
||||
if (!cfg.enabled) try setBaseConfig(self.state, "");
|
||||
loadRuntimeDir(self.state) catch |err| if (err == error.LuaRuntime) {
|
||||
std.log.warn("{s}", .{try self.state.toString(-1)});
|
||||
};
|
||||
|
||||
loadBaseConfig(self.state) catch |err| if (err == error.LuaRuntime) {
|
||||
std.log.warn("{s}", .{try self.state.toString(-1)});
|
||||
};
|
||||
|
||||
if (cfg.str) |path| {
|
||||
defer gpa.free(path);
|
||||
try setBaseConfig(self.state, path);
|
||||
}
|
||||
if (cfg.enabled) {
|
||||
loadConfigDir(self.state) catch |err| if (err == error.LuaRuntime) {
|
||||
std.log.warn("{s}", .{try self.state.toString(-1)});
|
||||
if (!cfg.enabled) try setBaseConfig(self.state, "");
|
||||
loadRuntimeDir(self.state) catch |err| if (err == error.LuaRuntime) {
|
||||
std.log.warn("{s}", .{try self.state.toString(-1)});
|
||||
};
|
||||
}
|
||||
|
||||
std.log.debug("Loaded lua", .{});
|
||||
loadBaseConfig(self.state) catch |err| if (err == error.LuaRuntime) {
|
||||
std.log.warn("{s}", .{try self.state.toString(-1)});
|
||||
};
|
||||
|
||||
if (cfg.str) |path| {
|
||||
defer gpa.free(path);
|
||||
try setBaseConfig(self.state, path);
|
||||
}
|
||||
if (cfg.enabled) {
|
||||
loadConfigDir(self.state) catch |err| if (err == error.LuaRuntime) {
|
||||
std.log.warn("{s}", .{try self.state.toString(-1)});
|
||||
};
|
||||
}
|
||||
|
||||
std.log.debug("Loaded lua", .{});
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Lua) void {
|
||||
self.state.deinit();
|
||||
self.state.deinit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,53 +8,53 @@ const View = @import("../View.zig");
|
|||
const server = &@import("../main.zig").server;
|
||||
|
||||
pub fn coerceNumber(comptime x: type, number: zlua.Number) error{InvalidNumber}!x {
|
||||
if (number < std.math.minInt(x) or number > std.math.maxInt(x) or std.math.isNan(number)) {
|
||||
return error.InvalidNumber;
|
||||
}
|
||||
switch (@typeInfo(x)) {
|
||||
.int => return @as(x, @intFromFloat(number)),
|
||||
.float => return @floatCast(number),
|
||||
else => @compileError("unsupported type"),
|
||||
}
|
||||
if (number < std.math.minInt(x) or number > std.math.maxInt(x) or std.math.isNan(number)) {
|
||||
return error.InvalidNumber;
|
||||
}
|
||||
switch (@typeInfo(x)) {
|
||||
.int => return @as(x, @intFromFloat(number)),
|
||||
.float => return @floatCast(number),
|
||||
else => @compileError("unsupported type"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn coerceInteger(comptime x: type, number: zlua.Integer) error{InvalidInteger}!x {
|
||||
if (number < std.math.minInt(x) or number > std.math.maxInt(x) or std.math.isNan(number)) {
|
||||
return error.InvalidInteger;
|
||||
}
|
||||
switch (@typeInfo(x)) {
|
||||
.int => return @intCast(number),
|
||||
.float => return @as(x, @floatFromInt(number)),
|
||||
else => @compileError("unsupported type"),
|
||||
}
|
||||
if (number < std.math.minInt(x) or number > std.math.maxInt(x) or std.math.isNan(number)) {
|
||||
return error.InvalidInteger;
|
||||
}
|
||||
switch (@typeInfo(x)) {
|
||||
.int => return @intCast(number),
|
||||
.float => return @as(x, @floatFromInt(number)),
|
||||
else => @compileError("unsupported type"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn newLib(L: *zlua.Lua, f: []const zlua.FnReg) void {
|
||||
L.newLibTable(f); // documented as being unavailable, but it is.
|
||||
for (f) |value| {
|
||||
if (value.func == null) continue;
|
||||
L.pushClosure(value.func.?, 0);
|
||||
L.setField(-2, value.name);
|
||||
}
|
||||
L.newLibTable(f); // documented as being unavailable, but it is.
|
||||
for (f) |value| {
|
||||
if (value.func == null) continue;
|
||||
L.pushClosure(value.func.?, 0);
|
||||
L.setField(-2, value.name);
|
||||
}
|
||||
}
|
||||
|
||||
/// makes a best effort to convert the value at the top of the stack to a string
|
||||
/// if we're unable to do so return "nil"
|
||||
pub fn toStringEx(L: *zlua.Lua) [:0]const u8 {
|
||||
const errstr = "nil";
|
||||
_ = L.getGlobal("tostring") catch return errstr;
|
||||
L.insert(1);
|
||||
L.protectedCall(.{ .args = 1, .results = 1 }) catch return errstr;
|
||||
return L.toString(-1) catch errstr;
|
||||
const errstr = "nil";
|
||||
_ = L.getGlobal("tostring") catch return errstr;
|
||||
L.insert(1);
|
||||
L.protectedCall(.{ .args = 1, .results = 1 }) catch return errstr;
|
||||
return L.toString(-1) catch errstr;
|
||||
}
|
||||
|
||||
pub fn viewById(view_id: u64) ?*View {
|
||||
if (view_id == 0) {
|
||||
if(server.seat.focused_surface) |fs| {
|
||||
if(fs == .view) return fs.view;
|
||||
if (view_id == 0) {
|
||||
if (server.seat.focused_surface) |fs| {
|
||||
if (fs == .view) return fs.view;
|
||||
}
|
||||
} else {
|
||||
return server.root.viewById(view_id);
|
||||
}
|
||||
} else {
|
||||
return server.root.viewById(view_id);
|
||||
}
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,181 +7,180 @@ const LuaUtils = @import("LuaUtils.zig");
|
|||
const server = &@import("../main.zig").server;
|
||||
|
||||
fn output_id_err(L: *zlua.Lua) noreturn {
|
||||
L.raiseErrorStr("The output id must be >= 0 and < inf", .{});
|
||||
L.raiseErrorStr("The output id must be >= 0 and < inf", .{});
|
||||
}
|
||||
|
||||
/// ---@alias output_id integer
|
||||
|
||||
/// ---Get the ids for all available outputs
|
||||
/// ---@return output_id[]?
|
||||
pub fn get_all_ids(L: *zlua.Lua) i32 {
|
||||
var it = server.root.scene.outputs.iterator(.forward);
|
||||
var index: usize = 1;
|
||||
var it = server.root.scene.outputs.iterator(.forward);
|
||||
var index: usize = 1;
|
||||
|
||||
L.newTable();
|
||||
L.newTable();
|
||||
|
||||
while(it.next()) |scene_output| : (index += 1) {
|
||||
if(scene_output.output.data == null) continue;
|
||||
while (it.next()) |scene_output| : (index += 1) {
|
||||
if (scene_output.output.data == null) continue;
|
||||
|
||||
const output = @as(*Output, @ptrCast(@alignCast(scene_output.output.data.?)));
|
||||
const output = @as(*Output, @ptrCast(@alignCast(scene_output.output.data.?)));
|
||||
|
||||
L.pushInteger(@intCast(index));
|
||||
L.pushInteger(@intCast(output.id));
|
||||
L.setTable(-3);
|
||||
}
|
||||
L.pushInteger(@intCast(index));
|
||||
L.pushInteger(@intCast(output.id));
|
||||
L.setTable(-3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Get the id for the focused output
|
||||
/// ---@return output_id?
|
||||
pub fn get_focused_id(L: *zlua.Lua) i32 {
|
||||
if(server.seat.focused_output) |output| {
|
||||
L.pushInteger(@intCast(output.id));
|
||||
return 1;
|
||||
}
|
||||
if (server.seat.focused_output) |output| {
|
||||
L.pushInteger(@intCast(output.id));
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Get refresh rate for the output
|
||||
/// ---@param output_id output_id 0 maps to focused output
|
||||
/// ---@return integer?
|
||||
pub fn get_rate(L: *zlua.Lua) i32 {
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if(output) |o| {
|
||||
L.pushInteger(@intCast(o.wlr_output.refresh));
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if (output) |o| {
|
||||
L.pushInteger(@intCast(o.wlr_output.refresh));
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Get resolution in pixels of the output
|
||||
/// ---@param output_id output_id 0 maps to focused output
|
||||
/// ---@return { width: integer, height: integer }?
|
||||
pub fn get_resolution(L: *zlua.Lua) i32 {
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if(output) |o| {
|
||||
L.newTable();
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if (output) |o| {
|
||||
L.newTable();
|
||||
|
||||
_ = L.pushString("width");
|
||||
L.pushInteger(@intCast(o.wlr_output.width));
|
||||
L.setTable(-3);
|
||||
_ = L.pushString("width");
|
||||
L.pushInteger(@intCast(o.wlr_output.width));
|
||||
L.setTable(-3);
|
||||
|
||||
_ = L.pushString("height");
|
||||
L.pushInteger(@intCast(o.wlr_output.height));
|
||||
L.setTable(-3);
|
||||
_ = L.pushString("height");
|
||||
L.pushInteger(@intCast(o.wlr_output.height));
|
||||
L.setTable(-3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Get the serial for the output
|
||||
/// ---@param output_id output_id 0 maps to focused output
|
||||
/// ---@return string?
|
||||
pub fn get_serial(L: *zlua.Lua) i32 {
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if(output) |o| {
|
||||
if(o.wlr_output.serial == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if (output) |o| {
|
||||
if (o.wlr_output.serial == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.serial.?));
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.serial.?));
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Get the make for the output
|
||||
/// ---@param output_id output_id 0 maps to focused output
|
||||
/// ---@return string?
|
||||
pub fn get_make(L: *zlua.Lua) i32 {
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if(output) |o| {
|
||||
if(o.wlr_output.make == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if (output) |o| {
|
||||
if (o.wlr_output.make == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.make.?));
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.make.?));
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Get the model for the output
|
||||
/// ---@param output_id output_id 0 maps to focused output
|
||||
/// ---@return stirng?
|
||||
pub fn get_model(L: *zlua.Lua) i32 {
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if(output) |o| {
|
||||
if(o.wlr_output.model == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if (output) |o| {
|
||||
if (o.wlr_output.model == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.model.?));
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.model.?));
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Get the description for the output
|
||||
/// ---@param output_id output_id 0 maps to focused output
|
||||
/// ---@return stirng?
|
||||
pub fn get_description(L: *zlua.Lua) i32 {
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if(output) |o| {
|
||||
if(o.wlr_output.description == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if (output) |o| {
|
||||
if (o.wlr_output.description == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.description.?));
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.description.?));
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// ---Get the name of the output
|
||||
/// ---@param output_id output_id 0 maps to focused output
|
||||
/// ---@return stirng
|
||||
pub fn get_name(L: *zlua.Lua) i32 {
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
const output_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch output_id_err(L);
|
||||
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if(output) |o| {
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.name));
|
||||
const output: ?*Output = if (output_id == 0) server.seat.focused_output else server.root.outputById(output_id);
|
||||
if (output) |o| {
|
||||
_ = L.pushString(std.mem.span(o.wlr_output.name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ const LuaUtils = @import("LuaUtils.zig");
|
|||
const RemoteLua = @import("../RemoteLua.zig");
|
||||
|
||||
pub fn print(L: *zlua.Lua) i32 {
|
||||
RemoteLua.sendNewLogEntry(L.checkString(1));
|
||||
return 0;
|
||||
RemoteLua.sendNewLogEntry(L.checkString(1));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
421
src/lua/View.zig
421
src/lua/View.zig
|
|
@ -11,7 +11,7 @@ const LuaUtils = @import("LuaUtils.zig");
|
|||
const server = &@import("../main.zig").server;
|
||||
|
||||
fn view_id_err(L: *zlua.Lua) noreturn {
|
||||
L.raiseErrorStr("The view id must be >= 0 and < inf", .{});
|
||||
L.raiseErrorStr("The view id must be >= 0 and < inf", .{});
|
||||
}
|
||||
|
||||
// This allows us to differentiate random numbers from ids
|
||||
|
|
@ -20,84 +20,83 @@ fn view_id_err(L: *zlua.Lua) noreturn {
|
|||
// ---Get the ids for all available views
|
||||
// ---@return view_id[]?
|
||||
pub fn get_all_ids(L: *zlua.Lua) i32 {
|
||||
var output_it = server.root.output_layout.outputs.iterator(.forward);
|
||||
var output_it = server.root.output_layout.outputs.iterator(.forward);
|
||||
|
||||
var index: i32 = 1;
|
||||
L.newTable();
|
||||
var index: i32 = 1;
|
||||
L.newTable();
|
||||
|
||||
while(output_it.next()) |o| {
|
||||
if(o.output.data == null) {
|
||||
std.log.err("Output arbitrary data not assigned", .{});
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const output: *Output = @ptrCast(@alignCast(o.output.data.?));
|
||||
if (!output.state.enabled) continue;
|
||||
|
||||
// Only search the content and fullscreen layers for views
|
||||
const layers = [_]*wlr.SceneTree{
|
||||
output.layers.content,
|
||||
output.layers.fullscreen,
|
||||
};
|
||||
|
||||
for(layers) |layer| {
|
||||
if(layer.children.length() == 0) continue; // No children
|
||||
|
||||
if(@intFromPtr(layer) == 0) {
|
||||
std.log.err("ts is literally a null ptr", .{});
|
||||
unreachable;
|
||||
}
|
||||
|
||||
var view_it = layer.children.iterator(.forward);
|
||||
|
||||
while(view_it.next()) |v| {
|
||||
|
||||
if(v.data == null) {
|
||||
std.log.err("Unassigned arbitrary data in scene graph", .{});
|
||||
unreachable;
|
||||
while (output_it.next()) |o| {
|
||||
if (o.output.data == null) {
|
||||
std.log.err("Output arbitrary data not assigned", .{});
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(v.data.?));
|
||||
const output: *Output = @ptrCast(@alignCast(o.output.data.?));
|
||||
if (!output.state.enabled) continue;
|
||||
|
||||
if(scene_node_data.* == .view) {
|
||||
L.pushInteger(@intCast(index));
|
||||
L.pushInteger(@intCast(scene_node_data.view.id));
|
||||
L.setTable(-3);
|
||||
// Only search the content and fullscreen layers for views
|
||||
const layers = [_]*wlr.SceneTree{
|
||||
output.layers.content,
|
||||
output.layers.fullscreen,
|
||||
};
|
||||
|
||||
index += 1;
|
||||
for (layers) |layer| {
|
||||
if (layer.children.length() == 0) continue; // No children
|
||||
|
||||
if (@intFromPtr(layer) == 0) {
|
||||
std.log.err("ts is literally a null ptr", .{});
|
||||
unreachable;
|
||||
}
|
||||
|
||||
var view_it = layer.children.iterator(.forward);
|
||||
|
||||
while (view_it.next()) |v| {
|
||||
if (v.data == null) {
|
||||
std.log.err("Unassigned arbitrary data in scene graph", .{});
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const scene_node_data: *SceneNodeData = @ptrCast(@alignCast(v.data.?));
|
||||
|
||||
if (scene_node_data.* == .view) {
|
||||
L.pushInteger(@intCast(index));
|
||||
L.pushInteger(@intCast(scene_node_data.view.id));
|
||||
L.setTable(-3);
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Get the id for the focused view
|
||||
// ---@return view_id?
|
||||
pub fn get_focused_id(L: *zlua.Lua) i32 {
|
||||
if(server.seat.focused_surface) |fs| {
|
||||
if(fs == .view) {
|
||||
L.pushInteger(@intCast(fs.view.id));
|
||||
return 1;
|
||||
if (server.seat.focused_surface) |fs| {
|
||||
if (fs == .view) {
|
||||
L.pushInteger(@intCast(fs.view.id));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Close the view with view_id
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
pub fn close(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
|
||||
if(LuaUtils.viewById(view_id)) |v| {
|
||||
v.close();
|
||||
}
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
v.close();
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---position the view by it's top left corner
|
||||
|
|
@ -105,39 +104,39 @@ pub fn close(L: *zlua.Lua) i32 {
|
|||
// ---@param x number x position for view
|
||||
// ---@param y number y position for view
|
||||
pub fn set_position(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
const x = LuaUtils.coerceNumber(i32, L.checkNumber(2)) catch L.raiseErrorStr("The x must be > -inf and < inf", .{});
|
||||
const y = LuaUtils.coerceNumber(i32, L.checkNumber(3)) catch L.raiseErrorStr("The y must be > -inf and < inf", .{});
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
const x = LuaUtils.coerceNumber(i32, L.checkNumber(2)) catch L.raiseErrorStr("The x must be > -inf and < inf", .{});
|
||||
const y = LuaUtils.coerceNumber(i32, L.checkNumber(3)) catch L.raiseErrorStr("The y must be > -inf and < inf", .{});
|
||||
|
||||
if(LuaUtils.viewById(view_id)) |v| {
|
||||
v.setPosition(x, y);
|
||||
}
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
v.setPosition(x, y);
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Get the position of the view
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
// ---@return { x: integer, y: integer }? Position of the view
|
||||
pub fn get_position(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
L.newTable();
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
L.newTable();
|
||||
|
||||
_ = L.pushString("x");
|
||||
L.pushInteger(@intCast(v.scene_tree.node.x));
|
||||
L.setTable(-3);
|
||||
_ = L.pushString("x");
|
||||
L.pushInteger(@intCast(v.scene_tree.node.x));
|
||||
L.setTable(-3);
|
||||
|
||||
_ = L.pushString("y");
|
||||
L.pushInteger(@intCast(v.scene_tree.node.y));
|
||||
L.setTable(-3);
|
||||
_ = L.pushString("y");
|
||||
L.pushInteger(@intCast(v.scene_tree.node.y));
|
||||
L.setTable(-3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Set the size of the spesified view. Will be resized relative to
|
||||
|
|
@ -145,234 +144,234 @@ pub fn get_position(L: *zlua.Lua) i32 {
|
|||
// ---@param view_id view_id 0 maps to focused view
|
||||
// ---@return
|
||||
pub fn set_size(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
// We use u32s here to enforce a minimum size of zero. The call to resize a
|
||||
// toplevel requires a i32, which doesn't make too much sense as there's an
|
||||
// assertion in the code enforcing that both the width and height are greater
|
||||
// than or equal to zero.
|
||||
const width = LuaUtils.coerceNumber(u32, L.checkNumber(2)) catch L.raiseErrorStr("The width must be >= 0 and < inf", .{});
|
||||
const height = LuaUtils.coerceNumber(u32, L.checkNumber(3)) catch L.raiseErrorStr("The height must be >= 0 and < inf", .{});
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
// We use u32s here to enforce a minimum size of zero. The call to resize a
|
||||
// toplevel requires a i32, which doesn't make too much sense as there's an
|
||||
// assertion in the code enforcing that both the width and height are greater
|
||||
// than or equal to zero.
|
||||
const width = LuaUtils.coerceNumber(u32, L.checkNumber(2)) catch L.raiseErrorStr("The width must be >= 0 and < inf", .{});
|
||||
const height = LuaUtils.coerceNumber(u32, L.checkNumber(3)) catch L.raiseErrorStr("The height must be >= 0 and < inf", .{});
|
||||
|
||||
if(LuaUtils.viewById(view_id)) |v| {
|
||||
v.setSize(@intCast(width), @intCast(height));
|
||||
}
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
v.setSize(@intCast(width), @intCast(height));
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Get the size of the view
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
// ---@return { width: integer, height: integer }? Size of the view
|
||||
pub fn get_size(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
L.newTable();
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
L.newTable();
|
||||
|
||||
_ = L.pushString("width");
|
||||
L.pushInteger(@intCast(v.xdg_toplevel.current.width));
|
||||
L.setTable(-3);
|
||||
_ = L.pushString("width");
|
||||
L.pushInteger(@intCast(v.xdg_toplevel.current.width));
|
||||
L.setTable(-3);
|
||||
|
||||
_ = L.pushString("height");
|
||||
L.pushInteger(@intCast(v.xdg_toplevel.current.height));
|
||||
L.setTable(-3);
|
||||
_ = L.pushString("height");
|
||||
L.pushInteger(@intCast(v.xdg_toplevel.current.height));
|
||||
L.setTable(-3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Remove focus from current view, and set to given id
|
||||
// ---@param view_id view_id Id of the view to be focused, or nil to remove focus
|
||||
pub fn set_focused(L: *zlua.Lua) i32 {
|
||||
const view_id: ?c_longlong = L.optInteger(1);
|
||||
const view_id: ?c_longlong = L.optInteger(1);
|
||||
|
||||
if(view_id == null) {
|
||||
server.seat.focusSurface(null);
|
||||
} else if(server.root.viewById(@intCast(view_id.?))) |view| {
|
||||
server.seat.focusSurface(.{ .view = view });
|
||||
}
|
||||
if (view_id == null) {
|
||||
server.seat.focusSurface(null);
|
||||
} else if (server.root.viewById(@intCast(view_id.?))) |view| {
|
||||
server.seat.focusSurface(.{ .view = view });
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Toggle the view to enter fullscreen. Will enter the fullsreen
|
||||
// layer.
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
pub fn toggle_fullscreen(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
|
||||
std.log.debug("fullscreen view {d}", .{view_id});
|
||||
if(LuaUtils.viewById(view_id)) |v| {
|
||||
std.log.debug("toggling fullscreen", .{});
|
||||
v.toggleFullscreen();
|
||||
}
|
||||
std.log.debug("fullscreen view {d}", .{view_id});
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
std.log.debug("toggling fullscreen", .{});
|
||||
v.toggleFullscreen();
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Get the title of the view
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
// ---@return string?
|
||||
pub fn get_title(L: *zlua.Lua) i32 {
|
||||
const view_id: u64 = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
const view_id: u64 = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
|
||||
if(LuaUtils.viewById(view_id)) |v| {
|
||||
if(v.xdg_toplevel.title == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
if (v.xdg_toplevel.title == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(v.xdg_toplevel.title.?));
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(v.xdg_toplevel.title.?));
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Get the app_id of the view
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
// ---@return string?
|
||||
pub fn get_app_id(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
|
||||
if(LuaUtils.viewById(view_id)) |v| {
|
||||
if(v.xdg_toplevel.app_id == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
if (v.xdg_toplevel.app_id == null) {
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(v.xdg_toplevel.app_id.?));
|
||||
return 1;
|
||||
}
|
||||
|
||||
_ = L.pushString(std.mem.span(v.xdg_toplevel.app_id.?));
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Enable or disable a view
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
// ---@param enabled boolean
|
||||
pub fn set_enabled(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
if (!L.isBoolean(2)) {
|
||||
L.raiseErrorStr("argument 2 must be a boolean", .{});
|
||||
}
|
||||
const activate = L.toBoolean(2);
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
if (!L.isBoolean(2)) {
|
||||
L.raiseErrorStr("argument 2 must be a boolean", .{});
|
||||
}
|
||||
const activate = L.toBoolean(2);
|
||||
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
_ = v.xdg_toplevel.setActivated(activate);
|
||||
return 0;
|
||||
}
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
_ = v.xdg_toplevel.setActivated(activate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Check if a view is enabled
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
// ---@return boolean?
|
||||
pub fn get_enabled(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
|
||||
if(LuaUtils.viewById(view_id)) |v| {
|
||||
_ = L.pushBoolean(v.xdg_toplevel.current.activated);
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
_ = L.pushBoolean(v.xdg_toplevel.current.activated);
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Set a view you intend to resize
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
// ---@param enable boolean
|
||||
pub fn set_resizing(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
if (!L.isBoolean(2)) {
|
||||
L.raiseErrorStr("argument 2 must be a boolean", .{});
|
||||
}
|
||||
const resizing = L.toBoolean(2);
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
if (!L.isBoolean(2)) {
|
||||
L.raiseErrorStr("argument 2 must be a boolean", .{});
|
||||
}
|
||||
const resizing = L.toBoolean(2);
|
||||
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
_ = v.xdg_toplevel.setResizing(resizing);
|
||||
return 0;
|
||||
}
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
_ = v.xdg_toplevel.setResizing(resizing);
|
||||
return 0;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---Check if a view is resizing
|
||||
// ---@param view_id view_id 0 maps to focused view
|
||||
// ---@return boolean? nil if view cannot be found
|
||||
pub fn get_resizing(L: *zlua.Lua) i32 {
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
const view_id = LuaUtils.coerceInteger(u64, L.checkInteger(1)) catch view_id_err(L);
|
||||
|
||||
if(LuaUtils.viewById(view_id)) |v| {
|
||||
_ = L.pushBoolean(v.xdg_toplevel.current.resizing);
|
||||
if (LuaUtils.viewById(view_id)) |v| {
|
||||
_ = L.pushBoolean(v.xdg_toplevel.current.resizing);
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
return 1;
|
||||
}
|
||||
|
||||
L.pushNil();
|
||||
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);
|
||||
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", .{});
|
||||
_ = 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 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;
|
||||
}
|
||||
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;
|
||||
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 };
|
||||
};
|
||||
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", .{});
|
||||
};
|
||||
_ = 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 (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();
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// TODO: impl
|
||||
|
|
@ -383,6 +382,6 @@ pub fn set_border(L: *zlua.Lua) i32 {
|
|||
/// NOTE(squibid): this should be handled by the layout_manager to reduce the
|
||||
/// work required by the user
|
||||
pub fn setWmCapabilities(L: *zlua.Lua) i32 {
|
||||
_ = L;
|
||||
return 0;
|
||||
_ = L;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
106
src/main.zig
106
src/main.zig
|
|
@ -27,66 +27,66 @@ const args =
|
|||
;
|
||||
|
||||
pub fn main() !void {
|
||||
const params = comptime clap.parseParamsComptime(args);
|
||||
var diag = clap.Diagnostic{};
|
||||
const parsers = comptime .{
|
||||
.path = clap.parsers.string,
|
||||
.command = clap.parsers.string,
|
||||
};
|
||||
var res = clap.parse(clap.Help, ¶ms, parsers, .{
|
||||
.diagnostic = &diag,
|
||||
.allocator = gpa,
|
||||
}) catch |err| {
|
||||
try diag.reportToFile(.stderr(), err);
|
||||
return err;
|
||||
};
|
||||
defer res.deinit();
|
||||
const params = comptime clap.parseParamsComptime(args);
|
||||
var diag = clap.Diagnostic{};
|
||||
const parsers = comptime .{
|
||||
.path = clap.parsers.string,
|
||||
.command = clap.parsers.string,
|
||||
};
|
||||
var res = clap.parse(clap.Help, ¶ms, parsers, .{
|
||||
.diagnostic = &diag,
|
||||
.allocator = gpa,
|
||||
}) catch |err| {
|
||||
try diag.reportToFile(.stderr(), err);
|
||||
return err;
|
||||
};
|
||||
defer res.deinit();
|
||||
|
||||
if (res.args.help == 1) {
|
||||
try @constCast(&std.fs.File.stdout().writer(&[_]u8{}).interface).writeAll(usage);
|
||||
std.process.exit(0);
|
||||
}
|
||||
if (res.args.version == 1) {
|
||||
try @constCast(&std.fs.File.stdout().writer(&[_]u8{}).interface).writeAll(config.version);
|
||||
std.process.exit(0);
|
||||
}
|
||||
if (res.args.help == 1) {
|
||||
try @constCast(&std.fs.File.stdout().writer(&[_]u8{}).interface).writeAll(usage);
|
||||
std.process.exit(0);
|
||||
}
|
||||
if (res.args.version == 1) {
|
||||
try @constCast(&std.fs.File.stdout().writer(&[_]u8{}).interface).writeAll(config.version);
|
||||
std.process.exit(0);
|
||||
}
|
||||
|
||||
var lua_config: Lua.Config = .{ .enabled = true, .str = null };
|
||||
if (res.args.u != null and res.args.clean == 1) {
|
||||
std.debug.panic("You cannot set both -u and --clean", .{});
|
||||
} else if (res.args.u != null) {
|
||||
// this is freed in lua/lua.zig
|
||||
const path = try std.fs.cwd().realpathAlloc(gpa, res.args.u.?);
|
||||
lua_config.str = path;
|
||||
} else if (res.args.clean == 1) {
|
||||
lua_config.enabled = false;
|
||||
}
|
||||
var lua_config: Lua.Config = .{ .enabled = true, .str = null };
|
||||
if (res.args.u != null and res.args.clean == 1) {
|
||||
std.debug.panic("You cannot set both -u and --clean", .{});
|
||||
} else if (res.args.u != null) {
|
||||
// this is freed in lua/lua.zig
|
||||
const path = try std.fs.cwd().realpathAlloc(gpa, res.args.u.?);
|
||||
lua_config.str = path;
|
||||
} else if (res.args.clean == 1) {
|
||||
lua_config.enabled = false;
|
||||
}
|
||||
|
||||
wlr.log.init(.err, null);
|
||||
std.log.info("Starting mezzaluna", .{});
|
||||
wlr.log.init(.err, null);
|
||||
std.log.info("Starting mezzaluna", .{});
|
||||
|
||||
server.init();
|
||||
defer server.deinit();
|
||||
try lua.init(lua_config);
|
||||
server.init();
|
||||
defer server.deinit();
|
||||
try lua.init(lua_config);
|
||||
|
||||
var buf: [11]u8 = undefined;
|
||||
const socket = try server.wl_server.addSocketAuto(&buf);
|
||||
var buf: [11]u8 = undefined;
|
||||
const socket = try server.wl_server.addSocketAuto(&buf);
|
||||
|
||||
env_map = try std.process.getEnvMap(gpa);
|
||||
try env_map.put("WAYLAND_DISPLAY", socket);
|
||||
env_map = try std.process.getEnvMap(gpa);
|
||||
try env_map.put("WAYLAND_DISPLAY", socket);
|
||||
|
||||
if (res.args.c) |cmd| {
|
||||
var child = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", cmd }, gpa);
|
||||
child.env_map = &env_map;
|
||||
try child.spawn();
|
||||
}
|
||||
defer env_map.deinit();
|
||||
if (res.args.c) |cmd| {
|
||||
var child = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", cmd }, gpa);
|
||||
child.env_map = &env_map;
|
||||
try child.spawn();
|
||||
}
|
||||
defer env_map.deinit();
|
||||
|
||||
std.log.info("Starting backend", .{});
|
||||
server.backend.start() catch |err| {
|
||||
std.debug.panic("Failed to start backend: {}", .{err});
|
||||
};
|
||||
std.log.info("Starting backend", .{});
|
||||
server.backend.start() catch |err| {
|
||||
std.debug.panic("Failed to start backend: {}", .{err});
|
||||
};
|
||||
|
||||
std.log.info("Starting server", .{});
|
||||
server.wl_server.run();
|
||||
std.log.info("Starting server", .{});
|
||||
server.wl_server.run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,53 +7,53 @@ const Hook = @import("Hook.zig");
|
|||
const server = &@import("../main.zig").server;
|
||||
|
||||
const Node = struct {
|
||||
hook: *const Hook,
|
||||
node: std.SinglyLinkedList.Node,
|
||||
hook: *const Hook,
|
||||
node: std.SinglyLinkedList.Node,
|
||||
};
|
||||
|
||||
events: std.StringHashMap(*std.SinglyLinkedList),
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) !Events {
|
||||
return Events{
|
||||
.allocator = allocator,
|
||||
.events = .init(allocator),
|
||||
};
|
||||
return Events{
|
||||
.allocator = allocator,
|
||||
.events = .init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn put(self: *Events, key: []const u8, hook: *const Hook) !void {
|
||||
var ll: *std.SinglyLinkedList = undefined;
|
||||
if (self.events.get(key)) |sll| {
|
||||
ll = sll;
|
||||
} else {
|
||||
ll = try self.allocator.create(std.SinglyLinkedList);
|
||||
ll.* = .{};
|
||||
try self.events.put(key, ll);
|
||||
}
|
||||
const data = try self.allocator.create(Node);
|
||||
data.* = .{
|
||||
.hook = hook,
|
||||
.node = .{},
|
||||
};
|
||||
ll.prepend(&data.node);
|
||||
var ll: *std.SinglyLinkedList = undefined;
|
||||
if (self.events.get(key)) |sll| {
|
||||
ll = sll;
|
||||
} else {
|
||||
ll = try self.allocator.create(std.SinglyLinkedList);
|
||||
ll.* = .{};
|
||||
try self.events.put(key, ll);
|
||||
}
|
||||
const data = try self.allocator.create(Node);
|
||||
data.* = .{
|
||||
.hook = hook,
|
||||
.node = .{},
|
||||
};
|
||||
ll.prepend(&data.node);
|
||||
}
|
||||
|
||||
pub fn del(self: *Events, key: []const u8, hook: *const Hook) void {
|
||||
if (self.events.get(key)) |e| {
|
||||
var node = e.first;
|
||||
while (node) |n| : (node = n.next) {
|
||||
const data: *Node = @fieldParentPtr("node", n);
|
||||
if (data.hook.options.lua_cb_ref_idx == hook.options.lua_cb_ref_idx) e.remove(n);
|
||||
if (self.events.get(key)) |e| {
|
||||
var node = e.first;
|
||||
while (node) |n| : (node = n.next) {
|
||||
const data: *Node = @fieldParentPtr("node", n);
|
||||
if (data.hook.options.lua_cb_ref_idx == hook.options.lua_cb_ref_idx) e.remove(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exec(self: *Events, event: []const u8, args: anytype) void {
|
||||
if (self.events.get(event)) |e| {
|
||||
var node = e.first;
|
||||
while (node) |n| : (node = n.next) {
|
||||
const data: *Node = @fieldParentPtr("node", n);
|
||||
data.hook.callback(args);
|
||||
if (self.events.get(event)) |e| {
|
||||
var node = e.first;
|
||||
while (node) |n| : (node = n.next) {
|
||||
const data: *Node = @fieldParentPtr("node", n);
|
||||
data.hook.callback(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,34 +13,34 @@ const Lua = &@import("../main.zig").lua;
|
|||
|
||||
events: [][]const u8, // a list of events
|
||||
options: struct {
|
||||
// group: []const u8, // TODO: do we need groups?
|
||||
/// This is the location of the callback lua function in the lua registry
|
||||
lua_cb_ref_idx: i32,
|
||||
// group: []const u8, // TODO: do we need groups?
|
||||
/// This is the location of the callback lua function in the lua registry
|
||||
lua_cb_ref_idx: i32,
|
||||
},
|
||||
|
||||
pub fn callback(self: *const Hook, args: anytype) void {
|
||||
const ArgsType = @TypeOf(args);
|
||||
const args_type_info = @typeInfo(ArgsType);
|
||||
if (args_type_info != .@"struct") {
|
||||
@compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
|
||||
}
|
||||
const ArgsType = @TypeOf(args);
|
||||
const args_type_info = @typeInfo(ArgsType);
|
||||
if (args_type_info != .@"struct") {
|
||||
@compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
|
||||
}
|
||||
|
||||
const t = Lua.state.rawGetIndex(zlua.registry_index, self.options.lua_cb_ref_idx);
|
||||
if (t != zlua.LuaType.function) {
|
||||
RemoteLua.sendNewLogEntry("Failed to call hook, it doesn't have a callback.");
|
||||
Lua.state.pop(1);
|
||||
return;
|
||||
}
|
||||
const t = Lua.state.rawGetIndex(zlua.registry_index, self.options.lua_cb_ref_idx);
|
||||
if (t != zlua.LuaType.function) {
|
||||
RemoteLua.sendNewLogEntry("Failed to call hook, it doesn't have a callback.");
|
||||
Lua.state.pop(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// allow passing any arguments to the lua hook
|
||||
var i: u8 = 0;
|
||||
inline for (args, 1..) |field, k| {
|
||||
try Lua.state.pushAny(field);
|
||||
i = k;
|
||||
}
|
||||
// allow passing any arguments to the lua hook
|
||||
var i: u8 = 0;
|
||||
inline for (args, 1..) |field, k| {
|
||||
try Lua.state.pushAny(field);
|
||||
i = k;
|
||||
}
|
||||
|
||||
Lua.state.protectedCall(.{ .args = i }) catch {
|
||||
RemoteLua.sendNewLogEntry(Lua.state.toString(-1) catch unreachable);
|
||||
};
|
||||
Lua.state.pop(-1);
|
||||
Lua.state.protectedCall(.{ .args = i }) catch {
|
||||
RemoteLua.sendNewLogEntry(Lua.state.toString(-1) catch unreachable);
|
||||
};
|
||||
Lua.state.pop(-1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,31 +14,31 @@ const Lua = &@import("../main.zig").lua;
|
|||
modifier: wlr.Keyboard.ModifierMask,
|
||||
keycode: xkb.Keysym,
|
||||
options: struct {
|
||||
repeat: bool,
|
||||
/// This is the location of the on press lua function in the lua registry
|
||||
lua_press_ref_idx: i32,
|
||||
/// This is the location of the on release lua function in the lua registry
|
||||
lua_release_ref_idx: i32,
|
||||
repeat: bool,
|
||||
/// This is the location of the on press lua function in the lua registry
|
||||
lua_press_ref_idx: i32,
|
||||
/// This is the location of the on release lua function in the lua registry
|
||||
lua_release_ref_idx: i32,
|
||||
},
|
||||
|
||||
pub fn callback(self: *const Keymap, release: bool) void {
|
||||
const lua_ref_idx = if (release) self.options.lua_release_ref_idx else self.options.lua_press_ref_idx;
|
||||
const lua_ref_idx = if (release) self.options.lua_release_ref_idx else self.options.lua_press_ref_idx;
|
||||
|
||||
const t = Lua.state.rawGetIndex(zlua.registry_index, lua_ref_idx);
|
||||
if (t != zlua.LuaType.function) {
|
||||
RemoteLua.sendNewLogEntry("Failed to call keybind, it doesn't have a callback.");
|
||||
Lua.state.pop(1);
|
||||
return;
|
||||
}
|
||||
const t = Lua.state.rawGetIndex(zlua.registry_index, lua_ref_idx);
|
||||
if (t != zlua.LuaType.function) {
|
||||
RemoteLua.sendNewLogEntry("Failed to call keybind, it doesn't have a callback.");
|
||||
Lua.state.pop(1);
|
||||
return;
|
||||
}
|
||||
|
||||
Lua.state.protectedCall(.{ .args = 0, .results = 0 }) catch {
|
||||
RemoteLua.sendNewLogEntry(Lua.state.toString(-1) catch unreachable);
|
||||
};
|
||||
Lua.state.pop(-1);
|
||||
Lua.state.protectedCall(.{ .args = 0, .results = 0 }) catch {
|
||||
RemoteLua.sendNewLogEntry(Lua.state.toString(-1) catch unreachable);
|
||||
};
|
||||
Lua.state.pop(-1);
|
||||
}
|
||||
|
||||
pub fn hash(modifier: wlr.Keyboard.ModifierMask, keycode: xkb.Keysym) u64 {
|
||||
const mod_val: u32 = @bitCast(modifier);
|
||||
const key_val: u32 = @intFromEnum(keycode);
|
||||
return (@as(u64, mod_val) << 32) | @as(u64, key_val);
|
||||
const mod_val: u32 = @bitCast(modifier);
|
||||
const key_val: u32 = @intFromEnum(keycode);
|
||||
return (@as(u64, mod_val) << 32) | @as(u64, key_val);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,55 +14,55 @@ const Lua = &@import("../main.zig").lua;
|
|||
modifier: wlr.Keyboard.ModifierMask,
|
||||
event_code: i32,
|
||||
options: struct {
|
||||
/// This is the location of the on press lua function in the lua registry
|
||||
lua_press_ref_idx: i32,
|
||||
/// This is the location of the on release lua function in the lua registry
|
||||
lua_release_ref_idx: i32,
|
||||
/// This is the location of the on drag lua function in the lua registry
|
||||
lua_drag_ref_idx: i32,
|
||||
/// This is the location of the on press lua function in the lua registry
|
||||
lua_press_ref_idx: i32,
|
||||
/// This is the location of the on release lua function in the lua registry
|
||||
lua_release_ref_idx: i32,
|
||||
/// This is the location of the on drag lua function in the lua registry
|
||||
lua_drag_ref_idx: i32,
|
||||
},
|
||||
|
||||
pub const MousemapState = enum { press, drag, release };
|
||||
|
||||
// Returns true if mouse input should be passed through
|
||||
pub fn callback(self: *const Mousemap, state: MousemapState, args: anytype) bool {
|
||||
const ArgsType = @TypeOf(args);
|
||||
const args_type_info = @typeInfo(ArgsType);
|
||||
if (args_type_info != .@"struct") {
|
||||
@compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
|
||||
}
|
||||
const ArgsType = @TypeOf(args);
|
||||
const args_type_info = @typeInfo(ArgsType);
|
||||
if (args_type_info != .@"struct") {
|
||||
@compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
|
||||
}
|
||||
|
||||
const lua_ref_idx = switch(state) {
|
||||
.press => self.options.lua_press_ref_idx,
|
||||
.release => self.options.lua_release_ref_idx,
|
||||
.drag => self.options.lua_drag_ref_idx
|
||||
};
|
||||
const lua_ref_idx = switch (state) {
|
||||
.press => self.options.lua_press_ref_idx,
|
||||
.release => self.options.lua_release_ref_idx,
|
||||
.drag => self.options.lua_drag_ref_idx,
|
||||
};
|
||||
|
||||
const t = Lua.state.rawGetIndex(zlua.registry_index, lua_ref_idx);
|
||||
if (t != zlua.LuaType.function) {
|
||||
RemoteLua.sendNewLogEntry("Failed to call mousemap, it doesn't have a callback.");
|
||||
Lua.state.pop(1);
|
||||
return false;
|
||||
}
|
||||
const t = Lua.state.rawGetIndex(zlua.registry_index, lua_ref_idx);
|
||||
if (t != zlua.LuaType.function) {
|
||||
RemoteLua.sendNewLogEntry("Failed to call mousemap, it doesn't have a callback.");
|
||||
Lua.state.pop(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// allow passing any arguments to the lua hook
|
||||
var i: u8 = 0;
|
||||
inline for (args, 1..) |field, k| {
|
||||
try Lua.state.pushAny(field);
|
||||
i = k;
|
||||
}
|
||||
// allow passing any arguments to the lua hook
|
||||
var i: u8 = 0;
|
||||
inline for (args, 1..) |field, k| {
|
||||
try Lua.state.pushAny(field);
|
||||
i = k;
|
||||
}
|
||||
|
||||
Lua.state.protectedCall(.{ .args = i, .results = 1 }) catch {
|
||||
RemoteLua.sendNewLogEntry(Lua.state.toString(-1) catch unreachable);
|
||||
};
|
||||
Lua.state.protectedCall(.{ .args = i, .results = 1 }) catch {
|
||||
RemoteLua.sendNewLogEntry(Lua.state.toString(-1) catch unreachable);
|
||||
};
|
||||
|
||||
const ret = if (Lua.state.isBoolean(-1)) Lua.state.toBoolean(-1) else false;
|
||||
Lua.state.pop(-1);
|
||||
return ret;
|
||||
const ret = if (Lua.state.isBoolean(-1)) Lua.state.toBoolean(-1) else false;
|
||||
Lua.state.pop(-1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pub fn hash(modifier: wlr.Keyboard.ModifierMask, event_code: i32) u64 {
|
||||
const mod_val: u32 = @bitCast(modifier);
|
||||
const button_val: u32 = @bitCast(event_code);
|
||||
return (@as(u64, mod_val) << 32) | @as(u64, button_val);
|
||||
const mod_val: u32 = @bitCast(modifier);
|
||||
const button_val: u32 = @bitCast(event_code);
|
||||
return (@as(u64, mod_val) << 32) | @as(u64, button_val);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue