Repository navigation
fix(rules): apply title rules when the title arrives just after opening - #262
Merged
Merged
Conversation
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Title-based placement rules now get one bounded retry shortly after a window opens, with safeguards for intervening user placement changes. The outstanding floating-window correctness finding remains subject to the separate blocking gate. Notes:
You can add or adjust custom eligibility rules. Learn more. |
qeude
force-pushed
the
fix/rules-late-title
branch
from
November 11, 2026 17:26
fb26fb8 to
f3a225a
Compare
macroscopeapp
Bot
dismissed
their stale review
November 11, 2026 17:26
Dismissing prior approval to re-evaluate f3a225a
A window discovered untitled is placed again, once, on its first new title within a second of opening, unless the user moved, resized, or floated it first. The window keeps the focus it already has.
A late title rule re-placed the window in the runtime, but the daemon only ran its opening steps for new windows, so a window made floating on another display kept its frame on the first one. Late-ruled windows now go through the same placement step, without the opening focus rules: their focus was settled when they opened. The test fixture takes a 'title <text>' line on stdin instead of a 'late' argument, so a scenario can set the title at any time.
Moving a column left or right leaves its Column value unchanged, so the late title check missed it and could send the window back to the rule's workspace. The recorded placement now includes the column's index.
qeude
force-pushed
the
fix/rules-late-title
branch
from
November 11, 2026 17:52
5057993 to
1cf2061
Compare
A late rule that kept a focused window on its workspace reinserted it after its right neighbour; the column now goes back to its index. A window already floating when a late monitor rule moved it was rebased twice and landed at the display's edge; the rule rebase now owns it. The fixture's title command, used by no test, is dropped.
Native fullscreen saves the window's tiled placement and restores it on exit. A late rule applied meanwhile left the window on two workspaces.
A late rule without a workspace or display put the window on the monitor's active workspace, so switching workspaces during the grace carried it along; it now stays on its own workspace. A floating window's frame is now part of the recorded placement, so moving or resizing it cancels the late rule.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A
[[rules]]entry withtitleortitle_regexwas only evaluated when Defi first discovered a window. An app that sets its title just after opening never matched.Change
When a newly opened window gets its first new, non-empty title within 1 s of opening, Defi evaluates its rules again, once. If the placement rules changed, it places the window again as if it had opened with that title. The late title comes from the existing snapshot path that already produces
window-changed, with no new Accessibility read or timer.lateTitleRuleGrace(1 s). A title that changes later, such as a browser tab's, never moves a window. Windows already open when Defi starts are skipped.workspace,monitor,window,initial_column_width,intrinsic_size.open_focusedandfollow_focus. Focus was already decided at opening. A focused window follows to its new place; any other window moves without taking focus. The daemon runs its placement step for the late window (a floating window's frame is moved onto the rule's display), but not its opening focus rules.include_initial_width_in_cycleis read at cycle time anyway.Niri reads its
open-*rules once, when the window first maps. Its dynamic rules are re-read on every title change. This change adds a short, one-time window for the case where the title arrives just after the window maps.CONFIGURATION.mddescribes the new behaviour in place of "a title set later never matches".Proof
WindowLifecycleTests: "A title set right after opening applies its rules" fails onmain(3 expectations) and passes here. "A late title never overrides the user or a window in use" covers a title after the grace, a float toggle, a column move, and a non-matching first title, on thenow:virtual clock. "A late title rule on the same workspace keeps the window's column" failed before 347ba60 (the window jumped past its right neighbour). "A late title leaves a native fullscreen window where it is" failed before d3f0a99 (the window ended on two workspaces). "A late rule without a destination keeps the window on its workspace" and "A late title never moves a floating window the user moved" failed before d37b5dd.DaemonDesktopSynchronizationTests.lateTitleRuleMovesTheWindowAsAnOpeningWould: the daemon state after a late title equals the state after an opening with that title, for a workspace rule, a floating rule on a second display, and a window already floating when the rule moves it. The second case failed before 78ff5c7 (frame left on the first display), the third before 347ba60 (frame rebased twice, ending at the display's edge).make verifypasses.defi-e2eVM with the installed daemon,origin/main(0f24f11) against this branch, recorded throughdefi subscribe --jsonand on-screen window bounds. The scenarios used a local fixture variant that sets its title on demand; it is not part of this PR.mainworkspace = "web"web; a focused window takes the view with it, an unfocused one moves quietlyforce-floating+monitoron a second displaytoggle-floatingbefore the titlewebwebExactly one
defi-daemonremained after each scenario.Regression pass,
origin/main(f12ed79) against this branch rebased on it, same scenarios on both:app_idrules (workspace,follow_focus): browser-like title changes (New Tab, then two page titles), a window closed 0.3-0.8 s after opening, two windows opening 0.1 s apart,toggle-floatingbefore a late title, and a rename. The event sequences match; the only differences are whether discovery saw the window before its first title or its close, which varies between runs on both builds.DesktopE2ETestsin the VM: 16 tests, 0 failures on one display; both two-display tests pass with the virtual display.Surfaces
window-openedthenwindow-moved.Not covered
Behaviour change for existing configs: a rule that matches only the first title, such as
title_regex = "^Loading"withforce-floating, is reverted when the title changes within the grace (seen in the VM: the window is tiled again). After the grace it stays.A window that Defi does not manage without a title rule (for example a system dialog with
force-floating) is still decided at discovery.The window is visible in the strip until its title arrives (about 100-400 ms in the VM), then moves. Preventing that would mean delaying placement of untitled windows.
A window floated late keeps the tile size it had in the meantime.
Any change to the window's column in the meantime, including a neighbour opening to its left, cancels the late rule. So does an app moving its own floating window during that second.
Proved by tests that fail without each fix,
make verify, and real-daemon scenarios in thedefi-e2eVM compared againstmain.Reviewed with review-loop: 2 rounds with Claude Opus 5.5. Verdict: approved
Note
Apply window title rules once when the title arrives just after opening
lateTitleRuleGrace), in WindowReconciliation.swiftRuntimeStatetracks candidates (opening title, rule decision, recorded placement, expiry) across reconciliation calls, and desktop synchronization feeds relocated windows into the normal post-reconciliation bookkeeping without the forced open-focus logicDaemon.synchronizeDesktopMacroscope summarized d37b5dd.