Skip to content

Commit 3a5f35e

Browse files
laanwjknst
authored andcommitted
Merge bitcoin-core/gui#336: Do not exit and re-enter main event loop during shutdown
451ca24 qt, refactor: Drop intermediate BitcoinApplication::shutdownResult slot (Hennadii Stepanov) f3a17bb qt: Do not exit and re-enter main event loop during shutdown (Hennadii Stepanov) b4e0d2c qt, refactor: Allocate SendConfirmationDialog instances on heap (Hennadii Stepanov) 332dea2 qt, refactor: Keep HelpMessageDialog in the main event loop (Hennadii Stepanov) c8bae37 qt, refactor: Keep PSBTOperationsDialog in the main event loop (Hennadii Stepanov) 7fa91e8 qt, refactor: Keep AskPassphraseDialog in the main event loop (Hennadii Stepanov) 6f6fde3 qt, refactor: Keep EditAddressDialog in the main event loop (Hennadii Stepanov) 59f7ba4 qt, refactor: Keep CoinControlDialog in the main event loop (Hennadii Stepanov) 7830cd0 qt, refactor: Keep OptionsDialog in the main event loop (Hennadii Stepanov) 13f6188 qt: Add GUIUtil::ShowModalDialogAndDeleteOnClose (Hennadii Stepanov) Pull request description: On master (1ef34ee) during shutdown `QApplication` exits the main event loop, then re-enter again. This PR streamlines shutdown process by removing the need to interrupt the main event loop, that is required for dashpay#59. Also, blocking [`QDialog::exec()`](https://doc.qt.io/qt-5/qdialog.html#exec) calls are replaced with safer [`QDialog::show()`](https://doc.qt.io/qt-5/qwidget.html#show), except for `SendConfirmationDialog` as that change is not trivial (marked as TODO). The [`QDialog::open()`](https://doc.qt.io/qt-5/qdialog.html#open) was not used because the actual modality mode (application modal or window modal) of a dialog depends on whether it has a parent. This PR does not change behavior, and all touched dialogs are still application modal. As a follow up, a design research could suggest to make some dialogs window modal. NOTE for reviewers: quitting app while a dialog is open (e.g., via systray icon menu) must work fine. ACKs for top commit: laanwj: Code review and lighly tested ACK 451ca24 promag: ACK 451ca24, just changed signal to `quitRequested`. Tree-SHA512: ef01ab6ed803b202e776019a4e1f592e816f7bc786e00574b25a0bf16be2374ddf9db21f0a26da08700df7ef0ab9e879550df46dcfe3b6d940f5ed02ca5f8447
1 parent 4a82d49 commit 3a5f35e

13 files changed

+73
-58
lines changed

src/qt/addressbookpage.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,14 @@ void AddressBookPage::onEditAction()
185185
if(indexes.isEmpty())
186186
return;
187187

188-
EditAddressDialog dlg(
188+
auto dlg = new EditAddressDialog(
189189
tab == SendingTab ?
190190
EditAddressDialog::EditSendingAddress :
191191
EditAddressDialog::EditReceivingAddress, this);
192-
dlg.setModel(model);
192+
dlg->setModel(model);
193193
QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
194-
dlg.loadRow(origIndex.row());
195-
dlg.exec();
194+
dlg->loadRow(origIndex.row());
195+
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
196196
}
197197

198198
void AddressBookPage::on_newAddress_clicked()

src/qt/bitcoin.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include <QThread>
5959
#include <QTimer>
6060
#include <QTranslator>
61+
#include <QWindow>
6162

6263
#if defined(QT_STATIC)
6364
#include <QtPlugin>
@@ -256,6 +257,8 @@ void BitcoinApplication::createOptionsModel(bool resetSettings)
256257
void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
257258
{
258259
window = new BitcoinGUI(node(), networkStyle, nullptr);
260+
connect(window, &BitcoinGUI::quitRequested, this, &BitcoinApplication::requestShutdown);
261+
259262
pollShutdownTimer = new QTimer(window);
260263
connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown);
261264
}
@@ -290,7 +293,7 @@ void BitcoinApplication::startThread()
290293

