mirror of
https://github.com/MezzalunaWM/Mezzaluna.git
synced 2026-03-07 19:49:53 -05:00
173 lines
5.1 KiB
Zig
173 lines
5.1 KiB
Zig
const Seat = @This();
|
|
|
|
const std = @import("std");
|
|
const wlr = @import("wlroots");
|
|
const wl = @import("wayland").server.wl;
|
|
const xkb = @import("xkbcommon");
|
|
|
|
const Utils = @import("Utils.zig");
|
|
const Popup = @import("Popup.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,
|
|
|
|
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,
|
|
|
|
focused_surface: ?FocusData,
|
|
focused_output: ?*Output,
|
|
|
|
keyboard_group: *wlr.KeyboardGroup,
|
|
keymap: *xkb.Keymap,
|
|
|
|
request_set_cursor: wl.Listener(*wlr.Seat.event.RequestSetCursor) = .init(handleRequestSetCursor),
|
|
request_set_selection: wl.Listener(*wlr.Seat.event.RequestSetSelection) = .init(handleRequestSetSelection),
|
|
// request_set_primary_selection
|
|
// request_start_drage
|
|
|
|
pub fn init(self: *Seat) void {
|
|
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 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 = try wlr.KeyboardGroup.create(),
|
|
.keymap = keymap.ref(),
|
|
};
|
|
errdefer {
|
|
self.keyboard_group.destroy();
|
|
self.wlr_seat.destroy();
|
|
}
|
|
|
|
_ = self.keyboard_group.keyboard.setKeymap(self.keymap);
|
|
self.wlr_seat.setKeyboard(&self.keyboard_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);
|
|
}
|
|
|
|
pub fn deinit(self: *Seat) void {
|
|
self.request_set_cursor.link.remove();
|
|
self.request_set_selection.link.remove();
|
|
|
|
self.keyboard_group.destroy();
|
|
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;
|
|
}
|
|
};
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(to_focus != null) {
|
|
server.seat.wlr_seat.keyboardNotifyEnter(
|
|
surface.?,
|
|
&server.seat.wlr_seat.keyboard_state.keyboard.?.keycodes,
|
|
null
|
|
);
|
|
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;
|
|
}
|
|
|
|
pub fn focusOutput(self: *Seat, output: *Output) void {
|
|
if(server.seat.focused_output) |prev_output| {
|
|
prev_output.focused = false;
|
|
}
|
|
|
|
self.focused_output = output;
|
|
}
|
|
|
|
fn handleRequestSetCursor(
|
|
_: *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);
|
|
}
|
|
|
|
fn handleRequestSetSelection (
|
|
_: *wl.Listener(*wlr.Seat.event.RequestSetSelection),
|
|
event: *wlr.Seat.event.RequestSetSelection,
|
|
) void {
|
|
server.seat.wlr_seat.setSelection(event.source, event.serial);
|
|
}
|