Implement fullscreening
This commit is contained in:
parent
643d6c82ab
commit
92e82f38f5
3 changed files with 101 additions and 46 deletions
|
|
@ -14,15 +14,31 @@ height: u31 = 0,
|
||||||
x: i32 = 0,
|
x: i32 = 0,
|
||||||
y: i32 = 0,
|
y: i32 = 0,
|
||||||
|
|
||||||
new_width: u31 = 0,
|
fullscreen: bool = false,
|
||||||
new_height: u31 = 0,
|
maximized: bool = false,
|
||||||
new_x: i32 = 0,
|
|
||||||
new_y: i32 = 0,
|
|
||||||
|
|
||||||
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,
|
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 {
|
pub fn init(window: *Window, context: *Context, river_window_v1: *river.WindowV1) void {
|
||||||
window.* = .{
|
window.* = .{
|
||||||
.context = context,
|
.context = context,
|
||||||
|
|
@ -70,32 +86,62 @@ fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event,
|
||||||
pub fn manage(window: *Window) void {
|
pub fn manage(window: *Window) void {
|
||||||
// Use server-side decoration (no client-drawn title bars)
|
// Use server-side decoration (no client-drawn title bars)
|
||||||
// TODO: Probably shouldn't send this for every manage(?)
|
// TODO: Probably shouldn't send this for every manage(?)
|
||||||
|
if (!window.initialized) {
|
||||||
|
@branchHint(.unlikely);
|
||||||
|
window.initialized = true;
|
||||||
|
|
||||||
window.window_v1.useSsd();
|
window.window_v1.useSsd();
|
||||||
|
|
||||||
// Layout has been pre-computed by WindowManager.calculatePrimaryStackLayout()
|
window.window_v1.setCapabilities(.{ .fullscreen = true, .maximize = true });
|
||||||
// Apply the computed dimensions
|
window.window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
|
||||||
if (window.new_width > 0 and window.new_height > 0) {
|
}
|
||||||
window.window_v1.proposeDimensions(window.new_width, window.new_height);
|
|
||||||
|
|
||||||
// Inform the window about its tiled/fullscreen state
|
// Any new state since the last manage event
|
||||||
if (window.context.wm.window_count == 1) {
|
defer window.pending_state = .{};
|
||||||
// Single window is fullscreen
|
const pending_state = window.pending_state;
|
||||||
window.window_v1.setTiled(.{ .top = false, .bottom = false, .left = false, .right = false });
|
// 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();
|
window.window_v1.informFullscreen();
|
||||||
} else {
|
} else {
|
||||||
// Tiled windows - set tiled edges
|
window.window_v1.exitFullscreen();
|
||||||
window.window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
|
|
||||||
window.window_v1.informNotFullscreen();
|
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 {
|
pub fn render(window: *Window) void {
|
||||||
// Set the window position using the pre-computed layout
|
// 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
|
// Set borders
|
||||||
if (!window.is_maximized) {
|
if (!window.fullscreen) {
|
||||||
const border_width = window.context.config.border_width;
|
const border_width = window.context.config.border_width;
|
||||||
if (window.isFocused()) {
|
if (window.isFocused()) {
|
||||||
const border_color_focused = window.context.config.border_color_focused;
|
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 {
|
fn isFocused(window: *Window) bool {
|
||||||
var it = window.context.wm.seats.iterator(.forward);
|
var it = window.context.wm.seats.iterator(.forward);
|
||||||
while (it.next()) |seat| {
|
while (it.next()) |seat| {
|
||||||
|
|
|
||||||
|
|
@ -75,50 +75,50 @@ fn calculatePrimaryStackLayout(wm: *WindowManager) void {
|
||||||
var it = wm.windows.iterator(.forward);
|
var it = wm.windows.iterator(.forward);
|
||||||
while (it.next()) |window| {
|
while (it.next()) |window| {
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
// Single window: fullscreen
|
// Single window: maximize
|
||||||
// TODO: Disable borders when maximized
|
window.pending_state.x = output_x;
|
||||||
window.new_x = output_x;
|
window.pending_state.y = output_y;
|
||||||
window.new_y = output_y;
|
window.pending_state.width = output_width;
|
||||||
window.new_width = output_width;
|
window.pending_state.height = output_height;
|
||||||
window.new_height = output_height;
|
window.pending_state.maximized = true;
|
||||||
window.is_maximized = true;
|
|
||||||
} else {
|
} else {
|
||||||
// Multiple windows: primary/stack layout
|
// Multiple windows: primary/stack layout
|
||||||
// TODO: Support multiple primaries
|
// TODO: Support multiple windows in primary stack
|
||||||
const primary_width: u31 = @intFromFloat(@as(f32, @floatFromInt(output_width)) * PRIMARY_RATIO);
|
const primary_width: u31 = @intFromFloat(@as(f32, @floatFromInt(output_width)) * PRIMARY_RATIO);
|
||||||
const stack_width: u31 = output_width - primary_width;
|
const stack_width: u31 = output_width - primary_width;
|
||||||
const stack_count = count - 1;
|
const stack_count = count - 1;
|
||||||
const stack_height: u31 = @divFloor(output_height, stack_count);
|
const stack_height: u31 = @divFloor(output_height, stack_count);
|
||||||
window.is_maximized = false;
|
window.pending_state.maximized = false;
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
// Primary window (first window) - right side
|
// Primary window (first window) - right side
|
||||||
window.new_x = output_x + @as(i32, stack_width);
|
window.pending_state.x = output_x + @as(i32, stack_width);
|
||||||
window.new_y = output_y;
|
window.pending_state.y = output_y;
|
||||||
window.new_width = primary_width;
|
window.pending_state.width = primary_width;
|
||||||
window.new_height = output_height;
|
window.pending_state.height = output_height;
|
||||||
} else {
|
} else {
|
||||||
// Stack window(s) - left side
|
// Stack window(s) - left side
|
||||||
const stack_index = index - 1;
|
const stack_index = index - 1;
|
||||||
window.new_x = output_x;
|
window.pending_state.x = output_x;
|
||||||
window.new_y = output_y + @as(i32, stack_index) * @as(i32, stack_height);
|
window.pending_state.y = output_y + @as(i32, stack_index) * @as(i32, stack_height);
|
||||||
window.new_width = stack_width;
|
window.pending_state.width = stack_width;
|
||||||
// Last stack window gets remaining height to avoid gaps from integer division
|
// Last stack window gets remaining height to avoid gaps from integer division
|
||||||
if (index == count - 1) {
|
if (index == count - 1) {
|
||||||
window.new_height = output_height - stack_index * stack_height;
|
window.pending_state.height = output_height - stack_index * stack_height;
|
||||||
} else {
|
} else {
|
||||||
window.new_height = stack_height;
|
window.pending_state.height = stack_height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Make space for borders; this is the same for all windows
|
// Make space for borders; this is the same for all windows.
|
||||||
// (unless we disable borders when maximized?)
|
// Borders are automatically disabled when a window is fullscreened so we don't
|
||||||
|
// have to worry about that.
|
||||||
const border_width = wm.context.config.border_width;
|
const border_width = wm.context.config.border_width;
|
||||||
window.new_height -= 2 * border_width;
|
window.pending_state.height.? -= 2 * border_width;
|
||||||
window.new_width -= 2 * border_width;
|
window.pending_state.width.? -= 2 * border_width;
|
||||||
window.new_x += border_width;
|
window.pending_state.x.? += border_width;
|
||||||
window.new_y += border_width;
|
window.pending_state.y.? += border_width;
|
||||||
}
|
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -140,8 +140,9 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv
|
||||||
context.xkb_bindings.addBinding(xkbcommon.Keysym.t, .{ .mod4 = true }, .{ .spawn = &.{"foot"} });
|
context.xkb_bindings.addBinding(xkbcommon.Keysym.t, .{ .mod4 = true }, .{ .spawn = &.{"foot"} });
|
||||||
context.xkb_bindings.addBinding(xkbcommon.Keysym.j, .{ .mod4 = true }, .focus_next);
|
context.xkb_bindings.addBinding(xkbcommon.Keysym.j, .{ .mod4 = true }, .focus_next);
|
||||||
context.xkb_bindings.addBinding(xkbcommon.Keysym.k, .{ .mod4 = true }, .focus_prev);
|
context.xkb_bindings.addBinding(xkbcommon.Keysym.k, .{ .mod4 = true }, .focus_prev);
|
||||||
context.xkb_bindings.addBinding(xkbcommon.Keysym.q, .{ .mod4 = true, .shift = true }, XkbBindings.Command.close_window);
|
context.xkb_bindings.addBinding(xkbcommon.Keysym.f, .{ .mod4 = true }, .fullscreen);
|
||||||
context.xkb_bindings.addBinding(xkbcommon.Keysym.e, .{ .mod4 = true, .shift = true }, XkbBindings.Command.exit);
|
context.xkb_bindings.addBinding(xkbcommon.Keysym.q, .{ .mod4 = true, .shift = true }, .close_window);
|
||||||
|
context.xkb_bindings.addBinding(xkbcommon.Keysym.e, .{ .mod4 = true, .shift = true }, .exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ pub const Command = union(enum) {
|
||||||
spawn: []const []const u8,
|
spawn: []const []const u8,
|
||||||
focus_next,
|
focus_next,
|
||||||
focus_prev,
|
focus_prev,
|
||||||
|
fullscreen,
|
||||||
close_window,
|
close_window,
|
||||||
exit,
|
exit,
|
||||||
};
|
};
|
||||||
|
|
@ -71,6 +72,11 @@ const XkbBinding = struct {
|
||||||
}
|
}
|
||||||
context.wm.window_manager_v1.manageDirty();
|
context.wm.window_manager_v1.manageDirty();
|
||||||
},
|
},
|
||||||
|
.fullscreen => {
|
||||||
|
const seat = context.wm.seats.first() orelse return;
|
||||||
|
const window = seat.focused orelse return;
|
||||||
|
window.pending_state.fullscreen = !window.fullscreen;
|
||||||
|
},
|
||||||
.close_window => {
|
.close_window => {
|
||||||
const seat = context.wm.seats.first() orelse return;
|
const seat = context.wm.seats.first() orelse return;
|
||||||
if (seat.focused) |window| {
|
if (seat.focused) |window| {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue