diff --git a/Omarchy_resolve_v2.sh b/Omarchy_resolve_v2.sh index 05416d9..14fc0d8 100755 --- a/Omarchy_resolve_v2.sh +++ b/Omarchy_resolve_v2.sh @@ -24,6 +24,8 @@ # 7. Ensures legacy libcrypt.so.1 is available (Arch dropped it) # 8. Installs desktop entries, icons, and udev rules # 9. Creates an XWayland wrapper script for Hyprland compatibility +# 10. Installs Hyprland window rules so the Omarchy bar doesn't cover Resolve's +# menu bar, and Resolve's dialogs don't trap the pointer # # Prerequisites: # - Omarchy (Arch Linux) with NVIDIA drivers installed and working @@ -463,6 +465,11 @@ sudo gtk-update-icon-cache -f /usr/share/icons/hicolor >/dev/null 2>&1 || true # Only runs when an Omarchy 4 Lua config is detected; pre-4 installs never # applied global translucency, so they need nothing. Idempotent via the # "resolve-full-opacity" marker. +# +# UPSTREAM: fixed in Omarchy by basecamp/omarchy#6382, which added +# opacity = "1 1" to its own davinci-resolve.lua. This block is therefore +# redundant on current Omarchy and only still matters on Omarchy 4 builds +# predating that PR. Harmless either way — same rule, same value. HYPR_LUA="${HOME}/.config/hypr/hyprland.lua" if [[ -f "${HYPR_LUA}" ]] && grep -q 'default\.hypr\.omarchy' "${HYPR_LUA}"; then if grep -q 'resolve-full-opacity' "${HYPR_LUA}"; then @@ -483,6 +490,130 @@ else log "No Omarchy 4 Lua config detected, skipping opacity rule (not needed pre-4)" fi +# ==================== Hyprland window rules ==================== +# +# Two Omarchy-specific Resolve problems are fixed here, both by installing +# Hyprland window rules: +# 1. the status bar covers Resolve's menu bar (omarchy-upstream-fixes/001) +# 2. dialogs trap the pointer until Resolve dies (omarchy-upstream-fixes/002) +# +# UPSTREAM: both are local workarounds. If they land in Omarchy itself this +# block becomes redundant (harmless — the rules are byte-identical to the ones +# proposed upstream — but it can then be dropped). +# +# ---- 1. Bar overlap ---- +# +# On Omarchy 4.x the status bar is a Quickshell layer-shell surface (namespace +# "omarchy-bar") sitting on Hyprland's "top" layer. It reserves a 26px +# exclusive zone at the top of the screen, which correctly pushes *tiled* +# windows down. +# +# Resolve is not tiled. Omarchy floats every Resolve window on purpose (see +# /usr/share/omarchy/default/hypr/apps/davinci-resolve.lua) because Resolve's +# many child windows tile badly. 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. The bar then draws on top of +# Resolve's own menu bar (File / Edit / Trim / Timeline / Clip / ...), making +# it unclickable. +# +# THE FIX: Hyprland renders a fullscreen window ABOVE "top"-layer layer-shell +# surfaces, so opening Resolve's main window fullscreen puts it over the bar +# instead of under it. We install a Hyprland window rule that does exactly that. +# +# The rule is deliberately scoped by title. Every Resolve window shares the +# class "resolve", and only the main one may be fullscreened: +# splash screen -> title "resolve" +# project chooser -> title "Project Manager" +# main window -> title "DaVinci Resolve - " +# Requiring the " - " suffix leaves the splash, the Project Manager +# and Resolve's modal dialogs floating at their natural size. +# +# ---- 2. Dialogs trapping the pointer ---- +# +# Omarchy sets `stay_focused = true` on ".*[Rr]esolve.*" — every Resolve window. +# That rule exists for a good reason: Resolve is not Wayland-native, and its +# transient popups (Change Clip Duration, Normalize Audio Levels, ...) close as +# soon as the pointer leaves them unless focus is pinned. See +# https://github.com/hyprwm/Hyprland/discussions/12235 +# +# But pinning EVERY Resolve window means that whenever two are visible at once, +# both demand focus and neither yields. Hyprland then flips focus back and +# forth between them and the dialog can't be dismissed — the pointer is stuck +# until Resolve is killed. Observed live, flipping between two windows: +# ACTIVE='Create New Project' windows=['Project Manager','Create New Project'] +# ACTIVE='Project Manager' windows=['Project Manager','Create New Project'] +# ACTIVE='Create New Project' windows=['Project Manager','Create New Project'] +# +# THE FIX: keep the pin on the transient popups, but remove it from the two +# windows those popups open *over* — the main window and the Project Manager. +# At most one pinned window is then ever visible, so nothing can fight. A later, +# more specific rule overrides an earlier one (verified on Hyprland 0.56.1). +# +# Skipped if RESOLVE_NO_HYPR_RULES=1 (e.g. you prefer Resolve windowed, or you +# don't want the installer touching your Hyprland config at all). +if [[ "${RESOLVE_NO_HYPR_RULES:-0}" == "1" ]]; then + log "Skipping Hyprland window rules (RESOLVE_NO_HYPR_RULES=1)" +elif [[ ! -f "${HOME}/.config/hypr/hyprland.lua" ]]; then + # Omarchy 4.x configures Hyprland in Lua. Older Hyprland setups use + # hyprland.conf with a different, version-dependent rule syntax, so rather + # than write something unverified we tell the user what to add. + warn "No ${HOME}/.config/hypr/hyprland.lua found — skipping the Hyprland rules." + warn "If the bar covers Resolve's menu bar, or dialogs trap the pointer, add:" + warn " windowrulev2 = fullscreen, class:^(resolve)\$, title:^(DaVinci Resolve - .+)\$" + warn " windowrulev2 = stayfocused off, class:^(resolve)\$, title:^(DaVinci Resolve - .+|Project Manager)\$" +else + log "Installing Hyprland rules (bar overlap + dialog pointer trap)..." + RESOLVE_HYPR_MODULE="${HOME}/.config/hypr/davinci-resolve.lua" + # Kept byte-identical to the rules proposed upstream in + # omarchy-upstream-fixes/001 and /002, including comment wording and Omarchy's + # house style (max 3-line comments in default/hypr/apps/), so that if they land + # upstream this file is a redundant duplicate rather than a divergent rule. + cat > "${RESOLVE_HYPR_MODULE}" <<'EOF' +-- DaVinci Resolve — installed by Omarchy_resolve_v2.sh. +-- Delete this file and the require() line in hyprland.lua to revert. + +-- 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 }) + +-- Resolve's transient popups close on mouse-out unless focus is pinned, but +-- pinning the windows they open *over* makes two stay_focused windows fight +-- and traps the pointer until Resolve is killed. Unpin the parents only. +o.window({ class = ".*[Rr]esolve.*", title = "^(DaVinci Resolve - .+|Project Manager)$" }, { stay_focused = false }) +EOF + + # Omarchy's hyprland.lua require()s each user module explicitly — there is no + # auto-loaded drop-in directory. package.path includes ~/.config/?.lua, so + # "hypr.davinci-resolve" resolves to the file written above. Only append the + # require if it isn't already there, so re-running this installer is safe. + RESOLVE_HYPR_MAIN="${HOME}/.config/hypr/hyprland.lua" + if grep -q 'require("hypr.davinci-resolve")' "${RESOLVE_HYPR_MAIN}"; then + log " require(\"hypr.davinci-resolve\") already present in hyprland.lua" + else + cp "${RESOLVE_HYPR_MAIN}" "${RESOLVE_HYPR_MAIN}.bak.$(date +%s)" + cat >> "${RESOLVE_HYPR_MAIN}" <<'EOF' + +-- Open DaVinci Resolve's main window over the Omarchy bar instead of under it. +require("hypr.davinci-resolve") +EOF + log " Added require to hyprland.lua (backup .bak. created)" + fi + + # Apply immediately if Hyprland is running, and surface any config error + # rather than letting it fail silently until the next login. + if command -v hyprctl >/dev/null 2>&1 && hyprctl version >/dev/null 2>&1; then + hyprctl reload >/dev/null 2>&1 || true + HYPR_ERRORS="$(hyprctl configerrors 2>/dev/null || true)" + if [[ -n "${HYPR_ERRORS}" && "${HYPR_ERRORS}" != "no errors" ]]; then + warn " Hyprland reported config errors after reload:" + warn "${HYPR_ERRORS}" + else + log " Reloaded Hyprland (no config errors)" + fi + fi +fi + # ==================== Audio backend fix (DeckLink → ALSA) ==================== # # Resolve ships with `Local.Audio.Type = DeckLink` as the default in its @@ -644,7 +775,9 @@ echo echo "✅ DaVinci Resolve installed to /opt/resolve" echo " (vendor libc++ kept; libcrypt.so.1 ensured; audio backend → ALSA + snd-aloop)" echo " (Omarchy 4: full-opacity window rule added — grading needs opaque windows)" +echo " Hyprland rules installed: Resolve sits over the bar; dialogs no longer trap the pointer" echo " Launch from your app menu, or run: resolve-nvidia-open" echo " Skip snd-aloop module setup: RESOLVE_NO_ALOOP=1 ./Omarchy_resolve_v2.sh" +echo " Skip the Hyprland window rules: RESOLVE_NO_HYPR_RULES=1 ./Omarchy_resolve_v2.sh" echo " Logs: ~/.local/share/DaVinciResolve/logs/ResolveDebug.txt" echo diff --git a/README.md b/README.md index aa2399a..af6b6ec 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,78 @@ Idempotent; skipped entirely on pre-4 installs, which never applied global translucency. To remove it, delete the `resolve-full-opacity` block from `~/.config/hypr/hyprland.lua`. +This one has since landed upstream ([basecamp/omarchy#6382](https://github.com/basecamp/omarchy/pull/6382)), +so on current Omarchy the rule is a harmless duplicate of Omarchy's own; it +still matters on Omarchy 4 builds predating that PR. + +### 9. Omarchy Bar Overlap Fix + +On Omarchy 4.x, Resolve launches with its own menu bar (File / Edit / Trim / +Timeline / …) hidden underneath the Omarchy status bar, so those menus can't be +clicked. + +The Omarchy bar is a layer-shell surface on Hyprland's `top` layer that reserves +26px at the top of the screen. That reserved space only constrains *tiled* +windows — and Omarchy deliberately floats every Resolve window, because +Resolve's many child windows tile badly. 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. The bar then draws on top of it. + +Hyprland renders a fullscreen window *above* `top`-layer surfaces, so the script +installs a Hyprland rule that opens Resolve's main window fullscreen — putting +Resolve over the bar instead of under it. The bar isn't hidden or killed, and +behaves normally again as soon as you leave fullscreen or focus another window. + +The rule is scoped by window title, because every Resolve window shares the same +class and only the main one may be fullscreened: + +| window | title | fullscreened? | +|-----------------|------------------------------------|---------------| +| splash screen | `resolve` | no | +| project chooser | `Project Manager` | no | +| modal dialogs | e.g. `Preferences` | no | +| main window | `DaVinci Resolve - ` | yes | + +Two files are written (`~/.config/hypr/davinci-resolve.lua` and one `require` +line appended to `~/.config/hypr/hyprland.lua`), then Hyprland is reloaded. +Re-running the installer won't duplicate the `require`, and `hyprland.lua` is +backed up before it's touched. + +### 10. Dialog Pointer Trap Fix + +Opening Resolve's **Preferences** or **Project Manager** could trap the pointer: +the dialog couldn't be dismissed, nothing else could be clicked, and quitting +Resolve was the only way out. + +Omarchy sets `stay_focused = true` on every Resolve window. That rule exists for +a good reason — Resolve isn't Wayland-native, so its transient popups (Change +Clip Duration, Normalize Audio Levels…) close as soon as the pointer leaves them +unless focus is pinned ([Hyprland #12235](https://github.com/hyprwm/Hyprland/discussions/12235)). +Deleting it outright would bring that problem back. + +The trouble is it's applied to *all* Resolve windows. When two are visible at +once, both demand focus and neither yields, so Hyprland flips between them +forever. Captured live: + +``` +ACTIVE='Create New Project' windows=['Project Manager', 'Create New Project'] +ACTIVE='Project Manager' windows=['Project Manager', 'Create New Project'] +ACTIVE='Create New Project' windows=['Project Manager', 'Create New Project'] +``` + +The script narrows the rule instead of removing it: the pin stays on the +transient popups, and comes off the two windows those popups open *over* — the +main window and the Project Manager. At most one pinned window is ever visible, +so nothing can fight, and every window that relied on the pin still has it. + +Set `RESOLVE_NO_HYPR_RULES=1` to skip both Hyprland rules entirely. + +> Both of these belong upstream in Omarchy rather than in this installer — see +> [`omarchy-upstream-fixes/`](omarchy-upstream-fixes/) for the ready-to-raise +> patches. Both are verified end-to-end; fix 002's caveats section lists the +> known limitation (its parent list is a blocklist) and an open design question +> for a maintainer. + ## Files Installed ### Application @@ -178,6 +250,13 @@ translucency. To remove it, delete the `resolve-full-opacity` block from | `/usr/local/bin/resolve-nvidia-open` | XWayland wrapper (main launcher) | | `/usr/bin/davinci-resolve` | Convenience symlink to wrapper | +### Hyprland Rules + +| Path | Purpose | +|------|---------| +| `~/.config/hypr/davinci-resolve.lua` | Opens Resolve's main window over the Omarchy bar; stops dialogs trapping the pointer | +| `~/.config/hypr/hyprland.lua` | One `require("hypr.davinci-resolve")` line appended, plus the `resolve-full-opacity` rule (§8) | + ### Desktop Entries | Path | Purpose | @@ -221,6 +300,22 @@ RESOLVE_NO_ALOOP=1 ./Omarchy_resolve_v2.sh This skips the `modprobe snd-aloop`, the `/etc/modules-load.d/` entry, and the PipeWire loopback bridge. The DeckLink → ALSA config patch still runs. +### Skip the Hyprland Window Rules + +If you would rather the installer left your Hyprland config alone entirely: + +```bash +RESOLVE_NO_HYPR_RULES=1 ./Omarchy_resolve_v2.sh +``` + +Neither `~/.config/hypr/davinci-resolve.lua` nor the `require` line is written. +The separate full-opacity rule (§8) is not covered by this switch — remove its +`resolve-full-opacity` block from `hyprland.lua` if you don't want it either. +The installer also skips the rules +automatically (with a warning showing the equivalent `windowrulev2` line) if +`~/.config/hypr/hyprland.lua` doesn't exist — i.e. on non-Omarchy-4.x setups +that still use `hyprland.conf`. + ### Hybrid GPU Laptops (Optimus) If you have an Intel iGPU + NVIDIA dGPU, edit the wrapper to force Resolve onto the NVIDIA GPU: @@ -350,6 +445,12 @@ sudo rm -rf /opt/resolve sudo rm -f /usr/local/bin/resolve-nvidia-open sudo rm -f /usr/bin/davinci-resolve +# Remove the Hyprland window rules (bar overlap + pointer trap), then reload +rm -f ~/.config/hypr/davinci-resolve.lua +sed -i '/require("hypr.davinci-resolve")/d' ~/.config/hypr/hyprland.lua +sed -i '/Open DaVinci Resolve.s main window over the Omarchy bar/d' ~/.config/hypr/hyprland.lua +hyprctl reload + # Remove desktop entries sudo rm -f /usr/share/applications/DaVinciResolve.desktop sudo rm -f /usr/share/applications/DaVinciControlPanelsSetup.desktop