From de65d7553c60d70f7bbca785774985e91bd6bb26 Mon Sep 17 00:00:00 2001 From: multica-agent Date: Mon, 14 Sep 2026 19:02:55 +0800 Subject: [PATCH] fix: prevent context menu/popup from toggling closed on rapid right-click BUG-353435: Rapid right-clicking a dock tray plugin icon could toggle the context menu closed (or a panel popup closed/reopened) instead of keeping it open. Root cause: PanelMenu.open() and PanelPopup.open() implemented toggle semantics -- when already visible, calling open() would close() the window. There is an async window between open() setting menu.visible (true, via readyBinding) and finalizeOpen() calling grabMouse(). During that window a second right-click still reaches PluginItem, creates a new Wayland popup surface, and triggers another open() which hits the toggle-close branch, dismissing the menu. Fix: Make open() pure-open semantics -- when already visible, return (no-op) instead of closing. The QML-level toggle was redundant: - Left-click toggle is already handled in the C++ layer (dde-tray-loader itemPopupApplet: existed && !embed -> return nullptr). - All QML callers invoke open() from onPopupCreated handlers (Wayland popup surface creation), which is always open-intent, never toggle. - Panel.requestClosePopup() only closes popupWindow, not menuWindow, so the menu path is unaffected. Changes (2 lines removed, plus explanatory comments): - frame/qml/PanelMenu.qml: drop close() in the menu.visible guard - frame/qml/PanelPopup.qml: drop close() in the popup.visible guard Log: yes --- frame/qml/PanelMenu.qml | 8 +++++++- frame/qml/PanelPopup.qml | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/frame/qml/PanelMenu.qml b/frame/qml/PanelMenu.qml index c6a06efaa..2cede622a 100644 --- a/frame/qml/PanelMenu.qml +++ b/frame/qml/PanelMenu.qml @@ -44,8 +44,14 @@ Item { function open() { + // Keep open() pure-open semantics: when already visible, do nothing + // instead of toggling closed. The redundant toggle-close here caused + // BUG-353435: during the async window between open() setting + // menu.visible=true and finalizeOpen() calling grabMouse(), a second + // right-click could reach PluginItem, trigger another open(), and hit + // this branch, closing the menu. Left-click toggle is already handled + // in the C++ layer (itemPopupApplet). See PanelPopup.open() too. if (menu.visible) { - close() return } diff --git a/frame/qml/PanelPopup.qml b/frame/qml/PanelPopup.qml index 33b132533..bc3a1ce11 100644 --- a/frame/qml/PanelPopup.qml +++ b/frame/qml/PanelPopup.qml @@ -50,8 +50,14 @@ Item { function open() { + // Keep open() pure-open semantics: when already visible, do nothing + // instead of toggling closed. The redundant toggle-close here caused + // BUG-353435: during the async window between open() setting + // popup.visible=true and finalizeOpen() showing the window, a second + // right-click could reach PluginItem, trigger another open(), and hit + // this branch, closing the popup. Left-click toggle is already handled + // in the C++ layer (itemPopupApplet). See PanelMenu.open() too. if (popup.visible) { - close() return }