Make window rules frame perfect

This moves window initialization earlier in the manage sequence.
Previously, it was on the Window's first manage() call, but this is
after the layout has already been calculated, which matters both because
of tags and whether the window starts floating or not.

Now, initialization is handled in a separate function that gets called
in Output.calculatePrimaryStackLayout() instead.
This commit is contained in:
Ben Buhse 2026-02-17 16:51:57 -06:00
commit c4da4ef30a
No known key found for this signature in database
GPG key ID: 7916ACFCD38FD0B4
3 changed files with 30 additions and 20 deletions

View file

@ -2,7 +2,6 @@
These are in rough order of my priority, though no promises I do them in this order. These are in rough order of my priority, though no promises I do them in this order.
- [ ] Support window rules (float/tags/SSD by app-id/title)
- [ ] Support overriding config location - [ ] Support overriding config location
- [ ] Support configuring primary vs secondary stack side - [ ] Support configuring primary vs secondary stack side
- [ ] Support switch handling (e.g. lid close) - [ ] Support switch handling (e.g. lid close)
@ -31,3 +30,4 @@ These are in rough order of my priority, though no promises I do them in this or
- [x] Add options to the tag overlay - [x] Add options to the tag overlay
- [x] Add options to the bar - [x] Add options to the bar
- [x] Make a Rect struct to combine x, y, width, and height - [x] Make a Rect struct to combine x, y, width, and height
- [x] Support window rules (float/tags by app-id/title)

View file

@ -617,6 +617,9 @@ fn calculatePrimaryStackLayout(output: *Output) void {
var active_count: u31 = 0; var active_count: u31 = 0;
var it = output.windows.iterator(.forward); var it = output.windows.iterator(.forward);
while (it.next()) |window| { while (it.next()) |window| {
// Initialize new windows before checking tags/float so that
// window rules are reflected in the first frame's layout.
window.initialize();
if (output.tags & window.tags != 0x0000) { if (output.tags & window.tags != 0x0000) {
// Floating windows should be shown but not included in this layout generation // Floating windows should be shown but not included in this layout generation
const will_float = window.pending_manage.floating orelse window.floating; const will_float = window.pending_manage.floating orelse window.floating;

View file

@ -164,13 +164,18 @@ fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event,
} }
} }
pub fn manage(window: *Window) void { /// Apply one-time initialization for newly created windows.
const river_window_v1 = window.river_window_v1; /// Called before calculatePrimaryStackLayout() so that tag and float
if (!window.initialized) { /// rules are reflected in the first frame's layout.
// Only happens once per Window pub fn initialize(window: *Window) void {
if (window.initialized) {
@branchHint(.unlikely); @branchHint(.unlikely);
return;
}
window.initialized = true; window.initialized = true;
const river_window_v1 = window.river_window_v1;
// TODO: We might want to think about paying attention to the decoration_hint event // TODO: We might want to think about paying attention to the decoration_hint event
// If we do, this would need to move, I think? // If we do, this would need to move, I think?
river_window_v1.useSsd(); river_window_v1.useSsd();
@ -184,11 +189,13 @@ pub fn manage(window: *Window) void {
window.pending_manage.floating = should_float window.pending_manage.floating = should_float
else else
window.pending_manage.floating = false; window.pending_manage.floating = false;
} }
pub fn manage(window: *Window) void {
// Updating state since the last manage event // Updating state since the last manage event
defer window.pending_manage = .{}; defer window.pending_manage = .{};
const pending_manage = window.pending_manage; const pending_manage = window.pending_manage;
const river_window_v1 = window.river_window_v1;
// Floating status // Floating status
if (pending_manage.floating) |floating| blk: { if (pending_manage.floating) |floating| blk: {
// This needs to be before proposing the new dimensions since we want to save the current ones! // This needs to be before proposing the new dimensions since we want to save the current ones!