From 051dec5f8f26c80609f1c02a898bbd88889e99ce Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Thu, 7 Jan 2021 21:51:38 +0100 Subject: [PATCH] [PlasmaComponents MenuItem] Create dummy action when action gets destroyed `MenuItem` does not delete other people's `QAction` but it does not take kindly to the `QAction` being deleted under it. As a workaround recreate a dummy action when ours gets destroyed. This crash can easily be triggered by opening the Media Controller applet and quickly right-clicking its icon to open the context menu. Media Controller recreates its actions in `contextualActionsAboutToShow`, which removes and deletes them. Then the `Instantiator` in System Tray's `ExpandedRepresentation` updates its `model`, deleting the delegate items (`MenuItem` instances) it created. This prompts the `Menu` to run `removeMenuItem` on the now removed `MenuItem`, accessing its backing `action()` to remove it from the menu, resulting in a crash as it was deleted earlier. --- src/declarativeimports/plasmacomponents/qmenuitem.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/declarativeimports/plasmacomponents/qmenuitem.cpp b/src/declarativeimports/plasmacomponents/qmenuitem.cpp index cda74ca66..f128fba5f 100644 --- a/src/declarativeimports/plasmacomponents/qmenuitem.cpp +++ b/src/declarativeimports/plasmacomponents/qmenuitem.cpp @@ -47,6 +47,17 @@ void QMenuItem::setAction(QAction *a) connect(m_action, &QAction::changed, this, &QMenuItem::checkableChanged); connect(m_action, &QAction::toggled, this, &QMenuItem::toggled); connect(m_action, &QAction::triggered, this, &QMenuItem::clicked); + // HACK QMenuItem doesn't delete other people's QAction (see m_action->parent() check above) + // but it does not take kindly to the QAction being deleted under it + // as a workaround for crashing when this happens, replace it by a dummy action again + // TODO this entire ownership handling in QMenu(Item) needs to be refactored... + connect(m_action, &QObject::destroyed, this, [this] { + if (m_action->parent() != this) { + m_action = new QAction(this); + m_action->setVisible(false); + emit actionChanged(); + } + }); connect(this, &QQuickItem::visibleChanged, this, &QMenuItem::updateAction); connect(this, &QQuickItem::enabledChanged, this, &QMenuItem::updateAction);