1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
From 7387547112e1a00aca294861abee666de3fbd68f Mon Sep 17 00:00:00 2001
From: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
Date: Fri, 18 Apr 2025 22:39:46 +0300
Subject: [PATCH] applets/appmenu: Fix displaying menu of the previous active
window
We need to break the DBusMenuImporter::menuUpdated() signal connection
when the active window changes. Otherwise, it's possible that the
menuUpdated signal will be emitted and the menu will be marked as
available.
BUG: 473714
---
applets/appmenu/plugin/appmenumodel.cpp | 115 +++++++++++++-----------
1 file changed, 63 insertions(+), 52 deletions(-)
diff --git a/applets/appmenu/plugin/appmenumodel.cpp b/applets/appmenu/plugin/appmenumodel.cpp
index 04834b6fab6..db3b351405f 100644
--- a/applets/appmenu/plugin/appmenumodel.cpp
+++ b/applets/appmenu/plugin/appmenumodel.cpp
@@ -202,16 +202,7 @@ void AppMenuModel::onActiveWindowChanged()
const QModelIndex activeTaskIndex = m_tasksModel->activeTask();
const QString objectPath = m_tasksModel->data(activeTaskIndex, TaskManager::AbstractTasksModel::ApplicationMenuObjectPath).toString();
const QString serviceName = m_tasksModel->data(activeTaskIndex, TaskManager::AbstractTasksModel::ApplicationMenuServiceName).toString();
-
- if (!objectPath.isEmpty() && !serviceName.isEmpty()) {
- setMenuAvailable(true);
- updateApplicationMenu(serviceName, objectPath);
- setVisible(true);
- Q_EMIT modelNeedsUpdate();
- } else {
- setMenuAvailable(false);
- setVisible(false);
- }
+ updateApplicationMenu(serviceName, objectPath);
}
QHash<int, QByteArray> AppMenuModel::roleNames() const
@@ -282,61 +273,81 @@ void AppMenuModel::updateApplicationMenu(const QString &serviceName, const QStri
return;
}
- m_serviceName = serviceName;
- m_serviceWatcher->setWatchedServices(QStringList({m_serviceName}));
-
- m_menuObjectPath = menuObjectPath;
+ if (serviceName.isEmpty() || menuObjectPath.isEmpty()) {
+ setMenuAvailable(false);
+ setVisible(false);
- if (m_importer) {
- m_importer->deleteLater();
- }
+ m_serviceName = QString();
+ m_menuObjectPath = QString();
+ m_serviceWatcher->setWatchedServices({});
- m_importer = new KDBusMenuImporter(serviceName, menuObjectPath, this);
- QMetaObject::invokeMethod(m_importer, "updateMenu", Qt::QueuedConnection);
+ if (m_importer) {
+ m_importer->disconnect(this);
+ m_importer->deleteLater();
+ m_importer = nullptr;
+ }
+ } else {
+ m_serviceName = serviceName;
+ m_menuObjectPath = menuObjectPath;
+ m_serviceWatcher->setWatchedServices(QStringList({m_serviceName}));
- connect(m_importer.data(), &DBusMenuImporter::menuUpdated, this, [=, this](QMenu *menu) {
- m_menu = m_importer->menu();
- if (m_menu.isNull() || menu != m_menu) {
- return;
+ if (m_importer) {
+ m_importer->disconnect(this);
+ m_importer->deleteLater();
}
- // cache first layer of sub menus, which we'll be popping up
- const auto actions = m_menu->actions();
- for (QAction *a : actions) {
- // signal dataChanged when the action changes
- connect(a, &QAction::changed, this, [this, a] {
- if (m_menuAvailable && m_menu) {
- const int actionIdx = m_menu->actions().indexOf(a);
- if (actionIdx > -1) {
- const QModelIndex modelIdx = index(actionIdx, 0);
- Q_EMIT dataChanged(modelIdx, modelIdx);
+ m_importer = new KDBusMenuImporter(serviceName, menuObjectPath, this);
+ QMetaObject::invokeMethod(m_importer, "updateMenu", Qt::QueuedConnection);
+
+ connect(m_importer.data(), &DBusMenuImporter::menuUpdated, this, [=, this](QMenu *menu) {
+ m_menu = m_importer->menu();
+ if (m_menu.isNull() || menu != m_menu) {
+ return;
+ }
+
+ // cache first layer of sub menus, which we'll be popping up
+ const auto actions = m_menu->actions();
+ for (QAction *a : actions) {
+ // signal dataChanged when the action changes
+ connect(a, &QAction::changed, this, [this, a] {
+ if (m_menuAvailable && m_menu) {
+ const int actionIdx = m_menu->actions().indexOf(a);
+ if (actionIdx > -1) {
+ const QModelIndex modelIdx = index(actionIdx, 0);
+ Q_EMIT dataChanged(modelIdx, modelIdx);
+ }
}
+ });
+
+ connect(a, &QAction::destroyed, this, &AppMenuModel::modelNeedsUpdate);
+
+ if (a->menu()) {
+ m_importer->updateMenu(a->menu());
}
- });
+ }
- connect(a, &QAction::destroyed, this, &AppMenuModel::modelNeedsUpdate);
+ setMenuAvailable(true);
+ Q_EMIT modelNeedsUpdate();
+ });
- if (a->menu()) {
- m_importer->updateMenu(a->menu());
+ connect(m_importer.data(), &DBusMenuImporter::actionActivationRequested, this, [this](QAction *action) {
+ // TODO submenus
+ if (!m_menuAvailable || !m_menu) {
+ return;
}
- }
- setMenuAvailable(true);
- Q_EMIT modelNeedsUpdate();
- });
+ const auto actions = m_menu->actions();
+ auto it = std::find(actions.begin(), actions.end(), action);
+ if (it != actions.end()) {
+ Q_EMIT requestActivateIndex(it - actions.begin());
+ }
+ });
- connect(m_importer.data(), &DBusMenuImporter::actionActivationRequested, this, [this](QAction *action) {
- // TODO submenus
- if (!m_menuAvailable || !m_menu) {
- return;
- }
+ setMenuAvailable(true);
+ setVisible(true);
- const auto actions = m_menu->actions();
- auto it = std::find(actions.begin(), actions.end(), action);
- if (it != actions.end()) {
- Q_EMIT requestActivateIndex(it - actions.begin());
- }
- });
+ Q_EMIT modelNeedsUpdate();
+ }
}
#include "moc_appmenumodel.cpp"
--
GitLab
|