[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.
This commit is contained in:
Kai Uwe Broulik 2021-01-07 21:51:38 +01:00
parent 2864f99dc5
commit 051dec5f8f

View File

@ -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);