Implement initial tiling layout.
For now, it's hardcoded to be a right-primary/stack layout (similar to dwm but with the primary on the right) with the primary window getting 55% of the width of the screen.
This commit is contained in:
parent
2c18946703
commit
61fd784246
2 changed files with 80 additions and 24 deletions
|
|
@ -7,6 +7,7 @@ const Window = @This();
|
||||||
context: *Context,
|
context: *Context,
|
||||||
|
|
||||||
window_v1: *river.WindowV1,
|
window_v1: *river.WindowV1,
|
||||||
|
node_v1: *river.NodeV1,
|
||||||
|
|
||||||
width: u31 = 0,
|
width: u31 = 0,
|
||||||
height: u31 = 0,
|
height: u31 = 0,
|
||||||
|
|
@ -19,12 +20,12 @@ new_x: i32 = 0,
|
||||||
new_y: i32 = 0,
|
new_y: i32 = 0,
|
||||||
|
|
||||||
link: wl.list.Link,
|
link: wl.list.Link,
|
||||||
is_head: bool = false,
|
|
||||||
|
|
||||||
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,
|
||||||
.window_v1 = river_window_v1,
|
.window_v1 = river_window_v1,
|
||||||
|
.node_v1 = river_window_v1.getNode() catch @panic("failed to get node"),
|
||||||
.link = undefined, // Handled by the wl.list
|
.link = undefined, // Handled by the wl.list
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -36,6 +37,8 @@ fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event,
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.closed => {
|
.closed => {
|
||||||
river_window_v1.destroy();
|
river_window_v1.destroy();
|
||||||
|
window.node_v1.destroy();
|
||||||
|
window.context.wm.window_count -= 1;
|
||||||
{
|
{
|
||||||
var it = window.context.wm.seats.iterator(.forward);
|
var it = window.context.wm.seats.iterator(.forward);
|
||||||
while (it.next()) |seat| {
|
while (it.next()) |seat| {
|
||||||
|
|
@ -63,32 +66,30 @@ fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn manage(window: *Window) void {
|
pub fn manage(window: *Window) void {
|
||||||
if (window.context.wm.outputs.length() == 0) {
|
// Layout has been pre-computed by WindowManager.calculatePrimaryStackLayout()
|
||||||
window.new_width = 0;
|
// Apply the computed dimensions
|
||||||
window.new_height = 0;
|
if (window.new_width > 0 and window.new_height > 0) {
|
||||||
window.new_x = 0;
|
window.window_v1.proposeDimensions(window.new_width, window.new_height);
|
||||||
window.new_y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Support multiple primaries
|
// Use server-side decoration (no client-drawn title bars)
|
||||||
// TODO: Is this a valid way to check for the window's index?
|
window.window_v1.useSsd();
|
||||||
|
|
||||||
// TODO: Remove this -- just fullscreen for now
|
// Inform the window about its tiled/fullscreen state
|
||||||
if (window.width != window.context.wm.outputs.first().?.width or
|
if (window.context.wm.window_count == 1) {
|
||||||
window.height != window.context.wm.outputs.first().?.height)
|
// Single window is fullscreen
|
||||||
{
|
window.window_v1.setTiled(.{ .top = false, .bottom = false, .left = false, .right = false });
|
||||||
window.width = @intCast(window.context.wm.outputs.first().?.width);
|
window.window_v1.informFullscreen();
|
||||||
window.height = @intCast(window.context.wm.outputs.first().?.height);
|
} else {
|
||||||
log.debug("setting window width={d} and height={d} {}", .{ window.width, window.height, window.is_head });
|
// Tiled windows - set tiled edges
|
||||||
|
window.window_v1.informNotFullscreen();
|
||||||
|
window.window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
window.window_v1.proposeDimensions(window.width, window.height);
|
|
||||||
// window.window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
|
|
||||||
window.window_v1.informFullscreen();
|
|
||||||
// window.window_v1.informMaximized();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(window: *Window) void {
|
pub fn render(window: *Window) void {
|
||||||
_ = window; // TODO ???
|
// Set the window position using the pre-computed layout
|
||||||
|
window.node_v1.setPosition(window.new_x, window.new_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
const WindowManager = @This();
|
const WindowManager = @This();
|
||||||
|
|
||||||
|
const PRIMARY_RATIO: f32 = 0.55;
|
||||||
|
|
||||||
context: *Context,
|
context: *Context,
|
||||||
|
|
||||||
window_manager_v1: *river.WindowManagerV1,
|
window_manager_v1: *river.WindowManagerV1,
|
||||||
|
|
@ -31,6 +33,60 @@ pub fn init(wm: *WindowManager, context: *Context, window_manager_v1: *river.Win
|
||||||
wm.window_manager_v1.setListener(*WindowManager, windowManagerV1Listener, wm);
|
wm.window_manager_v1.setListener(*WindowManager, windowManagerV1Listener, wm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculate primary/stack layout positions for all windows.
|
||||||
|
/// - Single window: fullscreen
|
||||||
|
/// - Multiple windows: stack (45% left, vertically tiled), primary (55% right)
|
||||||
|
pub fn calculatePrimaryStackLayout(wm: *WindowManager) void {
|
||||||
|
const count = wm.window_count;
|
||||||
|
if (count == 0) return;
|
||||||
|
|
||||||
|
const output = wm.outputs.first() orelse return;
|
||||||
|
// Output dimensions come as i32 from the protocol, convert to u31 for window dimensions
|
||||||
|
const output_width: u31 = @intCast(output.width);
|
||||||
|
const output_height: u31 = @intCast(output.height);
|
||||||
|
const output_x = output.x;
|
||||||
|
const output_y = output.y;
|
||||||
|
|
||||||
|
var index: u8 = 0;
|
||||||
|
var it = wm.windows.iterator(.forward);
|
||||||
|
while (it.next()) |window| {
|
||||||
|
if (count == 1) {
|
||||||
|
// Single window: fullscreen
|
||||||
|
window.new_x = output_x;
|
||||||
|
window.new_y = output_y;
|
||||||
|
window.new_width = output_width;
|
||||||
|
window.new_height = output_height;
|
||||||
|
} else {
|
||||||
|
// Multiple windows: primary/stack layout
|
||||||
|
const primary_width: u31 = @intFromFloat(@as(f32, @floatFromInt(output_width)) * PRIMARY_RATIO);
|
||||||
|
const stack_width: u31 = output_width - primary_width;
|
||||||
|
const stack_count = count - 1;
|
||||||
|
const stack_height: u31 = @divFloor(output_height, stack_count);
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
// Primary window (first window) - right side
|
||||||
|
window.new_x = output_x + @as(i32, stack_width);
|
||||||
|
window.new_y = output_y;
|
||||||
|
window.new_width = primary_width;
|
||||||
|
window.new_height = output_height;
|
||||||
|
} else {
|
||||||
|
// Stack window - left side
|
||||||
|
const stack_index = index - 1;
|
||||||
|
window.new_x = output_x;
|
||||||
|
window.new_y = output_y + @as(i32, stack_index) * @as(i32, stack_height);
|
||||||
|
window.new_width = stack_width;
|
||||||
|
// Last stack window gets remaining height to avoid gaps from integer division
|
||||||
|
if (index == count - 1) {
|
||||||
|
window.new_height = output_height - stack_index * stack_height;
|
||||||
|
} else {
|
||||||
|
window.new_height = stack_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: river.WindowManagerV1.Event, wm: *WindowManager) void {
|
fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: river.WindowManagerV1.Event, wm: *WindowManager) void {
|
||||||
assert(wm.window_manager_v1 == window_manager_v1);
|
assert(wm.window_manager_v1 == window_manager_v1);
|
||||||
const context = wm.context;
|
const context = wm.context;
|
||||||
|
|
@ -56,6 +112,8 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv
|
||||||
output.manage();
|
output.manage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Calculate layout before managing windows
|
||||||
|
wm.calculatePrimaryStackLayout();
|
||||||
{
|
{
|
||||||
var it = wm.windows.iterator(.forward);
|
var it = wm.windows.iterator(.forward);
|
||||||
while (it.next()) |window| {
|
while (it.next()) |window| {
|
||||||
|
|
@ -103,9 +161,6 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv
|
||||||
window.init(context, ev.id);
|
window.init(context, ev.id);
|
||||||
wm.windows.append(window);
|
wm.windows.append(window);
|
||||||
wm.window_count += 1;
|
wm.window_count += 1;
|
||||||
if (wm.window_count == 1) {
|
|
||||||
window.is_head = true;
|
|
||||||
}
|
|
||||||
log.debug("window_count = {d}", .{wm.window_count});
|
log.debug("window_count = {d}", .{wm.window_count});
|
||||||
},
|
},
|
||||||
else => |ev| {
|
else => |ev| {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue