Skip to content

Commit 1695d66

Browse files
committed
Merge bitcoin-core/gui#509: Respect dialog modality and fix a regression in wallet unlock
f730bd7 scripted-diff: Rename ShowModalDialogAndDeleteOnClose (Hennadii Stepanov) 5d7666b qt: Revert 7fa91e8 partially (Hennadii Stepanov) 89c277a qt: Delay shutdown while a modal dialog is active (Hennadii Stepanov) 8c0eb80 qt: Disable tray icon menu when a modal dialog is active (Hennadii Stepanov) 9242735 qt, refactor: Use local QAction instances for the tray icon menu (Hennadii Stepanov) 58e1603 qt, refactor: Drop BitcoinGUI::{send,receive}CoinsMenuAction members (Hennadii Stepanov) fd667e7 qt: Make show_hide_action dependent on the main window actual state (Hennadii Stepanov) ee151d0 qt: Drop BitcoinGUI::toggleHideAction member (Hennadii Stepanov) 78189da qt, refactor: Fill up trayIconMenu before connections (Hennadii Stepanov) 66afa28 qt, refactor: Replace BitcoinGUI::trayIconActivated with a lambda (Hennadii Stepanov) c3ca836 qt, refactor: Replace BitcoinGUI::macosDockIconActivated with a lambda (Hennadii Stepanov) Pull request description: As pointed in bitcoin#23790 a regression in wallet unlock was introduced in bitcoin-core/gui#336 when a synchronous `AskPassphraseDialog` has been replaced with an asynchronous one. This PR reverts a call back to a synchronous mode. To make synchronous dialogs behave nice during shutdown some additional changes were made. Please note that disabling the tray icon menu when a modal dialog is active is useful itself as on master (4ad5904) it is possible to switch to the "Receive" tab while the GUI is waiting for a password for the "Send" tab: ![Screenshot from 2021-12-17 18-59-51](https://user-images.githubusercontent.com/32963518/146580710-0a755f24-a166-414b-be60-7863232ac778.png) This is confusing and must be avoided. Fixes bitcoin#23790. ACKs for top commit: prayank23: tACK bitcoin-core/gui@f730bd7 Tree-SHA512: 2b68275754190e4a9831b96e882d3c5b005e03909aeb6f2c5846da07199bb3efbb74ce87a9d25bb139f643c43d377a2051b221d553281fa5aefdd3181a58077f
2 parents 8fe6f5a + f730bd7 commit 1695d66

File tree

10 files changed

+85
-83
lines changed

10 files changed

+85
-83
lines changed

src/qt/addressbookpage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ void AddressBookPage::onEditAction()
189189
dlg->setModel(model);
190190
QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
191191
dlg->loadRow(origIndex.row());
192-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
192+
GUIUtil::ShowModalDialogAsynchronously(dlg);
193193
}
194194

195195
void AddressBookPage::on_newAddress_clicked()

src/qt/bitcoin.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,11 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
268268
connect(window, &BitcoinGUI::quitRequested, this, &BitcoinApplication::requestShutdown);
269269

270270
pollShutdownTimer = new QTimer(window);
271-
connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown);
271+
connect(pollShutdownTimer, &QTimer::timeout, [this]{
272+
if (!QApplication::activeModalWidget()) {
273+
window->detectShutdown();
274+
}
275+
});
272276
}
273277

274278
void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)

src/qt/bitcoingui.cpp

Lines changed: 66 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -261,21 +261,13 @@ void BitcoinGUI::createActions()
261261
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
262262
tabGroup->addAction(sendCoinsAction);
263263

264-
sendCoinsMenuAction = new QAction(sendCoinsAction->text(), this);
265-
sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip());
266-
sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip());
267-
268264
receiveCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
269265
receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
270266
receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
271267
receiveCoinsAction->setCheckable(true);
272268
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
273269
tabGroup->addAction(receiveCoinsAction);
274270

275-
receiveCoinsMenuAction = new QAction(receiveCoinsAction->text(), this);
276-
receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip());
277-
receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip());
278-
279271
historyAction = new QAction(platformStyle->SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
280272
historyAction->setStatusTip(tr("Browse transaction history"));
281273
historyAction->setToolTip(historyAction->statusTip());
@@ -290,12 +282,8 @@ void BitcoinGUI::createActions()
290282
connect(overviewAction, &QAction::triggered, this, &BitcoinGUI::gotoOverviewPage);
291283
connect(sendCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
292284
connect(sendCoinsAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); });
293-
connect(sendCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
294-
connect(sendCoinsMenuAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); });
295285
connect(receiveCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
296286
connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
297-
connect(receiveCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
298-
connect(receiveCoinsMenuAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
299287
connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
300288
connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage);
301289
#endif // ENABLE_WALLET
@@ -315,8 +303,6 @@ void BitcoinGUI::createActions()
315303
optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(PACKAGE_NAME));
316304
optionsAction->setMenuRole(QAction::PreferencesRole);
317305
optionsAction->setEnabled(false);
318-
toggleHideAction = new QAction(tr("&Show / Hide"), this);
319-
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
320306

321307
encryptWalletAction = new QAction(tr("&Encrypt Wallet…"), this);
322308
encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
@@ -376,7 +362,6 @@ void BitcoinGUI::createActions()
376362
connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked);
377363
connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt);
378364
connect(optionsAction, &QAction::triggered, this, &BitcoinGUI::optionsClicked);
379-
connect(toggleHideAction, &QAction::triggered, this, &BitcoinGUI::toggleHidden);
380365
connect(showHelpMessageAction, &QAction::triggered, this, &BitcoinGUI::showHelpMessageClicked);
381366
connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showDebugWindow);
382367
// prevents an open debug window from becoming stuck/unusable on client shutdown
@@ -627,8 +612,6 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH
627612
trayIcon->setVisible(optionsModel->getShowTrayIcon());
628613
}
629614
} else {
630-
// Disable possibility to show main window via action
631-
toggleHideAction->setEnabled(false);
632615
if(trayIconMenu)
633616
{
634617
// Disable context menu on tray icon
@@ -752,9 +735,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
752735
{
753736
overviewAction->setEnabled(enabled);
754737
sendCoinsAction->setEnabled(enabled);
755-
sendCoinsMenuAction->setEnabled(enabled);
756738
receiveCoinsAction->setEnabled(enabled);
757-
receiveCoinsMenuAction->setEnabled(enabled);
758739
historyAction->setEnabled(enabled);
759740
encryptWalletAction->setEnabled(enabled);
760741
backupWalletAction->setEnabled(enabled);
@@ -784,57 +765,82 @@ void BitcoinGUI::createTrayIcon()
784765
void BitcoinGUI::createTrayIconMenu()
785766
{
786767
#ifndef Q_OS_MAC
787-
// return if trayIcon is unset (only on non-macOSes)
788-
if (!trayIcon)
789-
return;
790-
791-
trayIcon->setContextMenu(trayIconMenu.get());
792-
connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated);
793-
#else
794-
// Note: On macOS, the Dock icon is used to provide the tray's functionality.
795-
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
796-
connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated);
797-
trayIconMenu->setAsDockMenu();
798-
#endif
768+
if (!trayIcon) return;
769+
#endif // Q_OS_MAC
799770

800-
// Configuration of the tray icon (or Dock icon) menu
771+
// Configuration of the tray icon (or Dock icon) menu.
772+
QAction* show_hide_action{nullptr};
801773
#ifndef Q_OS_MAC
802774
// Note: On macOS, the Dock icon's menu already has Show / Hide action.
803-
trayIconMenu->addAction(toggleHideAction);
775+
show_hide_action = trayIconMenu->addAction(QString(), this, &BitcoinGUI::toggleHidden);
804776
trayIconMenu->addSeparator();
805-
#endif
777+
#endif // Q_OS_MAC
778+
779+
QAction* send_action{nullptr};
780+
QAction* receive_action{nullptr};
781+
QAction* sign_action{nullptr};
782+
QAction* verify_action{nullptr};
806783
if (enableWallet) {
807-
trayIconMenu->addAction(sendCoinsMenuAction);
808-
trayIconMenu->addAction(receiveCoinsMenuAction);
784+
send_action = trayIconMenu->addAction(sendCoinsAction->text(), sendCoinsAction, &QAction::trigger);
785+
receive_action = trayIconMenu->addAction(receiveCoinsAction->text(), receiveCoinsAction, &QAction::trigger);
809786
trayIconMenu->addSeparator();
810-
trayIconMenu->addAction(signMessageAction);
811-
trayIconMenu->addAction(verifyMessageAction);
787+
sign_action = trayIconMenu->addAction(signMessageAction->text(), signMessageAction, &QAction::trigger);
788+
verify_action = trayIconMenu->addAction(verifyMessageAction->text(), verifyMessageAction, &QAction::trigger);
812789
trayIconMenu->addSeparator();
813790
}
814-
trayIconMenu->addAction(optionsAction);
815-
trayIconMenu->addAction(openRPCConsoleAction);
816-
#ifndef Q_OS_MAC // This is built-in on macOS
791+
QAction* options_action = trayIconMenu->addAction(optionsAction->text(), optionsAction, &QAction::trigger);
792+
options_action->setMenuRole(QAction::PreferencesRole);
793+
QAction* node_window_action = trayIconMenu->addAction(openRPCConsoleAction->text(), openRPCConsoleAction, &QAction::trigger);
794+
QAction* quit_action{nullptr};
795+
#ifndef Q_OS_MAC
796+
// Note: On macOS, the Dock icon's menu already has Quit action.
817797
trayIconMenu->addSeparator();
818-
trayIconMenu->addAction(quitAction);
819-
#endif
820-
}
798+
quit_action = trayIconMenu->addAction(quitAction->text(), quitAction, &QAction::trigger);
821799

822-
#ifndef Q_OS_MAC
823-
void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
824-
{
825-
if(reason == QSystemTrayIcon::Trigger)
826-
{
827-
// Click on system tray icon triggers show/hide of the main window
828-
toggleHidden();
829-
}
830-
}
800+
trayIcon->setContextMenu(trayIconMenu.get());
801+
connect(trayIcon, &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) {
802+
if (reason == QSystemTrayIcon::Trigger) {
803+
// Click on system tray icon triggers show/hide of the main window
804+
toggleHidden();
805+
}
806+
});
831807
#else
832-
void BitcoinGUI::macosDockIconActivated()
833-
{
834-
show();
835-
activateWindow();
808+
// Note: On macOS, the Dock icon is used to provide the tray's functionality.
809+
MacDockIconHandler* dockIconHandler = MacDockIconHandler::instance();
810+
connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, [this] {
811+
show();
812+
activateWindow();
813+
});
814+
trayIconMenu->setAsDockMenu();
815+
#endif // Q_OS_MAC
816+
817+
connect(
818+
// Using QSystemTrayIcon::Context is not reliable.
819+
// See https://bugreports.qt.io/browse/QTBUG-91697
820+
trayIconMenu.get(), &QMenu::aboutToShow,
821+
[this, show_hide_action, send_action, receive_action, sign_action, verify_action, options_action, node_window_action, quit_action] {
822+
if (show_hide_action) show_hide_action->setText(
823+
(!isHidden() && !isMinimized() && !GUIUtil::isObscured(this)) ?
824+
tr("&Hide") :
825+
tr("S&how"));
826+
if (QApplication::activeModalWidget()) {
827+
for (QAction* a : trayIconMenu.get()->actions()) {
828+
a->setEnabled(false);
829+
}
830+
} else {
831+
if (show_hide_action) show_hide_action->setEnabled(true);
832+
if (enableWallet) {
833+
send_action->setEnabled(sendCoinsAction->isEnabled());
834+
receive_action->setEnabled(receiveCoinsAction->isEnabled());
835+
sign_action->setEnabled(signMessageAction->isEnabled());
836+
verify_action->setEnabled(verifyMessageAction->isEnabled());
837+
}
838+
options_action->setEnabled(optionsAction->isEnabled());
839+
node_window_action->setEnabled(openRPCConsoleAction->isEnabled());
840+
if (quit_action) quit_action->setEnabled(true);
841+
}
842+
});
836843
}
837-
#endif
838844

