Implement fullscreening

This commit is contained in:
Ben Buhse 2026-01-24 14:45:33 -06:00
commit 92e82f38f5
No known key found for this signature in database
GPG key ID: 7916ACFCD38FD0B4
3 changed files with 101 additions and 46 deletions

View file

@ -14,15 +14,31 @@ height: u31 = 0,
x: i32 = 0,
y: i32 = 0,
new_width: u31 = 0,
new_height: u31 = 0,
new_x: i32 = 0,
new_y: i32 = 0,
fullscreen: bool = false,
maximized: bool = false,
is_maximized: bool = false,
initialized: bool = false,
/// Used to manage updates to various aspect of Window's state
/// Gets reset at the end of every Window.manage() call.
///
/// It might be a good idea to have two separate versions of this so one
/// can be used in renders, but I think it's okay for now.
pending_state: PendingState = .{},
link: wl.list.Link,
/// Used to manage updates to various aspect of Window's state
pub const PendingState = struct {
width: ?u31 = null,
height: ?u31 = null,
x: ?i32 = null,
y: ?i32 = null,
fullscreen: ?bool = null,
maximized: ?bool = null,
};
pub fn init(window: *Window, context: *Context, river_window_v1: *river.WindowV1) void {
window.* = .{
.context = context,
@ -70,32 +86,62 @@ fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event,
pub fn manage(window: *Window) void {
// Use server-side decoration (no client-drawn title bars)
// TODO: Probably shouldn't send this for every manage(?)
window.window_v1.useSsd();
if (!window.initialized) {
@branchHint(.unlikely);
window.initialized = true;
// Layout has been pre-computed by WindowManager.calculatePrimaryStackLayout()
// Apply the computed dimensions
if (window.new_width > 0 and window.new_height > 0) {
window.window_v1.proposeDimensions(window.new_width, window.new_height);
window.window_v1.useSsd();
// Inform the window about its tiled/fullscreen state
if (window.context.wm.window_count == 1) {
// Single window is fullscreen
window.window_v1.setTiled(.{ .top = false, .bottom = false, .left = false, .right = false });
window.window_v1.setCapabilities(.{ .fullscreen = true, .maximize = true });
window.window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
}
// Any new state since the last manage event
defer window.pending_state = .{};
const pending_state = window.pending_state;
// Layout (pre-computed by WindowManager.calculatePrimaryStackLayout())
if (pending_state.width) |new_width| {
if (pending_state.height) |new_height| {
window.width = new_width;
window.height = new_height;
window.window_v1.proposeDimensions(new_width, new_height);
}
}
if (pending_state.x) |new_x| {
window.x = new_x;
}
if (pending_state.y) |new_y| {
window.y = new_y;
}
// Fullscreen and maximize operations
if (pending_state.fullscreen) |fullscreen| {
window.fullscreen = fullscreen;
if (fullscreen) {
const output = window.context.wm.outputs.first() orelse @panic("failed to get output");
window.window_v1.fullscreen(output.output_v1);
window.window_v1.informFullscreen();
} else {
// Tiled windows - set tiled edges
window.window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
window.window_v1.exitFullscreen();
window.window_v1.informNotFullscreen();
}
}
if (pending_state.maximized) |maximized| {
window.maximized = maximized;
if (maximized) {
window.window_v1.informMaximized();
} else {
window.window_v1.informUnmaximized();
}
}
}
pub fn render(window: *Window) void {
// Set the window position using the pre-computed layout
window.node_v1.setPosition(window.new_x, window.new_y);
window.node_v1.setPosition(window.x, window.y);
// Set borders
if (!window.is_maximized) {
if (!window.fullscreen) {
const border_width = window.context.config.border_width;
if (window.isFocused()) {
const border_color_focused = window.context.config.border_color_focused;
@ -107,6 +153,8 @@ pub fn render(window: *Window) void {
}
}
// TODO: Should probably make this better. Shouldn't be too bad since we only have one seat
// but there's no reason to do it like this
fn isFocused(window: *Window) bool {
var it = window.context.wm.seats.iterator(.forward);
while (it.next()) |seat| {