mirror of
https://github.com/MezzalunaWM/Mezzaluna.git
synced 2026-03-07 19:49:53 -05:00
This is currently incomplete and needs work to make sure that popups stay inside their parents current output. fixing popups, wip
222 lines
6.3 KiB
Zig
222 lines
6.3 KiB
Zig
const Server = @This();
|
|
|
|
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 Utils = @import("Utils.zig");
|
|
const Keymap = @import("types/Keymap.zig");
|
|
const Hook = @import("types/Hook.zig");
|
|
const Events = @import("types/Events.zig");
|
|
const Popup = @import("Popup.zig");
|
|
|
|
const gpa = std.heap.c_allocator;
|
|
const server = &@import("main.zig").server;
|
|
|
|
wl_server: *wl.Server,
|
|
compositor: *wlr.Compositor,
|
|
renderer: *wlr.Renderer,
|
|
backend: *wlr.Backend,
|
|
event_loop: *wl.EventLoop,
|
|
session: ?*wlr.Session,
|
|
|
|
shm: *wlr.Shm,
|
|
xdg_shell: *wlr.XdgShell,
|
|
layer_shell: *wlr.LayerShellV1,
|
|
xdg_toplevel_decoration_manager: *wlr.XdgDecorationManagerV1,
|
|
|
|
// Input
|
|
|
|
allocator: *wlr.Allocator,
|
|
|
|
root: Root,
|
|
seat: Seat,
|
|
cursor: Cursor,
|
|
|
|
// lua data
|
|
keymaps: std.AutoHashMap(u64, Keymap),
|
|
hooks: std.ArrayList(*Hook),
|
|
events: Events,
|
|
|
|
// Backend listeners
|
|
new_input: wl.Listener(*wlr.InputDevice) = .init(handleNewInput),
|
|
new_output: wl.Listener(*wlr.Output) = .init(handleNewOutput),
|
|
// backend.events.destroy
|
|
|
|
// XdgShell listeners
|
|
new_xdg_toplevel: wl.Listener(*wlr.XdgToplevel) = .init(handleNewXdgToplevel),
|
|
new_xdg_popup: wl.Listener(*wlr.XdgPopup) = .init(handleNewXdgPopup),
|
|
new_xdg_toplevel_decoration: wl.Listener(*wlr.XdgToplevelDecorationV1) = .init(handleNewXdgToplevelDecoration),
|
|
|
|
// LayerShell Listeners
|
|
new_layer_surface: wl.Listener(*wlr.LayerSurfaceV1) = .init(handleNewLayerSurface),
|
|
|
|
pub fn init(self: *Server) void {
|
|
errdefer Utils.oomPanic();
|
|
|
|
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();
|
|
|
|
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);
|
|
};
|
|
|
|
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),
|
|
.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,
|
|
.keymaps = .init(gpa),
|
|
.hooks = try .initCapacity(gpa, 10), // TODO: choose how many slots to start with
|
|
.events = try .init(gpa),
|
|
};
|
|
|
|
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();
|
|
|
|
_ = try wlr.Subcompositor.create(self.wl_server);
|
|
_ = try wlr.DataDeviceManager.create(self.wl_server);
|
|
|
|
// Add event listeners to events
|
|
// Backedn events
|
|
self.backend.events.new_input.add(&self.new_input);
|
|
self.backend.events.new_output.add(&self.new_output);
|
|
|
|
// XdgShell events
|
|
self.xdg_shell.events.new_toplevel.add(&self.new_xdg_toplevel);
|
|
self.xdg_shell.events.new_popup.add(&self.new_xdg_popup);
|
|
|
|
// XdgDecorationManagerV1 events
|
|
self.xdg_toplevel_decoration_manager.events.new_toplevel_decoration.add(&self.new_xdg_toplevel_decoration);
|
|
|
|
// LayerShell events
|
|
self.layer_shell.events.new_surface.add(&self.new_layer_surface);
|
|
|
|
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.seat.deinit();
|
|
self.root.deinit();
|
|
self.cursor.deinit();
|
|
|
|
self.backend.destroy();
|
|
|
|
self.wl_server.destroyClients();
|
|
self.wl_server.destroy();
|
|
|
|
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)"}
|
|
);
|
|
},
|
|
}
|
|
|
|
// 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 handleNewXdgToplevel(
|
|
_: *wl.Listener(*wlr.XdgToplevel),
|
|
xdg_toplevel: *wlr.XdgToplevel
|
|
) void {
|
|
_ = View.initFromTopLevel(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 handleNewXdgPopup(_: *wl.Listener(*wlr.XdgPopup), xdg_popup: *wlr.XdgPopup) void {
|
|
_ = xdg_popup;
|
|
}
|
|
|
|
fn handleNewLayerSurface(
|
|
_: *wl.Listener(*wlr.LayerSurfaceV1),
|
|
layer_surface: *wlr.LayerSurfaceV1
|
|
) void {
|
|
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;
|
|
}
|
|
|
|
_ = LayerSurface.init(layer_surface);
|
|
}
|