diff --git a/Modules/Bar/Widgets/Tray.qml b/Modules/Bar/Widgets/Tray.qml index 6c051fb1..f52423d7 100644 --- a/Modules/Bar/Widgets/Tray.qml +++ b/Modules/Bar/Widgets/Tray.qml @@ -15,18 +15,27 @@ Rectangle { property ShellScreen screen - // Get shared tray menu window from MainScreen (via screen's parent MainScreen) + // Trigger re-evaluation when window is registered + property int trayMenuUpdateTrigger: 0 + + // Get shared tray menu window from PanelService (reactive to trigger changes) readonly property var trayMenuWindow: { - // Access via PanelService to get the MainScreen that contains the trayMenuWindow - if (!screen) - return null - // Get any panel from this screen to access its parent MainScreen - const drawerPanel = PanelService.getPanel("trayDrawerPanel", screen) - return drawerPanel?.trayMenuWindow || null + // Reference trigger to force re-evaluation + var _ = trayMenuUpdateTrigger + return PanelService.getTrayMenuWindow(screen) } readonly property var trayMenu: trayMenuWindow ? trayMenuWindow.trayMenuLoader : null + Connections { + target: PanelService + function onTrayMenuWindowRegistered(registeredScreen) { + if (registeredScreen === screen) { + root.trayMenuUpdateTrigger++ + } + } + } + // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" property string section: "" @@ -310,7 +319,9 @@ Rectangle { if (mouse.button === Qt.LeftButton) { // Close any open menu first - trayMenuWindow.close() + if (trayMenuWindow) { + trayMenuWindow.close() + } if (!modelData.onlyMenu) { modelData.activate() @@ -337,7 +348,7 @@ Rectangle { drawerPanel.close() } - if (modelData.hasMenu && modelData.menu && trayMenu.item) { + if (modelData.hasMenu && modelData.menu && trayMenuWindow && trayMenu && trayMenu.item) { trayMenuWindow.open() // Position menu based on bar position @@ -365,7 +376,9 @@ Rectangle { } } onEntered: { - trayMenuWindow.close() + if (trayMenuWindow) { + trayMenuWindow.close() + } TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection()) } onExited: TooltipService.hide() diff --git a/Modules/MainScreen/AllScreens.qml b/Modules/MainScreen/AllScreens.qml index 3211a332..bf586ef7 100644 --- a/Modules/MainScreen/AllScreens.qml +++ b/Modules/MainScreen/AllScreens.qml @@ -83,5 +83,20 @@ Variants { Logger.d("Shell", "BarExclusionZone created for", modelData?.name) } } + + // TrayMenuWindow - separate window for tray context menus + // This must be a top-level PanelWindow. + Loader { + active: parent.windowLoaded && parent.shouldBeActive + asynchronous: false + + sourceComponent: TrayMenuWindow { + screen: modelData + } + + onLoaded: { + Logger.d("Shell", "TrayMenuWindow created for", modelData?.name) + } + } } } diff --git a/Modules/MainScreen/MainScreen.qml b/Modules/MainScreen/MainScreen.qml index 56603773..cc37a7db 100644 --- a/Modules/MainScreen/MainScreen.qml +++ b/Modules/MainScreen/MainScreen.qml @@ -44,7 +44,6 @@ PanelWindow { readonly property alias trayDrawerPanel: trayDrawerPanel readonly property alias wallpaperPanel: wallpaperPanel readonly property alias wifiPanel: wifiPanel - readonly property alias trayMenuWindow: trayMenuWindow Component.onCompleted: { Logger.d("MainScreen", "Initialized for screen:", screen?.name, "- Dimensions:", screen?.width, "x", screen?.height, "- Position:", screen?.x, ",", screen?.y) @@ -286,7 +285,6 @@ PanelWindow { TrayDrawerPanel { id: trayDrawerPanel screen: root.screen - trayMenuWindow: root.trayMenuWindow z: 50 Component.onCompleted: { @@ -317,49 +315,6 @@ PanelWindow { } } - // ---------------------------------------------- - // Shared TrayMenu window for context menus (used by both Tray widget and TrayDrawerPanel) - PanelWindow { - id: trayMenuWindow - anchors.top: true - anchors.left: true - anchors.right: true - anchors.bottom: true - visible: false - color: Color.transparent - screen: root.screen - - // Expose the trayMenu Loader directly - readonly property alias trayMenuLoader: trayMenu - - function open() { - visible = true - } - - function close() { - visible = false - if (trayMenu.item) { - trayMenu.item.hideMenu() - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: trayMenuWindow.close() - } - - Loader { - id: trayMenu - source: "../Bar/Extras/TrayMenu.qml" - onLoaded: { - if (item) { - item.screen = root.screen - } - } - } - } - // ---------------------------------------------- // Bar background placeholder - just for background positioning (actual bar content is in BarContentWindow) Item { diff --git a/Modules/MainScreen/TrayMenuWindow.qml b/Modules/MainScreen/TrayMenuWindow.qml new file mode 100644 index 00000000..de839e45 --- /dev/null +++ b/Modules/MainScreen/TrayMenuWindow.qml @@ -0,0 +1,63 @@ +import QtQuick +import Quickshell +import Quickshell.Wayland +import qs.Commons +import qs.Services.UI +import qs.Modules.Bar.Extras + +// Separate window for TrayMenu context menus +// This is a top-level PanelWindow (sibling to MainScreen, not nested inside it) +PanelWindow { + id: root + + required property ShellScreen screen + + anchors.top: true + anchors.left: true + anchors.right: true + anchors.bottom: true + visible: false + color: Color.transparent + + // Use Top layer (same as MainScreen) for proper event handling + WlrLayershell.layer: WlrLayer.Top + WlrLayershell.keyboardFocus: WlrKeyboardFocus.None + WlrLayershell.namespace: "noctalia-traymenu-" + (screen?.name || "unknown") + WlrLayershell.exclusionMode: ExclusionMode.Ignore + + // Expose the trayMenu Loader directly + readonly property alias trayMenuLoader: trayMenu + + // Register with PanelService so panels can find this window + Component.onCompleted: { + objectName = "trayMenuWindow-" + (screen?.name || "unknown") + PanelService.registerTrayMenuWindow(screen, root) + } + + function open() { + visible = true + } + + function close() { + visible = false + if (trayMenu.item) { + trayMenu.item.hideMenu() + } + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + onClicked: root.close() + } + + Loader { + id: trayMenu + source: "../Bar/Extras/TrayMenu.qml" + onLoaded: { + if (item) { + item.screen = root.screen + } + } + } +} diff --git a/Modules/Panels/Tray/TrayDrawerPanel.qml b/Modules/Panels/Tray/TrayDrawerPanel.qml index 38f0323a..ae1376a9 100644 --- a/Modules/Panels/Tray/TrayDrawerPanel.qml +++ b/Modules/Panels/Tray/TrayDrawerPanel.qml @@ -12,9 +12,6 @@ import qs.Modules.MainScreen SmartPanel { id: root - // Shared tray menu window (set by MainScreen) - property var trayMenuWindow: null - // Widget info for menu functionality property string widgetSection: "" property int widgetIndex: -1 @@ -99,9 +96,27 @@ SmartPanel { } } - // Get the trayMenu Loader from the shared window + // Trigger re-evaluation when window is registered + property int trayMenuUpdateTrigger: 0 + + // Get the trayMenu window and loader from PanelService (reactive to trigger changes) + readonly property var trayMenuWindow: { + // Reference trigger to force re-evaluation + var _ = trayMenuUpdateTrigger + return PanelService.getTrayMenuWindow(screen) + } + readonly property var trayMenu: trayMenuWindow ? trayMenuWindow.trayMenuLoader : null + Connections { + target: PanelService + function onTrayMenuWindowRegistered(registeredScreen) { + if (registeredScreen === screen) { + root.trayMenuUpdateTrigger++ + } + } + } + panelContent: Item { id: content @@ -176,7 +191,7 @@ SmartPanel { return } - if (modelData.hasMenu && modelData.menu && trayMenu.item) { + if (modelData.hasMenu && modelData.menu && trayMenuWindow && trayMenu && trayMenu.item) { trayMenuWindow.open() // Position menu at the tray icon @@ -211,7 +226,9 @@ SmartPanel { } onEntered: { - trayMenuWindow.close() + if (trayMenuWindow) { + trayMenuWindow.close() + } TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection()) } onExited: TooltipService.hide() diff --git a/Services/UI/PanelService.qml b/Services/UI/PanelService.qml index 79682646..51ae69c0 100644 --- a/Services/UI/PanelService.qml +++ b/Services/UI/PanelService.qml @@ -16,12 +16,33 @@ Singleton { signal willOpen signal didClose + // Tray menu windows (one per screen) + property var trayMenuWindows: ({}) + signal trayMenuWindowRegistered(var screen) + // Register this panel (called after panel is loaded) function registerPanel(panel) { registeredPanels[panel.objectName] = panel Logger.d("PanelService", "Registered panel:", panel.objectName) } + // Register tray menu window for a screen + function registerTrayMenuWindow(screen, window) { + if (!screen || !window) + return + var key = screen.name + trayMenuWindows[key] = window + Logger.d("PanelService", "Registered tray menu window for screen:", key) + trayMenuWindowRegistered(screen) + } + + // Get tray menu window for a screen + function getTrayMenuWindow(screen) { + if (!screen) + return null + return trayMenuWindows[screen.name] || null + } + // Returns a panel (loads it on-demand if not yet loaded) function getPanel(name, screen) { if (!screen) {