From 9b7ca88e1137cb9468d4ae34add6b6b14d2a6832 Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 7 Aug 2025 17:01:52 -0400 Subject: [PATCH] native tray menu --- Modules/TopBar/SystemTrayBar.qml | 27 +++- Modules/TopBar/SystemTrayContextMenu.qml | 181 ----------------------- Modules/TopBar/TopBar.qml | 11 +- shell.qml | 17 +-- 4 files changed, 22 insertions(+), 214 deletions(-) delete mode 100644 Modules/TopBar/SystemTrayContextMenu.qml diff --git a/Modules/TopBar/SystemTrayBar.qml b/Modules/TopBar/SystemTrayBar.qml index fc5da08e..a744e657 100644 --- a/Modules/TopBar/SystemTrayBar.qml +++ b/Modules/TopBar/SystemTrayBar.qml @@ -1,13 +1,15 @@ import QtQuick +import Quickshell import Quickshell.Services.SystemTray import qs.Common Rectangle { id: root + + property var parentWindow: null readonly property int calculatedWidth: SystemTray.items.values.length > 0 ? SystemTray.items.values.length * 24 + (SystemTray.items.values.length - 1) * Theme.spacingXS + Theme.spacingS * 2 : 0 - signal menuRequested(var menu, var item, real x, real y) width: calculatedWidth height: 30 @@ -84,16 +86,21 @@ Rectangle { cursorShape: Qt.PointingHandCursor onClicked: (mouse) => { if (!trayItem) - return ; + return if (mouse.button === Qt.LeftButton) { - if (!trayItem.onlyMenu) - trayItem.activate(); - + trayItem.activate() } else if (mouse.button === Qt.RightButton) { - if (trayItem && trayItem.hasMenu) - root.menuRequested(null, trayItem, mouse.x, mouse.y); - + if (trayItem.hasMenu) { + var globalPos = mapToGlobal(0, 0) + var currentScreen = Screen + var screenX = currentScreen.x || 0 + var relativeX = globalPos.x - screenX + menuAnchor.menu = trayItem.menu + menuAnchor.anchor.window = parentWindow + menuAnchor.anchor.rect = Qt.rect(relativeX, Theme.barHeight + Theme.spacingS, parent.width, 1) + menuAnchor.open() + } } } } @@ -104,4 +111,8 @@ Rectangle { } + QsMenuAnchor { + id: menuAnchor + } + } diff --git a/Modules/TopBar/SystemTrayContextMenu.qml b/Modules/TopBar/SystemTrayContextMenu.qml deleted file mode 100644 index c9a35ba7..00000000 --- a/Modules/TopBar/SystemTrayContextMenu.qml +++ /dev/null @@ -1,181 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland -import Quickshell.Widgets -import qs.Common -import qs.Widgets - -PanelWindow { - id: root - - property bool showContextMenu: false - property real contextMenuX: 0 - property real contextMenuY: 0 - property var currentTrayMenu: null - property var currentTrayItem: null - - visible: showContextMenu - WlrLayershell.layer: WlrLayershell.Overlay - WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - color: "transparent" - - anchors { - top: true - left: true - right: true - bottom: true - } - - Rectangle { - id: menuContainer - - x: contextMenuX - y: contextMenuY - width: Math.max(180, Math.min(300, menuList.maxTextWidth + Theme.spacingL * 2)) - height: Math.max(60, menuList.contentHeight + Theme.spacingS * 2) - color: Theme.popupBackground() - radius: Theme.cornerRadiusLarge - border.color: Theme.outlineMedium - border.width: 1 - opacity: showContextMenu ? 1 : 0 - scale: showContextMenu ? 1 : 0.85 - - Rectangle { - anchors.fill: parent - anchors.topMargin: 4 - anchors.leftMargin: 2 - anchors.rightMargin: -2 - anchors.bottomMargin: -4 - radius: parent.radius - color: Qt.rgba(0, 0, 0, 0.15) - z: parent.z - 1 - } - - Item { - anchors.fill: parent - anchors.margins: Theme.spacingS - - QsMenuOpener { - id: menuOpener - - menu: currentTrayItem && currentTrayItem.hasMenu ? currentTrayItem.menu : null - } - - DankListView { - id: menuList - - property real maxTextWidth: { - let maxWidth = 0; - if (model && model.values) { - for (let i = 0; i < model.values.length; i++) { - const item = model.values[i]; - if (item && item.text) { - const textWidth = textMetrics.advanceWidth * item.text.length * 0.6; - maxWidth = Math.max(maxWidth, textWidth); - } - } - } - return Math.min(maxWidth, 280); // Cap at reasonable width - } - - anchors.fill: parent - spacing: 1 - model: menuOpener.children - - TextMetrics { - id: textMetrics - - font.pixelSize: Theme.fontSizeSmall - text: "M" - } - - delegate: Rectangle { - width: ListView.view.width - height: modelData.isSeparator ? 5 : 28 - radius: modelData.isSeparator ? 0 : Theme.cornerRadiusSmall - color: modelData.isSeparator ? "transparent" : (menuItemArea.containsMouse ? Theme.primaryHover : "transparent") - - Rectangle { - visible: modelData.isSeparator - anchors.centerIn: parent - width: parent.width - Theme.spacingS * 2 - height: 1 - color: Theme.surfaceVariantAlpha - } - - Row { - visible: !modelData.isSeparator - anchors.left: parent.left - anchors.leftMargin: Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingXS - - StyledText { - text: modelData.text || "" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - font.weight: Font.Normal - elide: Text.ElideRight - maximumLineCount: 1 - } - - } - - MouseArea { - id: menuItemArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: modelData.isSeparator ? Qt.ArrowCursor : Qt.PointingHandCursor - enabled: !modelData.isSeparator - onClicked: { - if (modelData.triggered) - modelData.triggered(); - - showContextMenu = false; - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - - } - - } - - } - - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - - } - - Behavior on scale { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - - } - - } - - MouseArea { - anchors.fill: parent - z: -1 - onClicked: { - showContextMenu = false; - } - } - -} diff --git a/Modules/TopBar/TopBar.qml b/Modules/TopBar/TopBar.qml index 0d0095af..e1dbf90a 100644 --- a/Modules/TopBar/TopBar.qml +++ b/Modules/TopBar/TopBar.qml @@ -542,16 +542,7 @@ PanelWindow { id: systemTrayComponent SystemTrayBar { - onMenuRequested: (menu, item, x, y) => { - systemTrayContextMenu.currentTrayMenu = menu; - systemTrayContextMenu.currentTrayItem = item; - systemTrayContextMenu.contextMenuX = rightSection.x + rightSection.width - 400 - Theme.spacingL; - systemTrayContextMenu.contextMenuY = Theme.barHeight - Theme.spacingXS; - systemTrayContextMenu.showContextMenu = true; - if (menu) { - menu.menuVisible = true; - } - } + parentWindow: root } } diff --git a/shell.qml b/shell.qml index 3818123a..dff12ce6 100644 --- a/shell.qml +++ b/shell.qml @@ -1,3 +1,4 @@ +//@ pragma UseQApplication import QtQuick import Quickshell @@ -21,8 +22,7 @@ import qs.Services ShellRoot { id: root - WallpaperBackground { - } + WallpaperBackground {} Lock { id: lock @@ -36,7 +36,6 @@ ShellRoot { delegate: TopBar { modelData: item } - } Variants { @@ -47,17 +46,12 @@ ShellRoot { contextMenu: dockContextMenu windowsMenu: dockWindowsMenu } - } CentcomPopout { id: centcomPopout } - SystemTrayContextMenu { - id: systemTrayContextMenu - } - DockContextMenu { id: dockContextMenu } @@ -76,7 +70,6 @@ ShellRoot { delegate: NotificationPopupManager { modelData: item } - } ControlCenterPopout { @@ -141,7 +134,6 @@ ShellRoot { ProcessListModal { id: processListModal } - } IpcHandler { @@ -177,7 +169,6 @@ ShellRoot { delegate: Toast { modelData: item } - } Variants { @@ -186,7 +177,6 @@ ShellRoot { delegate: VolumePopup { modelData: item } - } Variants { @@ -195,7 +185,6 @@ ShellRoot { delegate: MicMutePopup { modelData: item } - } Variants { @@ -204,7 +193,5 @@ ShellRoot { delegate: BrightnessPopup { modelData: item } - } - }