Don't propose dimensions for windows floating for the first time

Before, we were using the same behavior as when we made any window
floating, which meant we'd set the window to 75% of the output's
dimensions. The issue is that, at least in my case, I usually want a
floating rule for windows that are small and have specific pre-set
sizes, so that didn't make sense. Now, if a window was made floating by
a rule, it should just start with its default dimensions but it can still
be resized later.
This commit is contained in:
Ben Buhse 2026-03-31 15:41:07 -05:00
commit 6136f9d3f8
No known key found for this signature in database
GPG key ID: 7916ACFCD38FD0B4
2 changed files with 46 additions and 5 deletions

View file

@ -53,3 +53,4 @@ These are in rough order of my priority, though no promises I do them in this or
- [x] Add bar padding to config - [x] Add bar padding to config
- [x] Support 12-hour clock format (maybe take any time format string?) - [x] Support 12-hour clock format (maybe take any time format string?)
- [x] Support configuring bar item positions (left/center/right) - [x] Support configuring bar item positions (left/center/right)
- [x] Skip proposing dimensions for floating windows altogether?

View file

@ -25,6 +25,15 @@ floating: bool = false,
floating_rect: utils.Rect = .{}, floating_rect: utils.Rect = .{},
dimensions_hint: DimensionsHint = .{}, dimensions_hint: DimensionsHint = .{},
/// Whether or not the window needs its position set
///
/// Right now, this is only used when windows are made floating by a rule but don't have their
/// dimensions set yet. We need their dimensions to be able to center them properly, so we have
/// to wait for that event.
///
/// This can't be part of PendingManage because it lasts between manage cycles.
needs_position: bool = true,
initialized: bool = false, initialized: bool = false,
/// State consumed in manage() phase, reset at end of manage(). /// State consumed in manage() phase, reset at end of manage().
@ -151,9 +160,18 @@ fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event,
window.destroy(); window.destroy();
}, },
.dimensions => |ev| { .dimensions => |ev| {
// Protocol guarantees that width and height are strictly greater than zero
assert(ev.width > 0 and ev.height > 0);
window.pending_manage.dimensions = .{ .width = @intCast(ev.width), .height = @intCast(ev.height) }; window.pending_manage.dimensions = .{ .width = @intCast(ev.width), .height = @intCast(ev.height) };
if (window.needs_position) {
@branchHint(.unlikely);
if (window.output) |output| {
window.needs_position = false;
window.pending_render.position = .{
.x = (output.geometry.width / 2) - (window.pending_manage.dimensions.?.width / 2),
.y = (output.geometry.height / 2) - (window.pending_manage.dimensions.?.height / 2),
};
}
}
}, },
.dimensions_hint => |ev| { .dimensions_hint => |ev| {
window.dimensions_hint = .{ window.dimensions_hint = .{
@ -231,7 +249,9 @@ fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event,
/// rules are reflected in the first frame's layout. /// rules are reflected in the first frame's layout.
pub fn initialize(window: *Window) void { pub fn initialize(window: *Window) void {
if (window.initialized) { if (window.initialized) {
@branchHint(.unlikely); // This branch should only reach once per window,
// but the method is called on every layout calculation.
@branchHint(.likely);
return; return;
} }
window.initialized = true; window.initialized = true;
@ -246,9 +266,12 @@ pub fn initialize(window: *Window) void {
river_window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true }); river_window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
const res = window.applyRules(); const res = window.applyRules();
if (res.tags) |tags| window.tags = tags; if (res.tags) |tags| {
if (res.float) |should_float| window.tags = tags;
}
if (res.float) |should_float| {
window.pending_manage.floating = should_float; window.pending_manage.floating = should_float;
}
} }
pub fn manage(window: *Window) void { pub fn manage(window: *Window) void {
@ -273,6 +296,23 @@ pub fn manage(window: *Window) void {
// This window has never floated before, let's give it floating dimensions. // This window has never floated before, let's give it floating dimensions.
// Use 75% of the output's usable size, clamped to the window's dimension hints. // Use 75% of the output's usable size, clamped to the window's dimension hints.
if (window.output) |output| { if (window.output) |output| {
if (window.rect.width == 0) {
// The window didn't even *exist* before, i.e. we only got here via a floating window rule.
// Don't propose dimensions, let it start how it wants.
if (window.pending_manage.dimensions) |dimensions| {
// TODO: Is it even possible to make it in here? I need to ask ifreund, probably
// We want to center the output; this works even if the proposed dimensions
// are 0 since the dimensions are the numerator, the window just wouldn't
// be centered.
window.pending_render.position = .{
.x = (output.geometry.width / 2) - (dimensions.width / 2),
.y = (output.geometry.height / 2) - (dimensions.height / 2),
};
} else {
window.needs_position = true;
}
break :blk;
}
window.floating_rect.width = window.dimensions_hint.clampWidth(@divFloor(output.usable_geometry.width * 3, 4)); window.floating_rect.width = window.dimensions_hint.clampWidth(@divFloor(output.usable_geometry.width * 3, 4));
window.floating_rect.height = window.dimensions_hint.clampHeight(@divFloor(output.usable_geometry.height * 3, 4)); window.floating_rect.height = window.dimensions_hint.clampHeight(@divFloor(output.usable_geometry.height * 3, 4));
window.floating_rect.x = output.usable_geometry.x + @divFloor(output.usable_geometry.width, 2) - @divFloor(window.floating_rect.width, 2); window.floating_rect.x = output.usable_geometry.x + @divFloor(output.usable_geometry.width, 2) - @divFloor(window.floating_rect.width, 2);