839845
void BitcoinGUI::optionsClicked()
840846
{
@@ -847,7 +853,7 @@ void BitcoinGUI::aboutClicked()
847853
return;
848854

849855
auto dlg = new HelpMessageDialog(this, /* about */ true);
850-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
856+
GUIUtil::ShowModalDialogAsynchronously(dlg);
851857
}
852858

853859
void BitcoinGUI::showDebugWindow()
@@ -992,7 +998,7 @@ void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab)
992998
connect(dlg, &OptionsDialog::quitOnReset, this, &BitcoinGUI::quitRequested);
993999
dlg->setCurrentTab(tab);
9941000
dlg->setModel(clientModel->getOptionsModel());
995-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
1001+
GUIUtil::ShowModalDialogAsynchronously(dlg);
9961002
}
9971003

9981004
void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state)

src/qt/bitcoingui.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ class BitcoinGUI : public QMainWindow
137137
QAction* historyAction = nullptr;
138138
QAction* quitAction = nullptr;
139139
QAction* sendCoinsAction = nullptr;
140-
QAction* sendCoinsMenuAction = nullptr;
141140
QAction* usedSendingAddressesAction = nullptr;
142141
QAction* usedReceivingAddressesAction = nullptr;
143142
QAction* signMessageAction = nullptr;
@@ -146,9 +145,7 @@ class BitcoinGUI : public QMainWindow
146145
QAction* m_load_psbt_clipboard_action = nullptr;
147146
QAction* aboutAction = nullptr;
148147
QAction* receiveCoinsAction = nullptr;
149-
QAction* receiveCoinsMenuAction = nullptr;
150148
QAction* optionsAction = nullptr;
151-
QAction* toggleHideAction = nullptr;
152149
QAction* encryptWalletAction = nullptr;
153150
QAction* backupWalletAction = nullptr;
154151
QAction* changePassphraseAction = nullptr;
@@ -302,13 +299,6 @@ public Q_SLOTS:
302299
void showDebugWindowActivateConsole();
303300
/** Show help message dialog */
304301
void showHelpMessageClicked();
305-
#ifndef Q_OS_MAC
306-
/** Handle tray icon clicked */
307-
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
308-
#else
309-
/** Handle macOS Dock icon clicked */
310-
void macosDockIconActivated();
311-
#endif
312302

