From c186dbbceb46cc07313b9d7acb2b8dbe15ca8323 Mon Sep 17 00:00:00 2001 From: 28allday Date: Wed, 29 Jul 2026 14:17:28 +0100 Subject: [PATCH] Add upstream fix handoffs for Omarchy window-rule bugs Two Resolve problems on Omarchy 4.x turned out to be bugs in Omarchy's own Hyprland rules rather than in this installer, so document them as ready-to-raise upstream patches: 001 the status bar covers Resolve's menu bar 002 Resolve's dialogs trap the pointer until Resolve is killed Each file is self-contained: symptom, root cause with captured command output, the exact patch in Omarchy's house style, verification performed, how to re-verify, and reviewer caveats. Both fixes are verified end-to-end on Hyprland 0.56.1 / Omarchy 4.0.0.r1440. Co-Authored-By: Claude Opus 5 (1M context) --- .../001-resolve-bar-overlap.md | 238 ++++++++++++++++++ .../002-resolve-dialog-focus-trap.md | 199 +++++++++++++++ omarchy-upstream-fixes/README.md | 105 ++++++++ 3 files changed, 542 insertions(+) create mode 100644 omarchy-upstream-fixes/001-resolve-bar-overlap.md create mode 100644 omarchy-upstream-fixes/002-resolve-dialog-focus-trap.md create mode 100644 omarchy-upstream-fixes/README.md diff --git a/omarchy-upstream-fixes/001-resolve-bar-overlap.md b/omarchy-upstream-fixes/001-resolve-bar-overlap.md new file mode 100644 index 0000000..51d64c3 --- /dev/null +++ b/omarchy-upstream-fixes/001-resolve-bar-overlap.md @@ -0,0 +1,238 @@ +# Fix 001 — DaVinci Resolve's main window is covered by the Omarchy bar + +**Status:** ready to raise · **Target project:** [omarchy](https://github.com/basecamp/omarchy) +**Target file:** `default/hypr/apps/davinci-resolve.lua` +**Change type:** append one window rule + explanatory comment. No new deps, no other app affected. + +> This file is a self-contained handoff. Everything needed to raise the PR — +> problem, root cause, exact patch, and reproduction/verification steps — is +> below. No other file in this repo is required. + +--- + +## 1. Symptom + +On Omarchy 4.x, launching DaVinci Resolve leaves Resolve's **own** menu bar +(File / Edit / Trim / Timeline / Clip / …) hidden underneath the Omarchy status +bar, so those menus cannot be clicked. + +## 2. Root cause + +`omarchy-bar` is a layer-shell surface on Hyprland's `top` layer with a 26px +exclusive zone: + +``` +$ hyprctl layers +Layer level 2 (top): + Layer ...: xywh: 0 0 2560 26, a: 1, namespace: omarchy-bar, pid: 1582 +``` + +That reserved zone only constrains **tiled** windows. It is being honoured +correctly — `hyprctl monitors` reports `reserved: [0, 26, 0, 0]`, and tiled +windows start at y=38 as expected. + +The problem is that Resolve is not tiled. `default/hypr/apps/davinci-resolve.lua` +floats every Resolve window, which is the right call — Resolve's many child +windows tile badly. But floating windows are positioned by the client, and +Resolve's XWayland main window places itself at **0,0 at the full monitor +size**, ignoring the reserved zone entirely: + +``` +class='resolve' title='DaVinci Resolve - New Project 2' at=[0, 0] size=[2560, 1440] float=True fs=0 +``` + +So the bar, being on the `top` layer, draws over it. + +## 3. Fix + +Hyprland renders a fullscreen window **above** `top`-layer layer-shell surfaces. +Opening Resolve's main window fullscreen therefore puts Resolve over the bar +instead of under it. The bar is not modified, hidden, or killed — it behaves +normally again as soon as you leave fullscreen or focus another window. + +### Why the title match must be narrow + +Every Resolve window shares the same class, and only the main one may be +fullscreened. Windows observed during a cold start: + +| window | title | size | fullscreened | +| --------------- | ---------------------------------- | --------- | ------------ | +| splash screen | `resolve` | 740×326 | no | +| project chooser | `Project Manager` | 900×512 | no | +| modal dialogs | e.g. `Preferences` | 630×534 | no | +| main window | `DaVinci Resolve - ` | 2560×1440 | **yes** | + +Requiring the `" - "` suffix leaves the splash, the Project Manager and +Resolve's modal dialogs floating at their natural size. A class-only rule would +fullscreen all of them, which is why the rule is title-scoped. + +The class pattern `.*[Rr]esolve.*` is kept byte-identical to the existing rule in +this file for consistency; the title is what does the scoping. Both patterns +were verified together as the exact string in the patch (see §5), not inferred +from testing the two halves separately. + +## 4. The patch + +Four lines: a blank, a three-line comment, and the rule. Apply with `git apply`: + +```diff +--- a/default/hypr/apps/davinci-resolve.lua ++++ b/default/hypr/apps/davinci-resolve.lua +@@ -6,3 +6,9 @@ + tag = "-default-opacity", + opacity = "1 1", + }) ++ ++-- Resolve's floating main window ignores the bar's reserved zone, so the bar ++-- covers its menu bar; fullscreen renders above top-layer surfaces. Scoped by ++-- title so the splash and Project Manager keep their natural size. ++o.window({ class = ".*[Rr]esolve.*", title = "^DaVinci Resolve - .+$" }, { fullscreen = true }) +``` + +If the diff doesn't apply cleanly (upstream moved), the change is just +**append the comment and this line to the end of the file**: + +```lua +o.window({ class = ".*[Rr]esolve.*", title = "^DaVinci Resolve - .+$" }, { fullscreen = true }) +``` + +### Resulting complete file + +```lua +-- DaVinci Resolve window focus handling. Kept fully opaque: the default +-- translucency distorts colour-critical grading work. +o.window(".*[Rr]esolve.*", { + float = true, + stay_focused = true, + tag = "-default-opacity", + opacity = "1 1", +}) + +-- Resolve's floating main window ignores the bar's reserved zone, so the bar +-- covers its menu bar; fullscreen renders above top-layer surfaces. Scoped by +-- title so the splash and Project Manager keep their natural size. +o.window({ class = ".*[Rr]esolve.*", title = "^DaVinci Resolve - .+$" }, { fullscreen = true }) +``` + +### Optional, once the PR is open + +`default/hypr/apps/jetbrains.lua` sets the precedent of keeping the code terse +and parking the deep rationale behind a link: + +```lua +-- Disable mouse focus (see https://github.com/basecamp/omarchy/pull/5183#issuecomment-4189299971). +``` + +If a reviewer wants more detail inline than the three lines give, follow that +pattern — append `(see )` to the comment rather than expanding +the comment block. + +## 5. Verification performed + +Tested on Hyprland 0.56.1 / Omarchy 4.0.0.r1440, NVIDIA, 2560×1440 logical +(3840×2160 physical, scale 1.5). + +Method: sample the top 26px strip with `grim`. Bar colour is `(26,27,38)`; +Resolve's UI chrome is `(23,24,26)`. + +**Before** — bar covers Resolve: + +``` + y= 5 [(26, 27, 38), (26, 27, 38), (26, 27, 38)] <- bar + y= 20 [(26, 27, 38), (26, 27, 38), (26, 27, 38)] <- bar + y= 35 [(26, 27, 38), (26, 27, 38), (26, 27, 38)] <- bar + y= 45 [(23, 24, 26), (23, 24, 26), (23, 24, 26)] <- Resolve only starts here +``` + +**After** — Resolve renders over the bar, its menu text now visible at y=35: + +``` + y= 5 [(23, 24, 26), (23, 24, 26), (23, 24, 26)] + y= 20 [(23, 24, 26), (23, 24, 26), (23, 24, 26)] + y= 35 [(179, 180, 180), (23, 24, 26), (23, 24, 26)] <- menu text + y= 45 [(23, 24, 26), (23, 24, 26), (23, 24, 26)] +``` + +With the exact rule string above installed, a cold start produces precisely the +intended scoping — only the main window is fullscreened, and a modal dialog that +happened to open during the run was correctly left alone: + +``` +title='resolve' size=[740, 326] FULLSCREEN=0 +title='Project Manager' size=[900, 512] FULLSCREEN=0 +title='DaVinci Resolve - New Project 2' size=[2560, 1440] FULLSCREEN=2 +title='Preferences' size=[630, 534] FULLSCREEN=0 +``` + +That `Preferences` line is the important one: it is the failure mode a +class-only rule would produce (a 630×534 dialog blown up to fill the screen), +and it demonstrably does not happen. + +Also confirmed visually by the reporting user. + +### How to re-verify + +```bash +# 1. Watch what Resolve opens, and at what size / fullscreen state +(while :; do + hyprctl clients -j | jq -r '.[] | select(.class=="resolve") + | "title=\(.title) size=\(.size) FULLSCREEN=\(.fullscreen)"' + sleep 2 + done) | sort -u & + +# 2. Launch Resolve, then SELECT A PROJECT in the Project Manager. +# Resolve never opens a project on its own, so an unattended launch stops +# at the chooser and the main window never appears. +# 3. Confirm the top strip belongs to Resolve, not the bar +grim -g "0,0 1200x60" /tmp/top.png +``` + +Expect the splash and Project Manager at `FULLSCREEN=0`, and only +`DaVinci Resolve - ` at `FULLSCREEN=2`. + +## 6. Upstream conventions this follows + +Checked against every file in `default/hypr/apps/` on omarchy 4.0.0.r1440, not +assumed. Keep these in mind if the patch is reworked. + +| Convention | Evidence upstream | How this patch complies | +|---|---|---| +| Comments are terse — **3 lines is the maximum** anywhere in `apps/` | longest are `webcam-overlay.lua`, `system.lua`, `omarchy-shell.lua` at 3 lines; most files have 0–1 | 3-line comment | +| Deep rationale goes in the PR, linked from code — not expanded inline | `jetbrains.lua` links a PR comment for its one-line rule | full rationale lives in this file / the PR; optional link noted above | +| Class+title matching uses the table form `o.window({ class = …, title = … }, { … })` | `battlenet.lua`, `omarchy-shell.lua`, `system.lua` | same form | +| Single-property rules stay inline on one line; only multi-property rules break across lines | `moonlight.lua`, `geforce.lua`, `qemu.lua` inline vs `retroarch.lua`, `pip.lua` multi-line | one property (`fullscreen = true`), inline | +| `fullscreen = true` is the established idiom for this | `moonlight.lua`, `retroarch.lua`, `system.lua` (screensaver) | same property | +| Long lines are acceptable — no wrapping for its own sake | `omarchy-shell.lua` (~180 chars), `browser.lua` (~150) | rule line is ~95 chars | +| Regex metacharacters escaped as `\\.` in Lua strings | `battlenet.lua`: `"^Battle\\.net$"` | no literal dot in the title; `.+` is intentional | +| 2-space indent, double-quoted strings | throughout | matches | +| One app per file, named after the app | the whole directory | extends the existing `davinci-resolve.lua` rather than adding a file | + +Note the packaged copy of Omarchy ships no `stylua.toml`, `.editorconfig` or +`CONTRIBUTING.md` (they aren't included in the package), so style here is +inferred from the source files themselves. Check the GitHub repo for a +formatter config before raising, and run it if one exists. + +## 7. Suggested PR text + +**Title** + +``` +hypr/apps: open DaVinci Resolve's main window fullscreen so it isn't covered by the bar +``` + +**Body** — sections 1, 2, 3 and 5 above, in that order. + +## 8. Caveats for the reviewer + +- Only the **main** window is fullscreened; splash, Project Manager and modal + dialogs are untouched. This is the whole point of the title scoping. +- If a user leaves fullscreen manually, the bar covers Resolve again — inherent + to the approach, and recoverable with `SUPER + F`. +- The title is matched at window-open time. If a future Resolve release changes + its main-window title format away from `DaVinci Resolve - `, the rule + silently stops matching and the old behaviour returns. It fails safe: no + window gets wrongly fullscreened. +- An alternative considered and rejected: having Resolve's launcher run + `omarchy toggle bar off` and restore it on exit. It needs no window titles, + but hides the bar system-wide across all workspaces for as long as Resolve is + open, and leaves the bar hidden if the process is killed uncleanly. diff --git a/omarchy-upstream-fixes/002-resolve-dialog-focus-trap.md b/omarchy-upstream-fixes/002-resolve-dialog-focus-trap.md new file mode 100644 index 0000000..9ca1f49 --- /dev/null +++ b/omarchy-upstream-fixes/002-resolve-dialog-focus-trap.md @@ -0,0 +1,199 @@ +# Fix 002 — DaVinci Resolve's dialogs trap the pointer until Resolve is killed + +**Status:** ready to raise — fully verified (§5) · **Target project:** [omarchy](https://github.com/basecamp/omarchy) +**Target file:** `default/hypr/apps/davinci-resolve.lua` +**Change type:** append one window rule + comment. Narrows an existing rule; removes nothing. + +> Self-contained handoff. Problem, root cause, patch and verification are all +> below. No other file in this repo is required. + +> Both halves are verified: the trap is measurably gone, and the popup +> behaviour `stay_focused` protects is confirmed intact. See §7 for the one +> remaining known limitation and an open design question for the maintainer. + +--- + +## 1. Symptom + +Opening certain DaVinci Resolve windows — confirmed with **Preferences** and +**Project Manager** — traps the pointer. The dialog cannot be dismissed and no +other window can be clicked. **Quitting Resolve entirely is the only way out.** + +## 2. Root cause + +`default/hypr/apps/davinci-resolve.lua` sets `stay_focused = true` on +`.*[Rr]esolve.*` — that is, on *every* Resolve window. + +That rule is there for a real reason and **must not simply be deleted**. +Resolve is not Wayland-native, so Hyprland misreads its transient popups +(Change Clip Duration, Normalize Audio Levels, …) and they close the moment the +pointer leaves them unless focus is pinned. See +[hyprwm/Hyprland#12235](https://github.com/hyprwm/Hyprland/discussions/12235), +which is where the `stayfocused` workaround originates. + +The bug is that it is applied **too broadly**. `stayfocused` forces focus onto a +window while it is visible. When two Resolve windows are visible at once, both +demand focus and neither yields, so Hyprland flips between them indefinitely. + +Captured live, sampling `hyprctl activewindow` every 0.4s, with the Project +Manager and its own child dialog both open: + +``` +t=361.7 ACTIVE='resolve'|'Create New Project' resolve_windows=['Project Manager', 'Create New Project'] +t=365.4 ACTIVE='resolve'|'Project Manager' resolve_windows=['Project Manager', 'Create New Project'] +t=365.8 ACTIVE='resolve'|'Create New Project' resolve_windows=['Project Manager', 'Create New Project'] +``` + +Focus oscillates between the two. Neither can be acted on, which is exactly what +"the mouse is captured" looks like from the user's side. + +## 3. Fix + +Keep the pin where it is needed — the transient popups — and remove it from the +windows those popups open *over*. At most one pinned window is then ever +visible, so nothing can fight. + +The two parent windows are the main window and the Project Manager: + +| window | role | pinned after fix | +|---|---|---| +| `DaVinci Resolve - ` | parent of Preferences, Change Clip Duration, … | no | +| `Project Manager` | parent of Create New Project | no | +| `Preferences`, `Create New Project`, transient popups | children | yes | + +This is a narrowing, not a removal: every window that previously relied on +`stay_focused` to stay open still has it. + +## 4. The patch + +```diff +--- a/default/hypr/apps/davinci-resolve.lua ++++ b/default/hypr/apps/davinci-resolve.lua +@@ -6,3 +6,8 @@ + tag = "-default-opacity", + opacity = "1 1", + }) ++ ++-- stay_focused above stops Resolve's transient popups closing on mouse-out ++-- (hyprwm/Hyprland#12235), but pinning the windows they open over makes two ++-- windows fight for focus and traps the pointer. Unpin the parents only. ++o.window({ class = ".*[Rr]esolve.*", title = "^(DaVinci Resolve - .+|Project Manager)$" }, { stay_focused = false }) +``` + +Independent of fix 001 — different property, order between them doesn't matter. + +## 5. Verification performed + +Hyprland 0.56.1 / Omarchy 4.0.0.r1440, NVIDIA, 2560×1440 logical. + +**The override mechanism is confirmed.** A later, more specific rule does beat +an earlier blanket one, tested in isolation with a throwaway class so nothing +about Resolve could confound it: + +```lua +o.window("^(OVERRIDETEST)$", { float = true }) +o.window({ class = "^(OVERRIDETEST)$", title = "^nofloat$" }, { float = false }) +``` +``` +title='nofloat' floating=False <- later specific rule wins +title='yesfloat' floating=True <- blanket rule still applies +``` + +**The oscillation is confirmed** — see the focus log in §2. + +**The trap is confirmed removed, by cold-start A/B.** Resolve was started fresh +twice — once with the fix, once with *only* the `stay_focused` exclusion removed +(fix 001 left in place, so the exclusion was the sole variable). In each run +Resolve was focused, focus was then dispatched to another window, and the actual +focus owner sampled 12 times at 0.5s intervals: + +| run | config | samples where Resolve held focus | verdict | +|---|---|---|---| +| A | with fix | **0 / 12** | focus sticks elsewhere — not trapped | +| B | control, exclusion removed | **11 / 12** | snaps back to Resolve — trapped | + +The control matters: it demonstrates the test can actually detect the trap, so +run A's result is meaningful rather than vacuous. + +Both runs exercised the **Project Manager**, one of the two windows the rule +excludes and one of the two originally reported. + +**The main window and the popups were then confirmed by hand.** Resolve always +requires a project to be selected from the Project Manager before the main +window opens — it never opens one on its own — so these two checks cannot be +automated and were driven manually by the reporting user: + +| check | procedure | result | +|---|---|---| +| Main window no longer traps | Open a project, open **Preferences** from the main window | **Pass** — dismissable, and other applications remain clickable while it is open | +| Popups do not regress | Edit page → right-click clip → **Change Clip Duration**, move pointer off the popup onto the main window | **Pass** — popup stays open | + +The second row is the one that matters most: it is the behaviour +`stay_focused` exists to protect, and it survives the narrowing intact. + +## 6. How to verify properly + +Both halves must be checked — the fix is only correct if it fixes the trap +**and** leaves the popups alone. + +```bash +# Log every focus transition while you drive Resolve by hand +while :; do + hyprctl activewindow -j | jq -r '"ACTIVE=\(.class)|\(.title)"' + sleep 0.4 +done | uniq +``` + +Note: Resolve never opens a project on its own — you must select one in the +Project Manager before the main window appears. Both checks below therefore have +to be driven by hand; an unattended launch stops at the chooser. + +1. **The trap is gone** — cold-start Resolve, open Project Manager → Create New + Project, then select a project and open Preferences from the main window. + Each dialog should take focus and stay there; you should be able to dismiss + it and click other apps. The log must show no rapid flip-flopping between two + `resolve` windows. +2. **No popup regression** — in the edit page, open a transient popup (right-click + a clip → Change Clip Duration, or Normalize Audio Levels) and move the pointer + off it onto the main window. It must **not** vanish. This is the behaviour + `stay_focused` exists to protect. + +## 7. Caveats for the reviewer + +- **The parent list is a blocklist and will need extending.** Only + `DaVinci Resolve - ` and `Project Manager` are excluded. If another + Resolve window can itself parent a dialog (Project Settings and the Deliver + page are the likely candidates), it will reintroduce the trap and must be + added to the alternation. +- **A cleaner long-term fix may exist.** Hyprland 0.53.3+ added + `input:mouse_refocus`, and [#12235](https://github.com/hyprwm/Hyprland/discussions/12235) + notes `mouse_refocus = 0` as an alternative to `stayfocused` entirely. On + 0.56.1 the underlying popup bug may even be fixed, which would make the whole + `stay_focused` rule obsolete. That was not tested here because + `mouse_refocus` is a **global** input setting, not a per-window rule, so + flipping it for every Omarchy user is a much larger decision than this + narrowing. Worth a maintainer's opinion. +- Related open issue: [basecamp/omarchy#5887](https://github.com/basecamp/omarchy/issues/5887) + reports Resolve child windows becoming inaccessible on Omarchy 4.0.0.alpha. + It doesn't mention `stayfocused`, but "child windows become inaccessible when + the main panel is clicked" is consistent with this root cause, and this fix + may resolve it. Worth linking in the PR. + +## 8. Upstream conventions this follows + +Same set verified for fix 001 — see +[`001-resolve-bar-overlap.md`](001-resolve-bar-overlap.md) §6. Specifically: +3-line comment (house max), table-match form for class+title, single-property +rule inline on one line, 2-space indent, extends the existing app file rather +than adding a new one. + +## 9. Suggested PR text + +**Title** + +``` +hypr/apps: stop DaVinci Resolve's dialogs trapping the pointer +``` + +**Body** — sections 1, 2 and 3 above, then the §5 evidence, then the §7 bullets +stated as known limitations. diff --git a/omarchy-upstream-fixes/README.md b/omarchy-upstream-fixes/README.md new file mode 100644 index 0000000..c301070 --- /dev/null +++ b/omarchy-upstream-fixes/README.md @@ -0,0 +1,105 @@ +# Upstream fixes for Omarchy + +Fixes found while getting DaVinci Resolve working on Omarchy that belong +**upstream in [omarchy](https://github.com/basecamp/omarchy)** rather than in +this installer script. + +Each file here is a **self-contained handoff**: one numbered Markdown file per +fix, containing everything needed to raise the PR with no other context — +symptom, root cause with evidence, the exact patch, verification already +performed, how to re-verify, and reviewer caveats. Hand one file to a person or +an AI and they can open the PR from it alone. + +| # | Fix | Target file | Status | +| --- | ---------------------------------------------------------------- | ------------------------------------------ | -------------- | +| 001 | [Resolve's main window is covered by the bar](001-resolve-bar-overlap.md) | `default/hypr/apps/davinci-resolve.lua` | ready to raise | +| 002 | [Resolve's dialogs trap the pointer](002-resolve-dialog-focus-trap.md) | `default/hypr/apps/davinci-resolve.lua` | ready to raise | + +## Raising 001 and 002 — read first + +Both fixes append to the **same file**, `default/hypr/apps/davinci-resolve.lua`, +and both diffs are anchored on the same context (`@@ -6,3 @@`, the end of the +original 8-line file). **Whichever lands first will make the other's patch fail +to apply.** They are otherwise independent — different properties, order between +them doesn't matter. + +**Raise them as two PRs, 001 first. Do not combine them.** + +Combining is tempting — same file, both small — and it does sidestep the patch +conflict. That's the weakest consideration: rebasing 002 after 001 lands means +appending two rules to the end of a file, with no semantic conflict. + +The reason to keep them apart is that they carry very different risk: + +| | 001 (bar overlap) | 002 (focus trap) | +|---|---|---| +| Nature | purely additive — a new rule for a window that had none | **narrows a rule a maintainer added deliberately** | +| Verified | end-to-end, including negative cases | end-to-end — cold-start A/B, plus hands-on main-window and popup checks | +| If wrong | fails safe — rule stops matching, old behaviour returns | popups vanish on mouse-out: worse than the bug being fixed | +| Likely review | uncontroversial | may attract debate (`mouse_refocus`, blocklist fragility) | + +002 touches `stay_focused`, which exists for a documented reason, and carries an +open design question for a maintainer (see its §7). Coupling them makes the +clean, low-risk fix wait on the more debatable one for no benefit. + +Both are now fully verified, so 002 no longer needs holding — raise them in +close succession, 001 first. + +If a maintainer explicitly asks for them together, use the combined end state +below as the target — one PR, two commits. + +### Combined end state (both fixes applied) + +```lua +-- DaVinci Resolve window focus handling. Kept fully opaque: the default +-- translucency distorts colour-critical grading work. +o.window(".*[Rr]esolve.*", { + float = true, + stay_focused = true, + tag = "-default-opacity", + opacity = "1 1", +}) + +-- Resolve's floating main window ignores the bar's reserved zone, so the bar +-- covers its menu bar; fullscreen renders above top-layer surfaces. Scoped by +-- title so the splash and Project Manager keep their natural size. +o.window({ class = ".*[Rr]esolve.*", title = "^DaVinci Resolve - .+$" }, { fullscreen = true }) + +-- stay_focused above stops Resolve's transient popups closing on mouse-out +-- (hyprwm/Hyprland#12235), but pinning the windows they open over makes two +-- windows fight for focus and traps the pointer. Unpin the parents only. +o.window({ class = ".*[Rr]esolve.*", title = "^(DaVinci Resolve - .+|Project Manager)$" }, { stay_focused = false }) +``` + +### State the testing accurately + +Both fixes are verified end-to-end; each file's §5 lists exactly what was +measured and what was checked by hand. Two things are worth carrying into the +PR bodies rather than quietly dropping: + +- 002's parent list is a **blocklist** that may need extending (its §7). +- 002 has an **open design question** — whether `input:mouse_refocus` makes the + whole `stay_focused` rule obsolete on Hyprland 0.56.1. Not tested, because it + is a global setting and that is a maintainer's call. + +## Conventions + +- **Filename:** `NNN-short-slug.md`, numbered in the order found. +- **Status:** `ready to raise` → `raised (#PR)` → `merged` / `rejected`. Update + the table above when it changes. +- **Evidence over assertion.** Every claim about behaviour should be backed by + command output pasted into the file (`hyprctl`, `grim` pixel samples, logs), + so a reviewer can judge it without reproducing the setup. +- **State what was actually tested**, including the environment (Hyprland and + Omarchy versions, GPU, resolution/scale). If something was reasoned about but + not run, say so explicitly. +- **Record rejected alternatives** and why, in the caveats section — it saves + the reviewer re-proposing them. + +## Relationship to the installer + +Until a fix lands upstream, `Omarchy_resolve_v2.sh` applies its own local +equivalent so the installer works today. Those local workarounds are marked in +the script with a comment pointing back to the fix number here. Once a fix is +merged upstream the local workaround becomes redundant — harmless, but it can +then be dropped.