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 {