QMenu: don't crash when another popup is closed when a popup is closed
When closing a popup (submenu) triggers closing another popup (the menu) programatically it can happen that QApplicationPrivate::popupWidgets is destroyed. Therefore we have to check if popupWidgets is still valid after the focus change event was delivered. Fixes: QTBUG-81222 Change-Id: Ide3a6897e43f389d396a80d8b158f7c8eb04e3aa Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
parent
a11267c532
commit
5c3b5efd40
@ -3762,7 +3762,9 @@ void QApplicationPrivate::closePopup(QWidget *popup)
|
||||
if (QWidget *fw = aw->focusWidget())
|
||||
fw->setFocus(Qt::PopupFocusReason);
|
||||
|
||||
if (QApplicationPrivate::popupWidgets->count() == 1) // grab mouse/keyboard
|
||||
// can become nullptr due to setFocus() above
|
||||
if (QApplicationPrivate::popupWidgets &&
|
||||
QApplicationPrivate::popupWidgets->count() == 1) // grab mouse/keyboard
|
||||
grabForPopup(aw);
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <QWidgetAction>
|
||||
#include <QDesktopWidget>
|
||||
#include <QScreen>
|
||||
#include <QSpinBox>
|
||||
#include <qdialog.h>
|
||||
|
||||
#include <qmenu.h>
|
||||
@ -114,6 +115,7 @@ private slots:
|
||||
void QTBUG30595_rtl_submenu();
|
||||
void QTBUG20403_nested_popup_on_shortcut_trigger();
|
||||
void QTBUG47515_widgetActionEnterLeave();
|
||||
void QTBUG8122_widgetActionCrashOnClose();
|
||||
|
||||
void QTBUG_10735_crashWithDialog();
|
||||
#ifdef Q_OS_MAC
|
||||
@ -1352,6 +1354,60 @@ void tst_QMenu::QTBUG47515_widgetActionEnterLeave()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QMenu::QTBUG8122_widgetActionCrashOnClose()
|
||||
{
|
||||
if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
|
||||
QSKIP("Window activation is not supported");
|
||||
if (QGuiApplication::platformName() == QLatin1String("cocoa"))
|
||||
QSKIP("See QTBUG-63031");
|
||||
#ifdef Q_OS_WINRT
|
||||
QSKIP("WinRT does not support QTest::mouseMove");
|
||||
#endif
|
||||
|
||||
const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
|
||||
QRect geometry(QPoint(), availableGeometry.size() / 3);
|
||||
geometry.moveCenter(availableGeometry.center());
|
||||
QPoint pointOutsideMenu = geometry.bottomRight() - QPoint(5, 5);
|
||||
|
||||
QMainWindow topLevel;
|
||||
topLevel.setGeometry(geometry);
|
||||
|
||||
auto menuBar = topLevel.menuBar();
|
||||
auto menu = menuBar->addMenu("Menu");
|
||||
auto wAct = new QWidgetAction(menu);
|
||||
auto spinBox1 = new QSpinBox(menu);
|
||||
wAct->setDefaultWidget(spinBox1);
|
||||
menu->addAction(wAct);
|
||||
auto subMenu = menu->addMenu("Submenu");
|
||||
auto nextMenuAct = menu->addMenu(subMenu);
|
||||
auto wAct2 = new QWidgetAction(menu);
|
||||
auto spinBox2 = new QSpinBox(menu);
|
||||
wAct2->setDefaultWidget(spinBox2);
|
||||
subMenu->addAction(wAct2);
|
||||
QObject::connect(spinBox2, &QSpinBox::editingFinished, menu, &QMenu::hide);
|
||||
|
||||
topLevel.show();
|
||||
topLevel.setWindowTitle(QTest::currentTestFunction());
|
||||
QVERIFY(QTest::qWaitForWindowActive(&topLevel));
|
||||
QWindow *topLevelWindow = topLevel.windowHandle();
|
||||
QVERIFY(topLevelWindow);
|
||||
|
||||
const QPoint menuActionPos = menuBar->mapTo(&topLevel, menuBar->actionGeometry(menu->menuAction()).center());
|
||||
QTest::mouseClick(topLevelWindow, Qt::LeftButton, Qt::KeyboardModifiers(), menuActionPos);
|
||||
QVERIFY(QTest::qWaitForWindowExposed(menu));
|
||||
|
||||
QPoint w1Center = topLevel.mapFromGlobal(spinBox1->mapToGlobal(spinBox1->rect().center()));
|
||||
QTest::mouseClick(topLevelWindow, Qt::LeftButton, Qt::KeyboardModifiers(), w1Center);
|
||||
menu->setActiveAction(nextMenuAct);
|
||||
QVERIFY(QTest::qWaitForWindowExposed(subMenu));
|
||||
|
||||
QPoint w2Center = topLevel.mapFromGlobal(spinBox2->mapToGlobal(spinBox2->rect().center()));
|
||||
QTest::mouseClick(topLevelWindow, Qt::LeftButton, Qt::KeyboardModifiers(), w2Center);
|
||||
QTest::mouseMove(topLevelWindow, topLevel.mapFromGlobal(pointOutsideMenu));
|
||||
QTRY_VERIFY(menu->isHidden());
|
||||
}
|
||||
|
||||
|
||||
class MyMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
|
Loading…
Reference in New Issue
Block a user