aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/island
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-24 09:44:39 +0200
committerDanilo M. <danix@danix.xyz>2026-10-24 09:44:39 +0200
commitdb144ea05a98051662b4d77a2a0dfd950d670295 (patch)
treea7a38704c421b9eb983d48f32345c7c923771b07 /desktop/island
parent0fa4736470a39b6abbb0e70d3eb5b7636fb61549 (diff)
downloadquickshell-db144ea05a98051662b4d77a2a0dfd950d670295.tar.gz
quickshell-db144ea05a98051662b4d77a2a0dfd950d670295.zip
island: release the tray-menu hold when the menu closes
A tray menu un-hovers the pills, so the island holds itself shown while one is open. display() reports no close, so the hold ended only when the pointer came back to the island. Quitting an app from its menu left the pointer on the vanished menu, below the pills, and the island stayed open until the next hover. Menus now open through a QsMenuAnchor. Its closed signal fires on any dismissal, an entry picked, Escape or a click elsewhere, and clears the hold and restarts the hide timer. Checked by eye: menu placement unchanged, Quit and a dismissal both retract the island, hovering back keeps it shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/island')
-rw-r--r--desktop/island/Island.qml11
-rw-r--r--desktop/island/README.md4
-rw-r--r--desktop/island/StatusPill.qml17
3 files changed, 24 insertions, 8 deletions
diff --git a/desktop/island/Island.qml b/desktop/island/Island.qml
index 12f49ea..ee03ca1 100644
--- a/desktop/island/Island.qml
+++ b/desktop/island/Island.qml
@@ -52,10 +52,9 @@ PanelWindow {
// A tray menu is a separate popup: moving onto it un-hovers the pills,
// and the hide timer would then hide the island under the open menu. The
- // menu cannot report its own close through display(), so the hold ends
- // the next time the pointer comes back to the island.
- // ponytail: if the menu is dismissed elsewhere, the island may stay shown
- // until the next hover.
+ // hold ends when the menu closes, or the next time the pointer comes back.
+ // It used to wait for the pointer alone, which left the island stuck open
+ // after a menu's Quit, since the pointer was on the menu, not the pills.
property bool menuHeld: false
onHoveredChanged: {
@@ -319,6 +318,10 @@ PanelWindow {
window: win
panel: win.panel
onMenuShown: win.menuHeld = true
+ onMenuClosed: {
+ win.menuHeld = false;
+ if (!win.hovered && win.panel === "") hideTimer.restart();
+ }
onOpenSound: win.panel = win.panel === "sound" ? "" : "sound"
onOpenHeadphones: win.panel = win.panel === "headphones" ? "" : "headphones"
onClosePanel: win.panel = ""
diff --git a/desktop/island/README.md b/desktop/island/README.md
index 9353f7e..01751c1 100644
--- a/desktop/island/README.md
+++ b/desktop/island/README.md
@@ -67,8 +67,8 @@ page now (`desktop/modules/perf/`).
opens the sound panel.
- **Tray** shows `SystemTray` items. Left click activates, right click opens
the item's menu. The island is the session's StatusNotifier host. A tray
- menu is a separate popup, so the island holds itself shown after `display()`
- until the pointer returns.
+ menu is a separate popup, opened through a `QsMenuAnchor`, so the island
+ holds itself shown until the anchor reports the menu closed.
- **Layout flag** shows the current keyboard layout, driven by Hyprland's
`activelayout` event. Scroll switches layout with
`hyprctl switchxkblayout current next|prev`.
diff --git a/desktop/island/StatusPill.qml b/desktop/island/StatusPill.qml
index 915807b..99f1512 100644
--- a/desktop/island/StatusPill.qml
+++ b/desktop/island/StatusPill.qml
@@ -38,8 +38,17 @@ Capsule {
signal openHeadphones()
signal closePanel()
signal openDrawer()
- // Emitted just before a tray menu opens; the menu cannot report its close.
+ // A tray menu opening and closing. display() reports no close, so menus
+ // open through a QsMenuAnchor, whose closed fires on any dismissal: an
+ // entry picked (Quit included), Escape or a click elsewhere.
signal menuShown()
+ signal menuClosed()
+
+ QsMenuAnchor {
+ id: menuAnchor
+ anchor.window: pill.window
+ onClosed: pill.menuClosed()
+ }
expanded: panel === "sound" || panel === "headphones"
restWidth: restRow.implicitWidth + 24
@@ -100,8 +109,12 @@ Capsule {
if (!wantsMenu) { item.activate(); return; }
if (!item.hasMenu) return;
const p = trayIcon.mapToItem(null, 0, trayIcon.height + 6);
+ if (menuAnchor.visible) menuAnchor.close();
+ menuAnchor.menu = item.menu;
+ menuAnchor.anchor.rect.x = p.x;
+ menuAnchor.anchor.rect.y = p.y;
pill.menuShown();
- item.display(pill.window, p.x, p.y);
+ menuAnchor.open();
}
}
}