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

8.9 KiB
Raw Permalink Blame History

Fix 002 — DaVinci Resolve's dialogs trap the pointer until Resolve is killed

Status: raised — basecamp/omarchy#6430, fully verified (§5) · Target project: 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, 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

--- 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:

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.

# 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 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 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 §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.