From 05016926ae37ae73a9da9375a95f3a4e8234477e Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 10 Feb 2025 20:16:16 +0100 Subject: [PATCH] QToolButton: allow opening a menu after it first failed because empty Commit 353ce5344fbde5a6cecbdd2c131e1cf0f4b7f383 made QMenu::exec() return immediately (without showing the menu), which meant it never emitted aboutToHide() and QToolButton didn't reset mouseButtonDown. Therefore, on the next click on the toolbutton (maybe by then the menu has actions), it won't even try to show it (because mouseButtonDown is still true). Pick-to: 6.8 Task-number: QTBUG-129108 Change-Id: I3f84b9a35eb444fc33d8516c4be130293c04017d Reviewed-by: Volker Hilsheimer (cherry picked from commit f0508b7ff3d2393521f49dcb1a9e880bf7665a87) Reviewed-by: Qt Cherry-pick Bot --- src/widgets/widgets/qtoolbutton.cpp | 5 ++++ .../widgets/qtoolbutton/tst_qtoolbutton.cpp | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/widgets/widgets/qtoolbutton.cpp b/src/widgets/widgets/qtoolbutton.cpp index e0775afd265..8957e93f051 100644 --- a/src/widgets/widgets/qtoolbutton.cpp +++ b/src/widgets/widgets/qtoolbutton.cpp @@ -788,6 +788,11 @@ void QToolButtonPrivate::popupTimerDone() QObjectPrivate::disconnect(actualMenu, &QMenu::aboutToHide, this, &QToolButtonPrivate::updateButtonDown); + if (menuButtonDown) { + // The menu was empty, it didn't actually show up, so it was never hidden either + updateButtonDown(); + } + if (mustDeleteActualMenu) { delete actualMenu; } else { diff --git a/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp b/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp index 81a8fb0efca..9588f193387 100644 --- a/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp +++ b/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp @@ -35,6 +35,7 @@ private slots: void qtbug_34759_sizeHintResetWhenSettingMenu(); void defaultActionSynced(); void deleteInHandler(); + void emptyMenu(); protected slots: void sendMouseClick(); @@ -338,5 +339,27 @@ void tst_QToolButton::deleteInHandler() QVERIFY(!tb); } +void tst_QToolButton::emptyMenu() +{ + + QToolButton tb; + auto menu = new QMenu(&tb); + tb.setMenu(menu); + tb.showMenu(); // calls exec(), but since the fix for QTBUG-129108, we don't show an empty menu + + // see triggered() test + QTest::mouseMove(tb.windowHandle(), tb.mapFromGlobal(QPoint(0, 0))); + + // But if we now put something in the menu, it should show up + auto act = menu->addAction("an action"); + QSignalSpy triggeredSpy(act, &QAction::triggered); + // In 200ms, click on the action so that exec() returns + QTimer::singleShot(200, menu, [&]() { + QTest::mouseClick(menu, Qt::LeftButton, {}, menu->rect().center()); + }); + tb.showMenu(); // calls exec(), which only returns in 200ms + QTRY_COMPARE(triggeredSpy.size(), 1); +} + QTEST_MAIN(tst_QToolButton) #include "tst_qtoolbutton.moc"