313303
/** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */
314304
void showNormalIfMinimized() { showNormalIfMinimized(false); }

src/qt/guiutil.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ void PrintSlotException(
984984
PrintExceptionContinue(exception, description.c_str());
985985
}
986986

987-
void ShowModalDialogAndDeleteOnClose(QDialog* dialog)
987+
void ShowModalDialogAsynchronously(QDialog* dialog)
988988
{
989989
dialog->setAttribute(Qt::WA_DeleteOnClose);
990990
dialog->setWindowModality(Qt::ApplicationModal);

src/qt/guiutil.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ namespace GUIUtil
426426
/**
427427
* Shows a QDialog instance asynchronously, and deletes it on close.
428428
*/
429-
void ShowModalDialogAndDeleteOnClose(QDialog* dialog);
429+
void ShowModalDialogAsynchronously(QDialog* dialog);
430430

431431
inline bool IsEscapeOrBack(int key)
432432
{

src/qt/sendcoinsdialog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ void SendCoinsDialog::coinControlButtonClicked()
930930
{
931931
auto dlg = new CoinControlDialog(*m_coin_control, model, platformStyle);
932932
connect(dlg, &QDialog::finished, this, &SendCoinsDialog::coinControlUpdateLabels);
933-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
933+
GUIUtil::ShowModalDialogAsynchronously(dlg);
934934
}
935935

936936
// Coin Control: checkbox custom change address

src/qt/transactionview.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ void TransactionView::editLabel()
511511
: EditAddressDialog::EditSendingAddress, this);
512512
dlg->setModel(addressBook);
513513
dlg->loadRow(idx);
514-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
514+
GUIUtil::ShowModalDialogAsynchronously(dlg);
515515
}
516516
else
517517
{
@@ -520,7 +520,7 @@ void TransactionView::editLabel()
520520
this);
521521
dlg->setModel(addressBook);
522522
dlg->setAddress(address);
523-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
523+
GUIUtil::ShowModalDialogAsynchronously(dlg);
524524
}
525525
}
526526
}

src/qt/walletframe.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard)
226226

227227
auto dlg = new PSBTOperationsDialog(this, currentWalletModel(), clientModel);
228228
dlg->openWithPSBT(psbtx);
229-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
229+
GUIUtil::ShowModalDialogAsynchronously(dlg);
230230
}
231231

232232
void WalletFrame::encryptWallet()

src/qt/walletview.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ void WalletView::encryptWallet()
208208
auto dlg = new AskPassphraseDialog(AskPassphraseDialog::Encrypt, this);
209209
dlg->setModel(walletModel);
210210
connect(dlg, &QDialog::finished, this, &WalletView::encryptionStatusChanged);
211-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
211+
GUIUtil::ShowModalDialogAsynchronously(dlg);
212212
}
213213

214214
void WalletView::backupWallet()
@@ -235,16 +235,18 @@ void WalletView::changePassphrase()
235235
{
236236
auto dlg = new AskPassphraseDialog(AskPassphraseDialog::ChangePass, this);
237237
dlg->setModel(walletModel);
238-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
238+
GUIUtil::ShowModalDialogAsynchronously(dlg);
239239
}
240240

241241
void WalletView::unlockWallet()
242242
{
243243
// Unlock wallet when requested by wallet model
244244
if (walletModel->getEncryptionStatus() == WalletModel::Locked) {
245-
auto dlg = new AskPassphraseDialog(AskPassphraseDialog::Unlock, this);
246-
dlg->setModel(walletModel);
247-
GUIUtil::ShowModalDialogAndDeleteOnClose(dlg);
245+
AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
246+
dlg.setModel(walletModel);
247+
// A modal dialog must be synchronous here as expected
248+
// in the WalletModel::requestUnlock() function.
249+
dlg.exec();
248250
}
249251
}
250252

0 commit comments

Comments
 (0)