291294
/* communication to and from thread */
292295
connect(&m_executor.value(), &InitExecutor::initializeResult, this, &BitcoinApplication::initializeResult);
293-
connect(&m_executor.value(), &InitExecutor::shutdownResult, this, &BitcoinApplication::shutdownResult);
296+
connect(&m_executor.value(), &InitExecutor::shutdownResult, this, &QCoreApplication::quit);
294297
connect(&m_executor.value(), &InitExecutor::runawayException, this, &BitcoinApplication::handleRunawayException);
295298
connect(this, &BitcoinApplication::requestedInitialize, &m_executor.value(), &InitExecutor::initialize);
296299
connect(this, &BitcoinApplication::requestedShutdown, &m_executor.value(), &InitExecutor::shutdown);
@@ -321,13 +324,17 @@ void BitcoinApplication::requestInitialize()
321324

322325
void BitcoinApplication::requestShutdown()
323326
{
327+
for (const auto w : QGuiApplication::topLevelWindows()) {
328+
w->hide();
329+
}
330+
324331
// Show a simple window indicating shutdown status
325332
// Do this first as some of the steps may take some time below,
326333
// for example the RPC console may still be executing a command.
327334
shutdownWindow.reset(ShutdownWindow::showShutdownWindow(window));
328335

329336
qDebug() << __func__ << ": Requesting shutdown";
330-
window->hide();
337+
331338
// Must disconnect node signals otherwise current thread can deadlock since
332339
// no event loop is running.
333340
window->unsubscribeFromCoreSignals();
@@ -407,15 +414,10 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead
407414
pollShutdownTimer->start(SHUTDOWN_POLLING_DELAY);
408415
} else {
409416
Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown
410-
quit(); // Exit first main loop invocation
417+
requestShutdown();
411418
}
412419
}
413420

414-
void BitcoinApplication::shutdownResult()
415-
{
416-
quit(); // Exit second main loop invocation after shutdown finished
417-
}
418-
419421
void BitcoinApplication::handleRunawayException(const QString &message)
420422
{
421423
QMessageBox::critical(
@@ -745,8 +747,6 @@ int GuiMain(int argc, char* argv[])
745747
#if defined(Q_OS_WIN)
746748
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely…").arg(PACKAGE_NAME), (HWND)app.getMainWinId());
747749
#endif
748-
app.exec();
749-
app.requestShutdown();
750750
app.exec();
751751
rv = app.getReturnValue();
752752
} else {

src/qt/bitcoin.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ class BitcoinApplication: public QApplication
6060

6161
/// Request core initialization
6262
void requestInitialize();
63-
/// Request core shutdown
64-
void requestShutdown();
6563

6664
/// Get process return value
6765
int getReturnValue() const { return returnValue; }
@@ -73,7 +71,8 @@ class BitcoinApplication: public QApplication
7371

7472
public Q_SLOTS:
7573
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info);
76-
void shutdownResult();
74+
/// Request core shutdown
75+
void requestShutdown();
7776
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
7877
void handleRunawayException(const QString &message);
7978

src/qt/bitcoingui.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ void BitcoinGUI::createActions()
475475
m_mask_values_action->setStatusTip(tr("Mask the values in the Overview tab"));
476476
m_mask_values_action->setCheckable(true);
477477

478-
connect(quitAction, &QAction::triggered, qApp, QApplication::quit);
478+
connect(quitAction, &QAction::triggered, this, &BitcoinGUI::quitRequested);
479479
connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked);
480480
connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt);
481481
connect(optionsAction, &QAction::triggered, this, &BitcoinGUI::optionsClicked);
@@ -1097,8 +1097,8 @@ void BitcoinGUI::aboutClicked()
10971097
if(!clientModel)
10981098
return;
10991099

1100-
HelpMessageDialog dlg(this, HelpMessageDialog::about);
1101-
dlg.exec();
1100+
auto dlg = new HelpMessageDialog(this, HelpMessageDialog::about);
1101+
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
11021102
}
11031103

11041104
void BitcoinGUI::showDebugWindow()
@@ -1353,13 +1353,14 @@ void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab)
13531353
if (!clientModel || !clientModel->getOptionsModel())
13541354
return;
13551355

