From 3136780cd4340e6b728e60878c5bb5f27944ce41 Mon Sep 17 00:00:00 2001 From: rope Date: Tue, 28 Jul 2026 14:37:28 +0100 Subject: [PATCH] quickshell: fix dropdown seed gate, drop the tray menu wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert the wait-for-items delay: never block opening on the menu. The actual bug was in the rotation. toggleDropdown gated seeding on chrome.height < 0.5, correct when height was the growth axis, but the growth axis is width now and chrome.height is tH — never 0 (200 by default, 32 after shrinkToButton). So seedFromButton has not run since the bar went vertical: the chrome never seeded at the clicked widget and tH animated from whatever the previous dropdown left behind. Gate now tests chrome.width. seedFromButton also holds snap for the length of the grow instead of releasing it immediately, so the panel expands along one axis at its content's real height, and content that lands mid-grow is followed instantly rather than starting a second animation. Co-Authored-By: Claude Opus 5 --- settings/quickshell.nix | 71 +++++++++++++---------------------------- 1 file changed, 23 insertions(+), 48 deletions(-) diff --git a/settings/quickshell.nix b/settings/quickshell.nix index 1bf6562..0023a49 100644 --- a/settings/quickshell.nix +++ b/settings/quickshell.nix @@ -1295,7 +1295,10 @@ in // Opening from fully closed: seed the chrome as a // small stub on the widget so the panel grows out of // it (reviving mid-close morphs back instead). - if (!activeDropdown && chrome.height < 0.5) { + // width, not height: the growth axis is horizontal now. + // chrome.height is tH, which is never 0, so testing it + // meant this never fired and the panel never seeded. + if (!activeDropdown && chrome.width < 0.5) { chrome.seedFromButton(dd); } // Retarget the chrome before closing the previous @@ -2049,7 +2052,19 @@ in snap = true; tY = stubY(dd); tH = stubH; - snap = false; + // Stay snapped for the length of the grow, rather than + // unsnapping immediately. The panel then expands along + // ONE axis — width — at whatever height its content is + // right now, and content that lands mid-grow (async + // DBus tray menus) is followed instantly instead of + // kicking off a second, visibly separate animation. + _unsnap.restart(); + } + + Timer { + id: _unsnap + interval: Theme.animMorph + onTriggered: chrome.snap = false } function shrinkToButton(dd) { tY = stubY(dd); @@ -2103,62 +2118,22 @@ in fullHeight: menuItems.height + 2 * Theme.panelGap onVisibleChanged: { - if (!visible) { - menuOpener.menu = null; - pendingItem = null; - _menuWait.stop(); - } + if (!visible) menuOpener.menu = null; } QsMenuOpener { id: menuOpener } - // The DBus menu populates asynchronously and Steam's is - // slow. Opening on click sized the panel from an EMPTY - // body: menuItems.width is fixed, so the width was already - // final while fullHeight was just padding — the panel shot - // out sideways, then lurched taller when the items landed. - // Two motions instead of one. Load first, open once there - // is something to show. - property var pendingItem: null - readonly property bool menuReady: - menuOpener.children && menuOpener.children.values.length > 0 - + // Opens immediately — never wait on the menu. Late content + // is handled by the chrome staying snapped for the length + // of the grow (see seedFromButton), so the height follows + // instantly instead of starting a second animation. function openFor(item, y) { dropdownY = y; trayItem = item; menuOpener.menu = item.menu; - if (menuReady) { - pendingItem = null; - bar.toggleDropdown(contextMenu, null); - } else { - pendingItem = item; - _menuWait.restart(); - } - } - - function openPending() { - if (!pendingItem) return; - pendingItem = null; - _menuWait.stop(); - if (bar.activeDropdown !== contextMenu) - bar.toggleDropdown(contextMenu, null); - } - - // Never strand a click if the menu never populates. - Timer { - id: _menuWait - interval: 500 - onTriggered: contextMenu.openPending() - } - - Connections { - target: menuOpener.children - function onValuesChanged() { - if (contextMenu.pendingItem && contextMenu.menuReady) - contextMenu.openPending(); - } + bar.toggleDropdown(contextMenu, null); } Card {