DaVinci-Resolve-Omarchy/omarchy-upstream-fixes/002-resolve-dialog-focus-trap.md
28allday a1c5971702 Mark upstream fixes 001/002 as raised, record quattro as the target branch
PRs basecamp/omarchy#6429 and #6430. Both target `quattro` — upstream `master`
is still Omarchy 3 and has no default/hypr/apps/davinci-resolve.lua at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 17:02:33 +01:00

200 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Fix 002 — DaVinci Resolve's dialogs trap the pointer until Resolve is killed
**Status:** raised — [basecamp/omarchy#6430](https://github.com/basecamp/omarchy/pull/6430), fully verified (§5) · **Target project:** [omarchy](https://github.com/basecamp/omarchy)
**Target branch:** `quattro` (Omarchy 4 lives there; `master` is still Omarchy 3 and has no Lua config)
**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 - <project>` | 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 - <project>` 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.