summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets/qmenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/widgets/qmenu.cpp')
-rw-r--r--src/widgets/widgets/qmenu.cpp44
1 files changed, 37 insertions, 7 deletions
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index 987dce71d9..db00f8a650 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -93,7 +93,9 @@ public:
Q_D(QTornOffMenu);
// make the torn-off menu a sibling of p (instead of a child)
QWidget *parentWidget = d->causedStack.isEmpty() ? p : d->causedStack.constLast();
- if (parentWidget->parentWidget())
+ if (!parentWidget && p)
+ parentWidget = p;
+ if (parentWidget && parentWidget->parentWidget())
parentWidget = parentWidget->parentWidget();
setParent(parentWidget, Qt::Window | Qt::Tool);
setAttribute(Qt::WA_DeleteOnClose, true);
@@ -163,7 +165,7 @@ void QMenuPrivate::init()
defaultMenuAction = menuAction = new QAction(q);
menuAction->setMenu(q); // this calls setOverrideMenuAction
setOverrideMenuAction(nullptr);
- QObject::connect(menuAction, &QAction::changed, [this] {
+ QObject::connect(menuAction, &QAction::changed, q, [this] {
if (!tornPopup.isNull())
tornPopup->updateWindowTitle();
});
@@ -290,6 +292,13 @@ inline bool QMenuPrivate::useFullScreenForPopup() const
QRect QMenuPrivate::popupGeometry(QScreen *screen) const
{
Q_Q(const QMenu);
+ if (screen == nullptr
+#if QT_CONFIG(graphicsview)
+ && q->graphicsProxyWidget() == nullptr
+#endif
+ ) {
+ screen = q->isVisible() ? q->screen() : popupScreen.data();
+ }
if (useFullScreenForPopup())
return screen ? screen->geometry()
: QWidgetPrivate::screenGeometry(q);
@@ -567,10 +576,16 @@ void QMenuPrivate::hideMenu(QMenu *menu)
};
#if QT_CONFIG(effects)
- QSignalBlocker blocker(menu);
+ // If deleteLater has been called and the event loop spins, while waiting
+ // for visual effects to happen, menu might become stale.
+ // To prevent a QSignalBlocker from restoring a stale object, block and restore signals manually.
+ QPointer<QMenu> stillAlive(menu);
+ const bool signalsBlocked = menu->signalsBlocked();
+ menu->blockSignals(true);
+
aboutToHide = true;
// Flash item which is about to trigger (if any).
- if (menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)
+ if (menu && menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)
&& currentAction && currentAction == actionAboutToTrigger
&& menu->actions().contains(currentAction)) {
QEventLoop eventLoop;
@@ -581,6 +596,9 @@ void QMenuPrivate::hideMenu(QMenu *menu)
QTimer::singleShot(60, &eventLoop, SLOT(quit()));
eventLoop.exec();
+ if (!stillAlive)
+ return;
+
// Select and wait 20 ms.
menu->setActiveAction(activeAction);
QTimer::singleShot(20, &eventLoop, SLOT(quit()));
@@ -588,10 +606,16 @@ void QMenuPrivate::hideMenu(QMenu *menu)
}
aboutToHide = false;
- blocker.unblock();
+
+ if (stillAlive)
+ menu->blockSignals(signalsBlocked);
+ else
+ return;
+
#endif // QT_CONFIG(effects)
if (activeMenu == menu)
activeMenu = nullptr;
+
menu->d_func()->causedPopup.action = nullptr;
menu->close();
menu->d_func()->causedPopup.widget = nullptr;
@@ -1708,7 +1732,7 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action)
\b{Important inherited functions:} addAction(), removeAction(), clear(),
addSeparator(), and addMenu().
- \sa QMenuBar, {Qt Widgets - Application Example}, {Menus Example}
+ \sa QMenuBar, {Menus Example}
*/
@@ -2292,6 +2316,9 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction positionFunction)
{
Q_Q(QMenu);
+ popupScreen = QGuiApplication::screenAt(p);
+ QScopeGuard popupScreenGuard([this](){ popupScreen.clear(); });
+
if (scroll) { // reset scroll state from last popup
if (scroll->scrollOffset)
itemsDirty = 1; // sizeHint will be incorrect if there is previous scroll
@@ -2367,6 +2394,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po
pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition();
else
pos = p;
+ popupScreen = QGuiApplication::screenAt(pos);
const QSize menuSizeHint(q->sizeHint());
QSize size = menuSizeHint;
@@ -2505,6 +2533,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po
}
}
}
+ popupScreen = QGuiApplication::screenAt(pos);
q->setGeometry(QRect(pos, size));
#if QT_CONFIG(effects)
int hGuess = q->isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
@@ -2645,6 +2674,7 @@ QAction *QMenuPrivate::exec(const QPoint &p, QAction *action, PositionFunction p
action = syncAction;
syncAction = nullptr;
eventLoop = nullptr;
+ popupScreen.clear();
return action;
}
@@ -2822,7 +2852,7 @@ void QMenu::paintEvent(QPaintEvent *e)
frame.rect = rect();
frame.palette = palette();
frame.state = QStyle::State_None;
- frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &frame);
+ frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &frame, this);
frame.midLineWidth = 0;
p.drawPrimitive(QStyle::PE_FrameMenu, frame);
}