diff --git a/frame/qml/PanelMenu.qml b/frame/qml/PanelMenu.qml index a2104214c..44f2466ec 100644 --- a/frame/qml/PanelMenu.qml +++ b/frame/qml/PanelMenu.qml @@ -17,6 +17,7 @@ Item { property bool readyBinding: false // WM_NAME, used for kwin. property string windowTitle: "dde-shell/panelmenu" + property bool autoCloseOnDeactivate: true width: menu.childrenRect.width height: menu.childrenRect.height @@ -83,8 +84,7 @@ Item { { if (!menuWindow) return - // TODO why activeChanged is not emit. - if (menuWindow && !menuWindow.active) { + if (autoCloseOnDeactivate && menuWindow && !menuWindow.active) { control.close() } } diff --git a/panels/dock/MenuHelper.qml b/panels/dock/MenuHelper.qml index 46775f090..842eaa70a 100644 --- a/panels/dock/MenuHelper.qml +++ b/panels/dock/MenuHelper.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2023-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -8,12 +8,14 @@ import Qt.labs.platform Item { property Menu activeMenu: null + property bool hasTrayMenuOpen: false signal menuClosed() Connections { target: activeMenu function onAboutToHide() { activeMenu = null + hasTrayMenuOpen = false menuClosed() } } diff --git a/panels/dock/taskmanager/package/AppItem.qml b/panels/dock/taskmanager/package/AppItem.qml index 40eed5b4e..a74408922 100644 --- a/panels/dock/taskmanager/package/AppItem.qml +++ b/panels/dock/taskmanager/package/AppItem.qml @@ -430,6 +430,10 @@ Item { function requestAppItemMenu() { contextMenuLoader.trashEmpty = TaskManager.isTrashEmpty() contextMenuLoader.active = true + let notifyPanel = DS.applet("org.deepin.ds.notificationcenter") + if (notifyPanel && notifyPanel.visible) { + notifyPanel.close() + } MenuHelper.openMenu(contextMenuLoader.item) } diff --git a/panels/dock/tray/SurfacePopup.qml b/panels/dock/tray/SurfacePopup.qml index 122ae045e..ab16e4546 100644 --- a/panels/dock/tray/SurfacePopup.qml +++ b/panels/dock/tray/SurfacePopup.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -16,6 +16,52 @@ Item { } property int toolTipVOffset: 0 signal popupCreated(var surfaceId) + property var pendingTrayMenu: null + Timer { + id: trayMenuOpenTimer + interval: 150 + repeat: false + onTriggered: { + if (pendingTrayMenu) { + pendingTrayMenu.open() + pendingTrayMenu = null + } + } + } + Timer { + id: restoreAutoCloseTimer + interval: 200 + repeat: false + onTriggered: { + if (pendingTrayMenu) { + pendingTrayMenu.autoCloseOnDeactivate = true + } + } + } + Connections { + target: menu + function onMenuVisibleChanged() { + if (!menu.menuVisible) { + MenuHelper.hasTrayMenuOpen = false + let notifyPanel = DS.applet("org.deepin.ds.notificationcenter") + if (notifyPanel) { + notifyPanel.hasTrayMenuOpen = false + } + } + } + } + Connections { + target: menu.menuWindow + function onActiveChanged() { + if (menu.menuWindow && !menu.menuWindow.active && !menu.menuVisible) { + MenuHelper.hasTrayMenuOpen = false + let notifyPanel = DS.applet("org.deepin.ds.notificationcenter") + if (notifyPanel) { + notifyPanel.hasTrayMenuOpen = false + } + } + } + } PanelToolTipWindow { id: toolTipWindow @@ -144,7 +190,18 @@ Item { menu.menuY = Qt.binding(function () { return menu.shellSurface.y }) - menu.open() + let notifyPanel = DS.applet("org.deepin.ds.notificationcenter") + if (notifyPanel && notifyPanel.visible) { + notifyPanel.close() + } + menu.autoCloseOnDeactivate = false + MenuHelper.hasTrayMenuOpen = true + if (notifyPanel) { + notifyPanel.hasTrayMenuOpen = true + } + root.pendingTrayMenu = menu + trayMenuOpenTimer.restart() + restoreAutoCloseTimer.restart() } } } diff --git a/panels/dock/tray/TrayItemSurfacePopup.qml b/panels/dock/tray/TrayItemSurfacePopup.qml index d2406a169..f49bf61b0 100644 --- a/panels/dock/tray/TrayItemSurfacePopup.qml +++ b/panels/dock/tray/TrayItemSurfacePopup.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -20,6 +20,52 @@ Item { return false } readonly property bool isOpened: popup.popupVisible + property var pendingTrayMenu: null + Timer { + id: trayMenuOpenTimer + interval: 150 + repeat: false + onTriggered: { + if (pendingTrayMenu) { + pendingTrayMenu.open() + pendingTrayMenu = null + } + } + } + Timer { + id: restoreAutoCloseTimer + interval: 200 + repeat: false + onTriggered: { + if (pendingTrayMenu) { + pendingTrayMenu.autoCloseOnDeactivate = true + } + } + } + Connections { + target: popupMenu + function onMenuVisibleChanged() { + if (!popupMenu.menuVisible) { + MenuHelper.hasTrayMenuOpen = false + let notifyPanel = DS.applet("org.deepin.ds.notificationcenter") + if (notifyPanel) { + notifyPanel.hasTrayMenuOpen = false + } + } + } + } + Connections { + target: popupMenu.menuWindow + function onActiveChanged() { + if (popupMenu.menuWindow && !popupMenu.menuWindow.active && !popupMenu.menuVisible) { + MenuHelper.hasTrayMenuOpen = false + let notifyPanel = DS.applet("org.deepin.ds.notificationcenter") + if (notifyPanel) { + notifyPanel.hasTrayMenuOpen = false + } + } + } + } function closeTooltip() { if (toolTip.toolTipVisible) { toolTip.close() @@ -161,7 +207,18 @@ Item { var point = Qt.point(popupMenu.shellSurface.x, popupMenu.shellSurface.y) return Qt.rect(point.x, point.y, popupMenu.width, popupMenu.height) }) - popupMenu.open() + let notifyPanel = DS.applet("org.deepin.ds.notificationcenter") + if (notifyPanel && notifyPanel.visible) { + notifyPanel.close() + } + popupMenu.autoCloseOnDeactivate = false + MenuHelper.hasTrayMenuOpen = true + if (notifyPanel) { + notifyPanel.hasTrayMenuOpen = true + } + root.pendingTrayMenu = popupMenu + trayMenuOpenTimer.restart() + restoreAutoCloseTimer.restart() } } } diff --git a/panels/notification/center/notificationcenterpanel.cpp b/panels/notification/center/notificationcenterpanel.cpp index 13f9729af..ff6ffa188 100644 --- a/panels/notification/center/notificationcenterpanel.cpp +++ b/panels/notification/center/notificationcenterpanel.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -9,24 +9,26 @@ #include "notificationcenterproxy.h" #include "notifyaccessor.h" -#include -#include #include -#include #include +#include +#include +#include -#include #include +#include #include #include -#include +#include DS_USE_NAMESPACE -namespace notification { +namespace notification +{ Q_DECLARE_LOGGING_CATEGORY(notifyLog) } -namespace notification { +namespace notification +{ static const QString DDENotifyDBusServer = "org.deepin.dde.Notification1"; static const QString DDENotifyDBusInterface = "org.deepin.dde.Notification1"; @@ -99,6 +101,10 @@ bool NotificationCenterPanel::visible() const void NotificationCenterPanel::setVisible(bool newVisible) { + if (m_hasTrayMenuOpen) { + qDebug(notifyLog) << "Blocked: tray menu is open"; + return; + } if (m_visible == newVisible) return; m_visible = newVisible; @@ -128,6 +134,19 @@ void NotificationCenterPanel::setBubblePanelEnabled(bool enabled) QMetaObject::invokeMethod(applet, "setEnabled", Qt::DirectConnection, Q_ARG(bool, enabled)); } +bool NotificationCenterPanel::hasTrayMenuOpen() const +{ + return m_hasTrayMenuOpen; +} + +void NotificationCenterPanel::setHasTrayMenuOpen(bool hasOpen) +{ + if (m_hasTrayMenuOpen == hasOpen) + return; + m_hasTrayMenuOpen = hasOpen; + emit hasTrayMenuOpenChanged(); +} + D_APPLET_CLASS(NotificationCenterPanel) } diff --git a/panels/notification/center/notificationcenterpanel.h b/panels/notification/center/notificationcenterpanel.h index 2cd546f7c..8bc76c9ae 100644 --- a/panels/notification/center/notificationcenterpanel.h +++ b/panels/notification/center/notificationcenterpanel.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,13 +6,15 @@ #include "panel.h" -namespace notification { +namespace notification +{ class NotificationCenterProxy; class NotificationCenterPanel : public DS_NAMESPACE::DPanel { Q_OBJECT Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged FINAL) + Q_PROPERTY(bool hasTrayMenuOpen READ hasTrayMenuOpen WRITE setHasTrayMenuOpen NOTIFY hasTrayMenuOpenChanged FINAL) public: explicit NotificationCenterPanel(QObject *parent = nullptr); ~NotificationCenterPanel(); @@ -24,14 +26,19 @@ class NotificationCenterPanel : public DS_NAMESPACE::DPanel void setVisible(bool newVisible); Q_INVOKABLE void close(); + bool hasTrayMenuOpen() const; + void setHasTrayMenuOpen(bool hasOpen); + Q_SIGNALS: void visibleChanged(); + void hasTrayMenuOpenChanged(); private slots: void setBubblePanelEnabled(bool enabled); private: bool m_visible = false; + bool m_hasTrayMenuOpen = false; NotificationCenterProxy *m_proxy = nullptr; }; } diff --git a/panels/notification/center/package/main.qml b/panels/notification/center/package/main.qml index 9843620df..b79e8eb65 100644 --- a/panels/notification/center/package/main.qml +++ b/panels/notification/center/package/main.qml @@ -80,7 +80,7 @@ Window { } // visible: true - visible: Panel.visible + visible: Panel.visible && !Panel.hasTrayMenuOpen flags: Qt.Tool property int contentPadding: 20