1356-
OptionsDialog dlg(this, enableWallet);
1357-
dlg.setCurrentTab(tab);
1358-
dlg.setModel(clientModel->getOptionsModel());
1359-
connect(&dlg, &OptionsDialog::appearanceChanged, [=]() {
1356+
auto dlg = new OptionsDialog(this, enableWallet);
1357+
connect(dlg, &OptionsDialog::quitOnReset, this, &BitcoinGUI::quitRequested);
1358+
dlg->setCurrentTab(tab);
1359+
dlg->setModel(clientModel->getOptionsModel());
1360+
connect(dlg, &OptionsDialog::appearanceChanged, [=]() {
13601361
updateWidth();
13611362
});
1362-
dlg.exec();
1363+
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
13631364

13641365
updateCoinJoinVisibility();
13651366
}
@@ -1703,7 +1704,7 @@ void BitcoinGUI::closeEvent(QCloseEvent *event)
17031704
// close rpcConsole in case it was open to make some space for the shutdown window
17041705
rpcConsole->close();
17051706

1706-
QApplication::quit();
1707+
Q_EMIT quitRequested();
17071708
}
17081709
else
17091710
{
@@ -1997,7 +1998,7 @@ void BitcoinGUI::detectShutdown()
19971998
{
19981999
if(rpcConsole)
19992000
rpcConsole->hide();
2000-
qApp->quit();
2001+
Q_EMIT quitRequested();
20012002
}
20022003
}
20032004

src/qt/bitcoingui.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ class BitcoinGUI : public QMainWindow
254254
void openOptionsDialogWithTab(OptionsDialog::Tab tab);
255255

256256
Q_SIGNALS:
257+
void quitRequested();
257258
/** Signal raised when a URI was entered or dragged to the GUI */
258259
void receivedURI(const QString &uri);
259260
/** Signal raised when RPC console shown */

src/qt/guiutil.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <QDateTime>
4343
#include <QDebug>
4444
#include <QDesktopServices>
45+
#include <QDialog>
4546
#include <QDialogButtonBox>
4647
#include <QDoubleValidator>
4748
#include <QFileDialog>
@@ -1949,4 +1950,11 @@ void PrintSlotException(
19491950
PrintExceptionContinue(std::make_exception_ptr(exception), description.c_str());
19501951
}
19511952

1953+
void ShowModalDialogAndDeleteOnClose(QDialog* dialog)
1954+
{
1955+
dialog->setAttribute(Qt::WA_DeleteOnClose);
1956+
dialog->setWindowModality(Qt::ApplicationModal);
1957+
dialog->show();
1958+
}
1959+
19521960
} // namespace GUIUtil

src/qt/guiutil.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class QAbstractItemView;
4343
class QAction;
4444
class QButtonGroup;
4545
class QDateTime;
46+
class QDialog;
4647
class QFont;
4748
class QKeySequence;
4849
class QLineEdit;
@@ -609,6 +610,11 @@ namespace GUIUtil
609610
type);
610611
}
611612

613+
/**
614+
* Shows a QDialog instance asynchronously, and deletes it on close.
615+
*/
616+
void ShowModalDialogAndDeleteOnClose(QDialog* dialog);
617+
612618
} // namespace GUIUtil
613619

614620
#endif // BITCOIN_QT_GUIUTIL_H

src/qt/optionsdialog.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,8 @@ void OptionsDialog::on_resetButton_clicked()
406406
/* reset all options and close GUI */
407407
model->Reset();
408408
model->resetSettingsOnShutdown = true;
409-
QApplication::quit();
409+
close();
410+
Q_EMIT quitOnReset();
410411
}
411412
}
412413

src/qt/optionsdialog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ private Q_SLOTS:
8282
Q_SIGNALS:
8383
void appearanceChanged();
8484
void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, uint16_t nProxyPort);
85+
void quitOnReset();
8586

8687
private:
8788
Ui::OptionsDialog *ui;

src/qt/sendcoinsdialog.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,10 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
476476

477477
const QString confirmation = model->wallet().privateKeysDisabled() ? tr("Confirm transaction proposal") : tr("Confirm send coins");
478478
const QString confirmButtonText = model->wallet().privateKeysDisabled() ? tr("Create Unsigned") : tr("Send");
479-
SendConfirmationDialog confirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this);
480-
confirmationDialog.exec();
481-
QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result());
479+
auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this);
480+
confirmationDialog->setAttribute(Qt::WA_DeleteOnClose);
481+
// TODO: Replace QDialog::exec() with safer QDialog::show().
482+
const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec());
482483

483484
if(retval != QMessageBox::Yes)
484485
{
@@ -937,9 +938,9 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
937938
// Coin Control: button inputs -> show actual coin control dialog
938939
void SendCoinsDialog::coinControlButtonClicked()
939940
{
940-
CoinControlDialog dlg(*m_coin_control, model, this);
941-
dlg.exec();
942-
coinControlUpdateLabels();
941+
auto dlg = new CoinControlDialog(*m_coin_control, model);
942+
connect(dlg, &QDialog::finished, this, &SendCoinsDialog::coinControlUpdateLabels);
943+
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
943944
}
944945

945946
// Coin Control: checkbox custom change address

0 commit comments

Comments
 (0)