diff options
Diffstat (limited to 'src/qt')
-rw-r--r-- | src/qt/guiutil.h | 12 | ||||
-rw-r--r-- | src/qt/walletcontroller.cpp | 17 |
2 files changed, 25 insertions, 4 deletions
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index c976b4b4bb..d7bd124884 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -340,6 +340,18 @@ namespace GUIUtil #endif } + /** + * Queue a function to run in an object's event loop. This can be + * replaced by a call to the QMetaObject::invokeMethod functor overload after Qt 5.10, but + * for now use a QObject::connect for compatibility with older Qt versions, based on + * https://stackoverflow.com/questions/21646467/how-to-execute-a-functor-or-a-lambda-in-a-given-thread-in-qt-gcd-style + */ + template <typename Fn> + void ObjectInvoke(QObject* object, Fn&& function, Qt::ConnectionType connection = Qt::QueuedConnection) + { + QObject source; + QObject::connect(&source, &QObject::destroyed, object, std::forward<Fn>(function), connection); + } } // namespace GUIUtil diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index d9e0274d01..83f3cccbff 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -128,10 +128,20 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal } // Instantiate model and register it. - WalletModel* wallet_model = new WalletModel(std::move(wallet), m_client_model, m_platform_style, nullptr); - // Handler callback runs in a different thread so fix wallet model thread affinity. + WalletModel* wallet_model = new WalletModel(std::move(wallet), m_client_model, m_platform_style, + nullptr /* required for the following moveToThread() call */); + + // Move WalletModel object to the thread that created the WalletController + // object (GUI main thread), instead of the current thread, which could be + // an outside wallet thread or RPC thread sending a LoadWallet notification. + // This ensures queued signals sent to the WalletModel object will be + // handled on the GUI event loop. wallet_model->moveToThread(thread()); - wallet_model->setParent(this); + // setParent(parent) must be called in the thread which created the parent object. More details in #18948. + GUIUtil::ObjectInvoke(this, [wallet_model, this] { + wallet_model->setParent(this); + }, GUIUtil::blockingGUIThreadConnection()); + m_wallets.push_back(wallet_model); // WalletModel::startPollBalance needs to be called in a thread managed by @@ -157,7 +167,6 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal // Re-emit coinsSent signal from wallet model. connect(wallet_model, &WalletModel::coinsSent, this, &WalletController::coinsSent); - // Notify walletAdded signal on the GUI thread. Q_EMIT walletAdded(wallet_model); return wallet_model; |