quattro
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5b2c02dee3 |
Fix unclickable tray submenus by drilling down inside the popup (#6703)
* Fix unclickable tray submenus by drilling down inside the popup Clicking a tray menu entry that has children was a silent no-op: the row called QsMenuEntry.display(), which renders a *platform* menu, and Quickshell refuses that unless the shell root sets `//@ pragma UseQApplication` -- shell.qml does not. The log shows "Cannot display PlatformMenuEntry as quickshell was not started in QApplication mode" and nothing opens. Apps whose whole menu is submenus, like radiotray-ng's station list, were unusable. Adding the pragma would be the wrong fix: it switches the entire shell from QGuiApplication to QApplication, dragging QtWidgets into the process and changing application-class behavior for the sake of one popup -- which would then render as an unstyled platform menu beside omarchy's own popup styling anyway. Instead, submenus drill down inside the existing popup. A child QsMenuEntry inherits QsMenuHandle, so it can feed a nested QsMenuOpener and render through the same row delegate. Each level keeps its own live opener on a stack -- a child entry is owned by its parent opener's model, so collapsing to a single reassigned opener would destroy the very entry being displayed. A back header row walks out one level; at the root the menu renders exactly as before, and items without a DBusMenu still use the platform fallback. * Destroy submenu openers deepest-first and reset before switching items resetTrayMenu() destroyed openers front-to-back and only cleared submenuStack afterward. A deeper opener's menu entry is owned by its parent's children model, so destroying the parent first could invalidate an entry a still-live child opener referenced. Clear the stack before tearing anything down, then destroy deepest-first so a child is always gone before the parent whose model owns its entry. openTrayMenu() reassigned activeTrayItem before calling resetTrayMenu(). trayMenuOpener.menu binds to activeTrayItem.menu, so that reassignment immediately swaps what the root opener's children expose -- invalidating entries any live submenu opener still referenced, before resetTrayMenu() got a chance to tear them down. Reset first, then switch items. Thanks @Copilot for catching both. * Defer submenu reset until the popup's fade-out actually finishes onTrayMenuOpenChanged reset the submenu stack the instant trayMenuOpen went false, but the popup stays visible for the whole 140ms opacity fade (PopupCard's own visible: open || card.opacity > 0) -- dismissing from a submenu flashed the root menu mid-fade, and could resize or reposition the fading popup if the two have different geometry. Moved the reset to trayMenuPopup's own onVisibleChanged, which only fires once the fade has genuinely completed. Switching to a different tray item is unaffected: openTrayMenu() already resets explicitly before assigning the new item, independent of whether the popup ever dips to invisible (rapid reopen mid-fade never does). Thanks @Copilot for catching this. * Ignore tray menu clicks for a beat after changing submenu level Changing level swaps the Repeater's model, which rebuilds the row delegates synchronously -- a fresh row lands under a cursor that hasn't moved. Submenu clicks used to be silent no-ops, which trained users to click them twice, so that second click now fires whatever entry took the spot. On radiotray-ng that means an accidental station switch. Gate row and back-header clicks for 250ms after each level change. A deliberate follow-up click is slower than that; a double-click is not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Pin the submenu back header above the scrolling menu rows The back header lived inside the Flickable's Column, so in a submenu taller than the 420px cap -- exactly the long station list this drill-down exists for -- scrolling down pushed the only way back off screen, with no Escape or right-click alternative. Move it into a pinned Column above the Flickable and account for its height in the popup's contentHeight. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Reset the tray menu scroll offset when the drill-down is torn down Flickable keeps its contentY across a model swap whenever the new content is still tall enough to hold it. A menu dismissed while scrolled therefore reopened part-way down with its first entries off screen: reproducible on any tray app whose root menu outgrows the 420px cap, and now reachable on every app once a long submenu has been scrolled. Zero the offset in resetTrayMenu(), which runs both on teardown and before switching items. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Toni Nowak <t.nowak@ai-flow.no> Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c3bd4a86ae |
Fix unbound XKBLAYOUT under set -u in the keyboard-layout migration (#6539)
* Fix unbound XKBLAYOUT under set -u in the keyboard-layout migration /etc/vconsole.conf only guarantees KEYMAP -- XKBLAYOUT is written by some installers but not required, and vconsole.conf on a stock install may not define it at all. omarchy-migrate runs every migration with set -euo pipefail, so referencing the unset variable directly aborted the migration run instead of just skipping a layout this migration doesn't care about. Read it with a default-empty expansion first, then apply the existing comma-strip separately -- keeps both failure modes (unset, and set with a trailing keymap variant) handled explicitly instead of folding them into one expansion that only covers one of the two. * Survive a missing vconsole.conf in the keyboard-layout migration Defaulting XKBLAYOUT fixed the unset variable but not the other way this line takes the migration chain down. `.` fails when /etc/vconsole.conf is not there at all, `&&` short-circuits, and the non-zero status leaves the command substitution and kills the assignment under omarchy-migrate's `bash -euo pipefail` -- the same abort, one branch over. The file is optional enough that both other readers of it, omarchy_hooks.conf and 1781485962.sh, guard with `-f` first. Run the echo unconditionally so the substitution reports its status instead of the source's. Read both paths from the environment, the way the zram migration already does, and cover the layout cases plus both crashes with a test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Read the keyboard layout from vconsole.conf alone Two ways the layout could come from somewhere other than the file, both found reviewing the fix before it: Sourcing does not clear an exported XKBLAYOUT, so on a machine that exports one, a vconsole.conf that sets no layout -- or none at all -- left the caller's environment deciding what the initramfs bundles. Unset it in the subshell so only the file can answer. Skipping the source when the file is missing, rather than letting the substitution swallow the failure, also stops depending on errexit being discarded inside command substitution. inherit_errexit takes that back and the chain aborts again; nothing in Omarchy sets it today, but the other two readers of vconsole.conf already check `-f` first and this now matches. Test the layout list past its one Cyrillic entry, both orders of a comma-separated pair, an exported XKBLAYOUT, and inherit_errexit. Each of those catches a mutation that survived before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Drop the test scaffolding from the keyboard-layout migration A migration runs once and then gets deleted, so a suite entry for this one is upkeep with a short shelf life. The path overrides existed only so that test could aim the migration at fixtures; with the test gone they are indirection nothing exercises, so both go back to literal paths. The fixes stay: check the file before sourcing it, unset XKBLAYOUT so an exported one cannot answer for a file that sets none, and strip the keymap variant before matching. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Toni Nowak <t.nowak@ai-flow.no> Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |