From fe4a655042f7de31dce120aeed72345579f1b59f Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 5 May 2012 16:07:14 +0200 Subject: Fine-grained UI updates Gets rid of `MainFrameRepaint` in favor of specific update functions that tell the UI exactly what changed. This improves the efficiency of various handlers. Also fixes problems with mined transactions not showing up until restart. The following notifications were added: - `NotifyBlocksChanged`: Block chain changed - `NotifyKeyStoreStatusChanged`: Wallet status (encrypted, locked) changed. - `NotifyAddressBookChanged`: Address book entry changed. - `NotifyTransactionChanged`: Wallet transaction added, removed or updated. - `NotifyNumConnectionsChanged`: Number of connections changed. - `NotifyAlertChanged`: New, updated or cancelled alert. As this finally makes it possible for the UI to know when a new alert arrived, it can be shown as OS notification. These notifications could also be useful for RPC clients. However, currently, they are ignored in bitcoind (in noui.cpp). Also brings back polling with timer for numBlocks in ClientModel. This value updates so frequently during initial download that the number of signals clogs the UI thread and causes heavy CPU usage. And after initial block download, the value changes so rarely that a delay of half a second until the UI updates is unnoticable. --- src/qt/bitcoin.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 14 deletions(-) (limited to 'src/qt/bitcoin.cpp') diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 6a0a32fbd9..a50443021f 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -84,20 +84,6 @@ void ThreadSafeHandleURI(const std::string& strURI) Q_ARG(QString, QString::fromStdString(strURI))); } -void MainFrameRepaint() -{ - if(clientmodel) - QMetaObject::invokeMethod(clientmodel, "update", Qt::QueuedConnection); - if(walletmodel) - QMetaObject::invokeMethod(walletmodel, "update", Qt::QueuedConnection); -} - -void AddressBookRepaint() -{ - if(walletmodel) - QMetaObject::invokeMethod(walletmodel, "updateAddressList", Qt::QueuedConnection); -} - void InitMessage(const std::string &message) { if(splashref) @@ -120,6 +106,61 @@ std::string _(const char* psz) return QCoreApplication::translate("bitcoin-core", psz).toStdString(); } +void NotifyBlocksChanged() +{ + // This notification is too frequent. Don't trigger a signal. + // Don't remove it, though, as it might be useful later. +} + +void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet) +{ + // This currently ignores the wallet argument. When multiple wallet support is implemented, this + // parameter should be mapped to a specific WalletModel for that wallet. + OutputDebugStringF("NotifyKeyStoreStatusChanged\n"); + if(walletmodel) + QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection); +} + +void NotifyAddressBookChanged(CWallet *wallet, const std::string &address, const std::string &label, ChangeType status) +{ + // This currently ignores the wallet argument. When multiple wallet support is implemented, this + // parameter should be mapped to a specific WalletModel for that wallet. + OutputDebugStringF("NotifyAddressBookChanged %s %s status=%i\n", address.c_str(), label.c_str(), status); + if(walletmodel) + QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(address)), + Q_ARG(QString, QString::fromStdString(label)), + Q_ARG(int, status)); +} + +void NotifyTransactionChanged(CWallet *wallet, const uint256 &hash, ChangeType status) +{ + // This currently ignores the wallet argument. When multiple wallet support is implemented, this + // parameter should be mapped to a specific WalletModel for that wallet. + OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status); + if(walletmodel) + QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(hash.GetHex())), + Q_ARG(int, status)); +} + +void NotifyNumConnectionsChanged(int newNumConnections) +{ + // Too noisy: OutputDebugStringF("NotifyNumConnectionsChanged %i\n", newNumConnections); + if(clientmodel) + QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection, + Q_ARG(int, newNumConnections)); +} + +void NotifyAlertChanged(const uint256 &hash, ChangeType status) +{ + OutputDebugStringF("NotifyAlertChanged %s status=%i\n", hash.GetHex().c_str(), status); + if(clientmodel) + QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(hash.GetHex())), + Q_ARG(int, status)); +} + /* Handle runaway exceptions. Shows a message box with the problem and quits the program. */ static void handleRunawayException(std::exception *e) -- cgit v1.2.3 From ab1b288fa7994db5f036e93d5f8ba73372017c40 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 6 May 2012 19:40:58 +0200 Subject: Convert UI interface to boost::signals2. - Signals now go directly from the core to WalletModel/ClientModel. - WalletModel subscribes to signals on CWallet: Prepares for multi-wallet support, by no longer assuming an implicit global wallet. - Gets rid of noui.cpp, the few lines that were left are merged into init.cpp - Rename wxXXX message flags to MF_XXX, to make them UI indifferent. - ThreadSafeMessageBox no longer returns the value `4` which was never used, converted to void. --- src/qt/bitcoin.cpp | 84 ++++++++++-------------------------------------------- 1 file changed, 15 insertions(+), 69 deletions(-) (limited to 'src/qt/bitcoin.cpp') diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index a50443021f..c5592b28df 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -36,15 +36,13 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets) // Need a global reference for the notifications to find the GUI static BitcoinGUI *guiref; static QSplashScreen *splashref; -static WalletModel *walletmodel; -static ClientModel *clientmodel; -int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) { // Message from network thread if(guiref) { - bool modal = (style & wxMODAL); + bool modal = (style & MF_MODAL); // in case of modal message, use blocking connection to wait for user to click OK QMetaObject::invokeMethod(guiref, "error", modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, @@ -57,10 +55,9 @@ int ThreadSafeMessageBox(const std::string& message, const std::string& caption, printf("%s: %s\n", caption.c_str(), message.c_str()); fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); } - return 4; } -bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) { if(!guiref) return false; @@ -75,7 +72,7 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) return payFee; } -void ThreadSafeHandleURI(const std::string& strURI) +static void ThreadSafeHandleURI(const std::string& strURI) { if(!guiref) return; @@ -84,7 +81,7 @@ void ThreadSafeHandleURI(const std::string& strURI) Q_ARG(QString, QString::fromStdString(strURI))); } -void InitMessage(const std::string &message) +static void InitMessage(const std::string &message) { if(splashref) { @@ -93,7 +90,7 @@ void InitMessage(const std::string &message) } } -void QueueShutdown() +static void QueueShutdown() { QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); } @@ -101,66 +98,11 @@ void QueueShutdown() /* Translate string to current locale using Qt. */ -std::string _(const char* psz) +static std::string Translate(const char* psz) { return QCoreApplication::translate("bitcoin-core", psz).toStdString(); } -void NotifyBlocksChanged() -{ - // This notification is too frequent. Don't trigger a signal. - // Don't remove it, though, as it might be useful later. -} - -void NotifyKeyStoreStatusChanged(CBasicKeyStore *wallet) -{ - // This currently ignores the wallet argument. When multiple wallet support is implemented, this - // parameter should be mapped to a specific WalletModel for that wallet. - OutputDebugStringF("NotifyKeyStoreStatusChanged\n"); - if(walletmodel) - QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection); -} - -void NotifyAddressBookChanged(CWallet *wallet, const std::string &address, const std::string &label, ChangeType status) -{ - // This currently ignores the wallet argument. When multiple wallet support is implemented, this - // parameter should be mapped to a specific WalletModel for that wallet. - OutputDebugStringF("NotifyAddressBookChanged %s %s status=%i\n", address.c_str(), label.c_str(), status); - if(walletmodel) - QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(address)), - Q_ARG(QString, QString::fromStdString(label)), - Q_ARG(int, status)); -} - -void NotifyTransactionChanged(CWallet *wallet, const uint256 &hash, ChangeType status) -{ - // This currently ignores the wallet argument. When multiple wallet support is implemented, this - // parameter should be mapped to a specific WalletModel for that wallet. - OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status); - if(walletmodel) - QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(hash.GetHex())), - Q_ARG(int, status)); -} - -void NotifyNumConnectionsChanged(int newNumConnections) -{ - // Too noisy: OutputDebugStringF("NotifyNumConnectionsChanged %i\n", newNumConnections); - if(clientmodel) - QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection, - Q_ARG(int, newNumConnections)); -} - -void NotifyAlertChanged(const uint256 &hash, ChangeType status) -{ - OutputDebugStringF("NotifyAlertChanged %s status=%i\n", hash.GetHex().c_str(), status); - if(clientmodel) - QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, - Q_ARG(QString, QString::fromStdString(hash.GetHex())), - Q_ARG(int, status)); -} - /* Handle runaway exceptions. Shows a message box with the problem and quits the program. */ static void handleRunawayException(std::exception *e) @@ -307,6 +249,14 @@ int main(int argc, char *argv[]) if (translator.load(lang_territory, ":/translations/")) app.installTranslator(&translator); + // Subscribe to global signals from core + uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox); + uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee); + uiInterface.ThreadSafeHandleURI.connect(ThreadSafeHandleURI); + uiInterface.InitMessage.connect(InitMessage); + uiInterface.QueueShutdown.connect(QueueShutdown); + uiInterface.Translate.connect(Translate); + // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. if (mapArgs.count("-?") || mapArgs.count("--help")) @@ -348,9 +298,7 @@ int main(int argc, char *argv[]) splash.finish(&window); ClientModel clientModel(&optionsModel); - clientmodel = &clientModel; WalletModel walletModel(pwalletMain, &optionsModel); - walletmodel = &walletModel; window.setClientModel(&clientModel); window.setWalletModel(&walletModel); @@ -392,8 +340,6 @@ int main(int argc, char *argv[]) window.setClientModel(0); window.setWalletModel(0); guiref = 0; - clientmodel = 0; - walletmodel = 0; } Shutdown(NULL); } -- cgit v1.2.3 From 239c11d0dd4287e74286c40fb338aea85f4b1996 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 19 May 2012 09:35:26 +0200 Subject: Make testcases build, prevent windows symbol collision --- src/qt/bitcoin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qt/bitcoin.cpp') diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index c5592b28df..07bdee0886 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -42,7 +42,7 @@ static void ThreadSafeMessageBox(const std::string& message, const std::string& // Message from network thread if(guiref) { - bool modal = (style & MF_MODAL); + bool modal = (style & CClientUIInterface::MODAL); // in case of modal message, use blocking connection to wait for user to click OK QMetaObject::invokeMethod(guiref, "error", modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, -- cgit v1.2.3