From 5659e73493fcdfb5d0cb9d686c24c4fbe1c217ed Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 14 Aug 2020 20:46:32 +0300 Subject: [PATCH 1/3] qt: Add ObjectInvoke template function This is a replacement of the QMetaObject::invokeMethod functor overload which is available in Qt 5.10+. Co-authored-by: Russell Yanofsky --- src/qt/guiutil.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index c976b4b4bb0..d7bd1248844 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 + void ObjectInvoke(QObject* object, Fn&& function, Qt::ConnectionType connection = Qt::QueuedConnection) + { + QObject source; + QObject::connect(&source, &QObject::destroyed, object, std::forward(function), connection); + } } // namespace GUIUtil From 5fcfee68af47d4a891ae9c9964d73886f0f01d7d Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 14 Aug 2020 20:53:35 +0300 Subject: [PATCH 2/3] qt: Call setParent() in the parent's context setParent(parent) calls sendEvent(parent, QChildEvent) that implies running in the thread which created the parent object. --- src/qt/walletcontroller.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index d9e0274d01b..a59f33b785f 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -131,7 +131,11 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptrmoveToThread(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 From 8963b2c71f120b2746396c4987392f0105c8dd60 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 11 May 2020 17:12:59 +0300 Subject: [PATCH 3/3] qt: Improve comments in WalletController::getOrCreateWallet() --- src/qt/walletcontroller.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index a59f33b785f..83f3cccbff0 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -128,8 +128,14 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptrmoveToThread(thread()); // setParent(parent) must be called in the thread which created the parent object. More details in #18948. GUIUtil::ObjectInvoke(this, [wallet_model, this] { @@ -161,7 +167,6 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr