From 55f69a47002a1fc5bdf4e0c345e61ec955fa664b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 24 Mar 2012 16:52:43 +0100 Subject: [PATCH 01/10] move QT_PLUGINS stuff to qt main file, where it belongs --- src/init.cpp | 11 ----------- src/qt/bitcoin.cpp | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 8531b2071..d04c7a2db 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -13,17 +13,6 @@ #include #include -#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) -#define _BITCOIN_QT_PLUGINS_INCLUDED -#define __INSURE__ -#include -Q_IMPORT_PLUGIN(qcncodecs) -Q_IMPORT_PLUGIN(qjpcodecs) -Q_IMPORT_PLUGIN(qtwcodecs) -Q_IMPORT_PLUGIN(qkrcodecs) -Q_IMPORT_PLUGIN(qtaccessiblewidgets) -#endif - #ifdef WIN32 #define strncasecmp strnicmp #endif diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 6ee7fed5c..738464668 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -21,6 +21,17 @@ #include +#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) +#define _BITCOIN_QT_PLUGINS_INCLUDED +#define __INSURE__ +#include +Q_IMPORT_PLUGIN(qcncodecs) +Q_IMPORT_PLUGIN(qjpcodecs) +Q_IMPORT_PLUGIN(qtwcodecs) +Q_IMPORT_PLUGIN(qkrcodecs) +Q_IMPORT_PLUGIN(qtaccessiblewidgets) +#endif + // Need a global reference for the notifications to find the GUI BitcoinGUI *guiref; QSplashScreen *splashref; From 7e7bcce2d992c6fd53fdc4d9eb40f21c951d5347 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 24 Mar 2012 17:07:29 +0100 Subject: [PATCH 02/10] Code deduplication: make function in GUIUtil to get connection type to call object slot in GUI thread with invokeMethod. --- src/qt/bitcoin.cpp | 21 +++------------------ src/qt/guiutil.cpp | 12 ++++++++++++ src/qt/guiutil.h | 8 ++++++++ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 738464668..0f7c96e6a 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -5,6 +5,7 @@ #include "clientmodel.h" #include "walletmodel.h" #include "optionsmodel.h" +#include "guiutil.h" #include "headers.h" #include "init.h" @@ -12,7 +13,6 @@ #include #include -#include #include #include #include @@ -70,15 +70,7 @@ bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindo return true; bool payFee = false; - // Call slot on GUI thread. - // If called from another thread, use a blocking QueuedConnection. - Qt::ConnectionType connectionType = Qt::DirectConnection; - if(QThread::currentThread() != QCoreApplication::instance()->thread()) - { - connectionType = Qt::BlockingQueuedConnection; - } - - QMetaObject::invokeMethod(guiref, "askFee", connectionType, + QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(), Q_ARG(qint64, nFeeRequired), Q_ARG(bool*, &payFee)); @@ -90,14 +82,7 @@ void ThreadSafeHandleURL(const std::string& strURL) if(!guiref) return; - // Call slot on GUI thread. - // If called from another thread, use a blocking QueuedConnection. - Qt::ConnectionType connectionType = Qt::DirectConnection; - if(QThread::currentThread() != QCoreApplication::instance()->thread()) - { - connectionType = Qt::BlockingQueuedConnection; - } - QMetaObject::invokeMethod(guiref, "handleURL", connectionType, + QMetaObject::invokeMethod(guiref, "handleURL", GUIUtil::blockingGUIThreadConnection(), Q_ARG(QString, QString::fromStdString(strURL))); } diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index ac69bd07e..ad530a78e 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -17,6 +17,7 @@ #include #include #include +#include QString GUIUtil::dateTimeStr(qint64 nTime) { @@ -184,3 +185,14 @@ QString GUIUtil::getSaveFileName(QWidget *parent, const QString &caption, return result; } +Qt::ConnectionType GUIUtil::blockingGUIThreadConnection() +{ + if(QThread::currentThread() != QCoreApplication::instance()->thread()) + { + return Qt::BlockingQueuedConnection; + } + else + { + return Qt::DirectConnection; + } +} diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 75ba53f20..06426d76b 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -60,6 +60,14 @@ public: const QString &dir=QString(), const QString &filter=QString(), QString *selectedSuffixOut=0); + + /** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking. + + @returns If called from the GUI thread, return a Qt::DirectConnection. + If called from another thread, return a Qt::BlockingQueuedConnection. + */ + static Qt::ConnectionType blockingGUIThreadConnection(); + }; #endif // GUIUTIL_H From 98e61758744ed34e8b7f59b37edb6d09b33d5517 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 24 Mar 2012 18:48:18 +0100 Subject: [PATCH 03/10] Update UI through async calls MainFrameRepaint and AddressBookRepaint instead of a timer. - Overall, this is better design - This fixes problems with the address book UI not updating when the address book is changed through RPC - Move Statusbar change detection responsibility to ClientModel --- src/noui.h | 4 ++++ src/qt/addressbookpage.cpp | 2 -- src/qt/addresstablemodel.cpp | 11 ++--------- src/qt/addresstablemodel.h | 6 ++---- src/qt/bitcoin.cpp | 22 ++++++++++++++++++---- src/qt/bitcoingui.cpp | 13 ------------- src/qt/bitcoingui.h | 2 -- src/qt/clientmodel.cpp | 18 ++++++++++-------- src/qt/clientmodel.h | 1 + src/qt/walletmodel.cpp | 15 +++++---------- src/qt/walletmodel.h | 3 +-- src/qtui.h | 1 + src/wallet.cpp | 2 ++ 13 files changed, 46 insertions(+), 54 deletions(-) diff --git a/src/noui.h b/src/noui.h index 458fc647a..e4faa2ed0 100644 --- a/src/noui.h +++ b/src/noui.h @@ -67,6 +67,10 @@ inline void MainFrameRepaint() { } +inline void AddressBookRepaint() +{ +} + inline void InitMessage(const std::string &message) { } diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index cb185beae..88212835d 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -94,8 +94,6 @@ void AddressBookPage::setModel(AddressTableModel *model) this->model = model; if(!model) return; - // Refresh list from core - model->updateList(); proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(model); diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 8fd6d52b7..198a857b2 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -231,7 +231,7 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & pa } } -void AddressTableModel::updateList() +void AddressTableModel::update() { // Update address book model from Bitcoin core beginResetModel(); @@ -285,10 +285,9 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con { return QString(); } - // Add entry and update list + // Add entry CRITICAL_BLOCK(wallet->cs_wallet) wallet->SetAddressBookName(strAddress, strLabel); - updateList(); return QString::fromStdString(strAddress); } @@ -306,15 +305,9 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex & paren { wallet->DelAddressBookName(rec->address.toStdString()); } - updateList(); return true; } -void AddressTableModel::update() -{ - -} - /* Look up label for address in address book, if not found return empty string. */ QString AddressTableModel::labelForAddress(const QString &address) const diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 074330013..7fd07cfb8 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -56,10 +56,6 @@ public: */ QString addRow(const QString &type, const QString &label, const QString &address); - /* Update address list from core. Invalidates any indices. - */ - void updateList(); - /* Look up label for address in address book, if not found return empty string. */ QString labelForAddress(const QString &address) const; @@ -82,6 +78,8 @@ signals: void defaultAddressChanged(const QString &address); public slots: + /* Update address list from core. Invalidates any indices. + */ void update(); }; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 0f7c96e6a..f330feedb 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -33,8 +33,10 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets) #endif // Need a global reference for the notifications to find the GUI -BitcoinGUI *guiref; -QSplashScreen *splashref; +static BitcoinGUI *guiref; +static QSplashScreen *splashref; +static WalletModel *walletmodel; +static ClientModel *clientmodel; int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y) { @@ -98,8 +100,16 @@ void UIThreadCall(boost::function0 fn) void MainFrameRepaint() { - if(guiref) - QMetaObject::invokeMethod(guiref, "refreshStatusBar", Qt::QueuedConnection); + 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) @@ -230,7 +240,9 @@ int main(int argc, char *argv[]) splash.finish(&window); ClientModel clientModel(&optionsModel); + clientmodel = &clientModel; WalletModel walletModel(pwalletMain, &optionsModel); + walletmodel = &walletModel; guiref = &window; window.setClientModel(&clientModel); @@ -270,6 +282,8 @@ int main(int argc, char *argv[]) app.exec(); guiref = 0; + clientmodel = 0; + walletmodel = 0; } Shutdown(NULL); } diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index cf4e43c5d..f2d131851 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -538,19 +538,6 @@ void BitcoinGUI::setNumBlocks(int count) progressBar->setToolTip(tooltip); } -void BitcoinGUI::refreshStatusBar() -{ - /* Might display multiple times in the case of multiple alerts - static QString prevStatusBar; - QString newStatusBar = clientModel->getStatusBarWarnings(); - if (prevStatusBar != newStatusBar) - { - prevStatusBar = newStatusBar; - error(tr("Network Alert"), newStatusBar); - }*/ - setNumBlocks(clientModel->getNumBlocks()); -} - void BitcoinGUI::error(const QString &title, const QString &message) { // Report errors from network/worker thread diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index dbc32640b..2130babcb 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -113,8 +113,6 @@ public slots: @see WalletModel::EncryptionStatus */ void setEncryptionStatus(int status); - /** Set the status bar text if there are any warnings (removes sync progress bar if applicable) */ - void refreshStatusBar(); /** Notify the user of an error in the network or transaction handling code. */ void error(const QString &title, const QString &message); diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 5a0b4aa83..8163da091 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -6,19 +6,12 @@ #include "headers.h" -#include #include ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : QObject(parent), optionsModel(optionsModel), cachedNumConnections(0), cachedNumBlocks(0) { - // Until signal notifications is built into the bitcoin core, - // simply update everything after polling using a timer. - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(update())); - timer->start(MODEL_UPDATE_DELAY); - numBlocksAtStartup = -1; } @@ -47,14 +40,23 @@ void ClientModel::update() { int newNumConnections = getNumConnections(); int newNumBlocks = getNumBlocks(); + QString newStatusBar = getStatusBarWarnings(); if(cachedNumConnections != newNumConnections) emit numConnectionsChanged(newNumConnections); - if(cachedNumBlocks != newNumBlocks) + if(cachedNumBlocks != newNumBlocks || cachedStatusBar != newStatusBar) + { + // Simply emit a numBlocksChanged for now in case the status message changes, + // so that the view updates the status bar. + // TODO: It should send a notification. + // (However, this might generate looped notifications and needs to be thought through and tested carefully) + // error(tr("Network Alert"), newStatusBar); emit numBlocksChanged(newNumBlocks); + } cachedNumConnections = newNumConnections; cachedNumBlocks = newNumBlocks; + cachedStatusBar = newStatusBar; } bool ClientModel::isTestNet() const diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 5a12c4fcd..3dfbcecc0 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -43,6 +43,7 @@ private: int cachedNumConnections; int cachedNumBlocks; + QString cachedStatusBar; int numBlocksAtStartup; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 8344a653d..084185492 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -7,7 +7,6 @@ #include "headers.h" #include "db.h" // for BackupWallet -#include #include WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : @@ -16,12 +15,6 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p cachedBalance(0), cachedUnconfirmedBalance(0), cachedNumTransactions(0), cachedEncryptionStatus(Unencrypted) { - // Until signal notifications is built into the bitcoin core, - // simply update everything after polling using a timer. - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(update())); - timer->start(MODEL_UPDATE_DELAY); - addressTableModel = new AddressTableModel(wallet, this); transactionTableModel = new TransactionTableModel(wallet, this); } @@ -69,6 +62,11 @@ void WalletModel::update() addressTableModel->update(); } +void WalletModel::updateAddressList() +{ + addressTableModel->update(); +} + bool WalletModel::validateAddress(const QString &address) { CBitcoinAddress addressParsed(address.toStdString()); @@ -164,9 +162,6 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QListupdateList(); - return SendCoinsReturn(OK, 0, hex); } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index e89484249..6a85abd6d 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -138,9 +138,8 @@ signals: void error(const QString &title, const QString &message); public slots: - -private slots: void update(); + void updateAddressList(); }; diff --git a/src/qtui.h b/src/qtui.h index 9791ba544..70952da70 100644 --- a/src/qtui.h +++ b/src/qtui.h @@ -44,6 +44,7 @@ extern void ThreadSafeHandleURL(const std::string& strURL); extern void CalledSetStatusBar(const std::string& strText, int nField); extern void UIThreadCall(boost::function0 fn); extern void MainFrameRepaint(); +extern void AddressBookRepaint(); extern void InitMessage(const std::string &message); extern std::string _(const char* psz); diff --git a/src/wallet.cpp b/src/wallet.cpp index 27ed7228d..3bdb4bb56 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1279,6 +1279,7 @@ int CWallet::LoadWallet(bool& fFirstRunRet) bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName) { mapAddressBook[address] = strName; + AddressBookRepaint(); if (!fFileBacked) return false; return CWalletDB(strWalletFile).WriteName(address.ToString(), strName); @@ -1287,6 +1288,7 @@ bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& s bool CWallet::DelAddressBookName(const CBitcoinAddress& address) { mapAddressBook.erase(address); + AddressBookRepaint(); if (!fFileBacked) return false; return CWalletDB(strWalletFile).EraseName(address.ToString()); From f0b5e9e116a1eb8b19b3676e7f8b125e912a78f3 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 24 Mar 2012 19:11:39 +0100 Subject: [PATCH 04/10] remove unused CalledSetStatusBar and UIThreadCall notifications --- src/main.cpp | 3 --- src/noui.h | 9 --------- src/qt/bitcoin.cpp | 10 ---------- src/qtui.h | 3 --- 4 files changed, 25 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ca75b9fdb..ca589e54f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3450,8 +3450,6 @@ void static BitcoinMiner(CWallet *pwallet) dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); nHPSTimerStart = GetTimeMillis(); nHashCounter = 0; - string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0); - UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0)); static int64 nLogTime; if (GetTime() - nLogTime > 30 * 60) { @@ -3508,7 +3506,6 @@ void static ThreadBitcoinMiner(void* parg) vnThreadsRunning[THREAD_MINER]--; PrintException(NULL, "ThreadBitcoinMiner()"); } - UIThreadCall(boost::bind(CalledSetStatusBar, "", 0)); nHPSTimerStart = 0; if (vnThreadsRunning[THREAD_MINER] == 0) dHashesPerSec = 0; diff --git a/src/noui.h b/src/noui.h index e4faa2ed0..e91cca3cf 100644 --- a/src/noui.h +++ b/src/noui.h @@ -6,7 +6,6 @@ #define BITCOIN_NOUI_H #include -#include #include "wallet.h" typedef void wxWindow; @@ -55,14 +54,6 @@ inline bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, return true; } -inline void CalledSetStatusBar(const std::string& strText, int nField) -{ -} - -inline void UIThreadCall(boost::function0 fn) -{ -} - inline void MainFrameRepaint() { } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index f330feedb..e91855bec 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -88,16 +88,6 @@ void ThreadSafeHandleURL(const std::string& strURL) Q_ARG(QString, QString::fromStdString(strURL))); } -void CalledSetStatusBar(const std::string& strText, int nField) -{ - // Only used for built-in mining, which is disabled, simple ignore -} - -void UIThreadCall(boost::function0 fn) -{ - // Only used for built-in mining, which is disabled, simple ignore -} - void MainFrameRepaint() { if(clientmodel) diff --git a/src/qtui.h b/src/qtui.h index 70952da70..662b231cd 100644 --- a/src/qtui.h +++ b/src/qtui.h @@ -5,7 +5,6 @@ #define BITCOIN_EXTERNUI_H #include -#include #include "wallet.h" typedef void wxWindow; @@ -41,8 +40,6 @@ extern int MyMessageBox(const std::string& message, const std::string& caption=" extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1); extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent); extern void ThreadSafeHandleURL(const std::string& strURL); -extern void CalledSetStatusBar(const std::string& strText, int nField); -extern void UIThreadCall(boost::function0 fn); extern void MainFrameRepaint(); extern void AddressBookRepaint(); extern void InitMessage(const std::string &message); From 6cb6d623479c5dd42d91de7a4d391078d0800e54 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 24 Mar 2012 20:07:01 +0100 Subject: [PATCH 05/10] remove dependency on serialize.h and util.h for SecureString --- bitcoin-qt.pro | 3 +- src/allocators.h | 119 +++++++++++++++++++++++++++++++++++++++++++ src/crypter.h | 2 +- src/qt/walletmodel.h | 2 +- src/serialize.h | 106 +------------------------------------- src/util.h | 10 ---- 6 files changed, 125 insertions(+), 117 deletions(-) create mode 100644 src/allocators.h diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index d9206b3bf..a2bf4010e 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -155,7 +155,8 @@ HEADERS += src/qt/bitcoingui.h \ src/qt/askpassphrasedialog.h \ src/protocol.h \ src/qt/notificator.h \ - src/qt/qtipcserver.h + src/qt/qtipcserver.h \ + src/allocators.h SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/qt/transactiontablemodel.cpp \ diff --git a/src/allocators.h b/src/allocators.h new file mode 100644 index 000000000..85d9cfbbb --- /dev/null +++ b/src/allocators.h @@ -0,0 +1,119 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_ALLOCATORS_H +#define BITCOIN_ALLOCATORS_H + +#include + +#ifdef WIN32 +#define _WIN32_WINNT 0x0501 +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +// This is used to attempt to keep keying material out of swap +// Note that VirtualLock does not provide this as a guarantee on Windows, +// but, in practice, memory that has been VirtualLock'd almost never gets written to +// the pagefile except in rare circumstances where memory is extremely low. +#define mlock(p, n) VirtualLock((p), (n)); +#define munlock(p, n) VirtualUnlock((p), (n)); +#else +#include +#include +/* This comes from limits.h if it's not defined there set a sane default */ +#ifndef PAGESIZE +#include +#define PAGESIZE sysconf(_SC_PAGESIZE) +#endif +#define mlock(a,b) \ + mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ + (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) +#define munlock(a,b) \ + munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ + (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) +#endif + +// +// Allocator that locks its contents from being paged +// out of memory and clears its contents before deletion. +// +template +struct secure_allocator : public std::allocator +{ + // MSVC8 default copy constructor is broken + typedef std::allocator base; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + secure_allocator() throw() {} + secure_allocator(const secure_allocator& a) throw() : base(a) {} + template + secure_allocator(const secure_allocator& a) throw() : base(a) {} + ~secure_allocator() throw() {} + template struct rebind + { typedef secure_allocator<_Other> other; }; + + T* allocate(std::size_t n, const void *hint = 0) + { + T *p; + p = std::allocator::allocate(n, hint); + if (p != NULL) + mlock(p, sizeof(T) * n); + return p; + } + + void deallocate(T* p, std::size_t n) + { + if (p != NULL) + { + memset(p, 0, sizeof(T) * n); + munlock(p, sizeof(T) * n); + } + std::allocator::deallocate(p, n); + } +}; + + +// +// Allocator that clears its contents before deletion. +// +template +struct zero_after_free_allocator : public std::allocator +{ + // MSVC8 default copy constructor is broken + typedef std::allocator base; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + zero_after_free_allocator() throw() {} + zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {} + template + zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {} + ~zero_after_free_allocator() throw() {} + template struct rebind + { typedef zero_after_free_allocator<_Other> other; }; + + void deallocate(T* p, std::size_t n) + { + if (p != NULL) + memset(p, 0, sizeof(T) * n); + std::allocator::deallocate(p, n); + } +}; + +// This is exactly like std::string, but with a custom allocator. +// (secure_allocator<> is defined in serialize.h) +typedef std::basic_string, secure_allocator > SecureString; + +#endif diff --git a/src/crypter.h b/src/crypter.h index 0f9ea0217..59a005a22 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -4,7 +4,7 @@ #ifndef __CRYPTER_H__ #define __CRYPTER_H__ -#include "util.h" /* for SecureString */ +#include "allocators.h" /* for SecureString */ #include "key.h" const unsigned int WALLET_CRYPTO_KEY_SIZE = 32; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 6a85abd6d..6c62b5b4a 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -3,7 +3,7 @@ #include -#include "util.h" +#include "allocators.h" /* for SecureString */ class OptionsModel; class AddressTableModel; diff --git a/src/serialize.h b/src/serialize.h index 227bfb927..2d4aaba6a 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -19,38 +19,11 @@ #include #include +#include "allocators.h" + typedef long long int64; typedef unsigned long long uint64; -#ifdef WIN32 -#define _WIN32_WINNT 0x0501 -#define WIN32_LEAN_AND_MEAN 1 -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -// This is used to attempt to keep keying material out of swap -// Note that VirtualLock does not provide this as a guarantee on Windows, -// but, in practice, memory that has been VirtualLock'd almost never gets written to -// the pagefile except in rare circumstances where memory is extremely low. -#define mlock(p, n) VirtualLock((p), (n)); -#define munlock(p, n) VirtualUnlock((p), (n)); -#else -#include -#include -/* This comes from limits.h if it's not defined there set a sane default */ -#ifndef PAGESIZE -#include -#define PAGESIZE sysconf(_SC_PAGESIZE) -#endif -#define mlock(a,b) \ - mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ - (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) -#define munlock(a,b) \ - munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\ - (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1)))) -#endif - class CScript; class CDataStream; class CAutoFile; @@ -779,81 +752,6 @@ struct ser_streamplaceholder -// -// Allocator that locks its contents from being paged -// out of memory and clears its contents before deletion. -// -template -struct secure_allocator : public std::allocator -{ - // MSVC8 default copy constructor is broken - typedef std::allocator base; - typedef typename base::size_type size_type; - typedef typename base::difference_type difference_type; - typedef typename base::pointer pointer; - typedef typename base::const_pointer const_pointer; - typedef typename base::reference reference; - typedef typename base::const_reference const_reference; - typedef typename base::value_type value_type; - secure_allocator() throw() {} - secure_allocator(const secure_allocator& a) throw() : base(a) {} - template - secure_allocator(const secure_allocator& a) throw() : base(a) {} - ~secure_allocator() throw() {} - template struct rebind - { typedef secure_allocator<_Other> other; }; - - T* allocate(std::size_t n, const void *hint = 0) - { - T *p; - p = std::allocator::allocate(n, hint); - if (p != NULL) - mlock(p, sizeof(T) * n); - return p; - } - - void deallocate(T* p, std::size_t n) - { - if (p != NULL) - { - memset(p, 0, sizeof(T) * n); - munlock(p, sizeof(T) * n); - } - std::allocator::deallocate(p, n); - } -}; - - -// -// Allocator that clears its contents before deletion. -// -template -struct zero_after_free_allocator : public std::allocator -{ - // MSVC8 default copy constructor is broken - typedef std::allocator base; - typedef typename base::size_type size_type; - typedef typename base::difference_type difference_type; - typedef typename base::pointer pointer; - typedef typename base::const_pointer const_pointer; - typedef typename base::reference reference; - typedef typename base::const_reference const_reference; - typedef typename base::value_type value_type; - zero_after_free_allocator() throw() {} - zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {} - template - zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {} - ~zero_after_free_allocator() throw() {} - template struct rebind - { typedef zero_after_free_allocator<_Other> other; }; - - void deallocate(T* p, std::size_t n) - { - if (p != NULL) - memset(p, 0, sizeof(T) * n); - std::allocator::deallocate(p, n); - } -}; diff --git a/src/util.h b/src/util.h index 0af5b0a2c..0b73549dc 100644 --- a/src/util.h +++ b/src/util.h @@ -267,16 +267,6 @@ public: - - -// This is exactly like std::string, but with a custom allocator. -// (secure_allocator<> is defined in serialize.h) -typedef std::basic_string, secure_allocator > SecureString; - - - - - inline std::string i64tostr(int64 n) { return strprintf("%"PRI64d, n); From 5d7cebdadc991a23195a3519c1e9c038cb4f2290 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 24 Mar 2012 21:13:48 +0100 Subject: [PATCH 06/10] move translation function _ to qtui.h/noui.h instead of util.h --- src/noui.h | 5 +++++ src/util.h | 7 ------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/noui.h b/src/noui.h index e91cca3cf..4010ec3c7 100644 --- a/src/noui.h +++ b/src/noui.h @@ -66,4 +66,9 @@ inline void InitMessage(const std::string &message) { } +inline const char* _(const char* psz) +{ + return psz; +} + #endif diff --git a/src/util.h b/src/util.h index 0b73549dc..e4cf83f43 100644 --- a/src/util.h +++ b/src/util.h @@ -95,13 +95,6 @@ inline void Sleep(int64 n) } #endif -#if !defined(QT_GUI) -inline const char* _(const char* psz) -{ - return psz; -} -#endif - From 1a3f0da9229a8e524d1010cdc8bd3b9da71fe529 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 25 Mar 2012 20:17:59 +0200 Subject: [PATCH 07/10] support RPC stop and encryptwallet with UI --- src/bitcoinrpc.cpp | 17 +++-------------- src/main.cpp | 2 +- src/noui.h | 7 +++++++ src/qt/bitcoin.cpp | 5 +++++ src/qtui.h | 1 + 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 868419eaa..e511505c1 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -221,13 +221,9 @@ Value stop(const Array& params, bool fHelp) throw runtime_error( "stop\n" "Stop bitcoin server."); -#ifndef QT_GUI // Shutdown will take long enough that the response should get back - CreateThread(Shutdown, NULL); + QueueShutdown(); return "bitcoin server stopping"; -#else - throw runtime_error("NYI: cannot shut down GUI with RPC command"); -#endif } @@ -1676,11 +1672,6 @@ Value encryptwallet(const Array& params, bool fHelp) if (pwalletMain->IsCrypted()) throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called."); -#ifdef QT_GUI - // shutting down via RPC while the GUI is running does not work (yet): - throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command"); -#endif - // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) // Alternately, find a way to make params[0] mlock()'d to begin with. SecureString strWalletPass; @@ -1698,7 +1689,7 @@ Value encryptwallet(const Array& params, bool fHelp) // BDB seems to have a bad habit of writing old data into // slack space in .dat files; that is bad if the old data is // unencrypted private keys. So: - CreateThread(Shutdown, NULL); + QueueShutdown(); return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet"; } @@ -2381,9 +2372,7 @@ void ThreadRPCServer2(void* parg) strWhatAmI.c_str(), GetConfigFile().c_str(), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()); -#ifndef QT_GUI - CreateThread(Shutdown, NULL); -#endif + QueueShutdown(); return; } diff --git a/src/main.cpp b/src/main.cpp index ca589e54f..19a6c08f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1812,7 +1812,7 @@ bool CheckDiskSpace(uint64 nAdditionalBytes) strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION); - CreateThread(Shutdown, NULL); + QueueShutdown(); return false; } return true; diff --git a/src/noui.h b/src/noui.h index 4010ec3c7..0cb42ca0a 100644 --- a/src/noui.h +++ b/src/noui.h @@ -7,6 +7,7 @@ #include #include "wallet.h" +#include "init.h" typedef void wxWindow; #define wxYES 0x00000002 @@ -71,4 +72,10 @@ inline const char* _(const char* psz) return psz; } +inline void QueueShutdown() +{ + // Without UI, Shutdown can simply be started in a new thread + CreateThread(Shutdown, NULL); +} + #endif diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index e91855bec..f566476e6 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -111,6 +111,11 @@ void InitMessage(const std::string &message) } } +void QueueShutdown() +{ + QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); +} + /* Translate string to current locale using Qt. */ diff --git a/src/qtui.h b/src/qtui.h index 662b231cd..07451e5f5 100644 --- a/src/qtui.h +++ b/src/qtui.h @@ -42,6 +42,7 @@ extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, extern void ThreadSafeHandleURL(const std::string& strURL); extern void MainFrameRepaint(); extern void AddressBookRepaint(); +extern void QueueShutdown(); extern void InitMessage(const std::string &message); extern std::string _(const char* psz); From 7cfbe1fee465e82ddbdc8ed17dfcce791bd765f5 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 25 Mar 2012 20:47:33 +0200 Subject: [PATCH 08/10] qtui.h/noui.h interface cleanup - rename wxMessageBox, remove redundant arguments to noui/qtui calls - also, add flag to force blocking, modal dialog box for disk space warning etc - clarify function naming - no more special MessageBox needed from AppInit2, as window object is created before calling AppInit2 --- src/init.cpp | 18 +++++++++--------- src/main.cpp | 2 +- src/noui.h | 13 ++++--------- src/qt/bitcoin.cpp | 31 ++++++++++++++----------------- src/qt/bitcoingui.cpp | 13 +++++++++---- src/qt/bitcoingui.h | 2 +- src/qt/clientmodel.h | 2 +- src/qt/walletmodel.cpp | 2 +- src/qt/walletmodel.h | 2 +- src/qtui.h | 9 ++++----- src/util.cpp | 2 +- src/wallet.cpp | 2 +- 12 files changed, 47 insertions(+), 51 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index d04c7a2db..eecbc83ed 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -237,7 +237,7 @@ bool AppInit2(int argc, char* argv[]) strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end()); #if defined(QT_GUI) && defined(WIN32) // On windows, show a message box, as there is no stderr - wxMessageBox(strUsage, "Usage"); + ThreadSafeMessageBox(strUsage, _("Usage"), wxOK | wxMODAL); #else fprintf(stderr, "%s", strUsage.c_str()); #endif @@ -326,7 +326,7 @@ bool AppInit2(int argc, char* argv[]) static boost::interprocess::file_lock lock(strLockFile.c_str()); if (!lock.try_lock()) { - wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin"); + ThreadSafeMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), _("Bitcoin"), wxOK|wxMODAL); return false; } @@ -368,7 +368,7 @@ bool AppInit2(int argc, char* argv[]) { strErrors << _("Wallet needed to be rewritten: restart Bitcoin to complete") << "\n"; printf("%s", strErrors.str().c_str()); - wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR); + ThreadSafeMessageBox(strErrors.str(), _("Bitcoin"), wxOK | wxICON_ERROR | wxMODAL); return false; } else @@ -440,7 +440,7 @@ bool AppInit2(int argc, char* argv[]) if (!strErrors.str().empty()) { - wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR); + ThreadSafeMessageBox(strErrors.str(), _("Bitcoin"), wxOK | wxICON_ERROR | wxMODAL); return false; } @@ -496,7 +496,7 @@ bool AppInit2(int argc, char* argv[]) addrProxy = CService(mapArgs["-proxy"], 9050); if (!addrProxy.IsValid()) { - wxMessageBox(_("Invalid -proxy address"), "Bitcoin"); + ThreadSafeMessageBox(_("Invalid -proxy address"), _("Bitcoin"), wxOK | wxMODAL); return false; } } @@ -527,7 +527,7 @@ bool AppInit2(int argc, char* argv[]) std::string strError; if (!BindListenPort(strError)) { - wxMessageBox(strError, "Bitcoin"); + ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL); return false; } } @@ -547,11 +547,11 @@ bool AppInit2(int argc, char* argv[]) { if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) { - wxMessageBox(_("Invalid amount for -paytxfee="), "Bitcoin"); + ThreadSafeMessageBox(_("Invalid amount for -paytxfee="), _("Bitcoin"), wxOK | wxMODAL); return false; } if (nTransactionFee > 0.25 * COIN) - wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION); + ThreadSafeMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), _("Bitcoin"), wxOK | wxICON_EXCLAMATION | wxMODAL); } // @@ -563,7 +563,7 @@ bool AppInit2(int argc, char* argv[]) RandAddSeedPerfmon(); if (!CreateThread(StartNode, NULL)) - wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin"); + ThreadSafeMessageBox(_("Error: CreateThread(StartNode) failed"), _("Bitcoin"), wxOK | wxMODAL); if (fServer) CreateThread(ThreadRPCServer, NULL); diff --git a/src/main.cpp b/src/main.cpp index 19a6c08f8..7c49316b4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1811,7 +1811,7 @@ bool CheckDiskSpace(uint64 nAdditionalBytes) string strMessage = _("Warning: Disk space is low "); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION); + ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL); QueueShutdown(); return false; } diff --git a/src/noui.h b/src/noui.h index 0cb42ca0a..4ae57365a 100644 --- a/src/noui.h +++ b/src/noui.h @@ -9,7 +9,6 @@ #include "wallet.h" #include "init.h" -typedef void wxWindow; #define wxYES 0x00000002 #define wxOK 0x00000004 #define wxNO 0x00000008 @@ -36,21 +35,17 @@ typedef void wxWindow; #define wxHELP 0x00008000 #define wxMORE 0x00010000 #define wxSETUP 0x00020000 +// Force blocking, modal message box dialog (not just notification) +#define wxMODAL 0x00040000 -inline int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1) +inline int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK) { printf("%s: %s\n", caption.c_str(), message.c_str()); fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); return 4; } -#define wxMessageBox MyMessageBox -inline int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1) -{ - return MyMessageBox(message, caption, style, parent, x, y); -} - -inline bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent) +inline bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) { return true; } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index f566476e6..394e4a766 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -38,23 +38,18 @@ static QSplashScreen *splashref; static WalletModel *walletmodel; static ClientModel *clientmodel; -int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y) -{ - // Message from AppInit2(), always in main thread before main window is constructed - QMessageBox::critical(0, QString::fromStdString(caption), - QString::fromStdString(message), - QMessageBox::Ok, QMessageBox::Ok); - return 4; -} - -int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y) +int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) { // Message from network thread if(guiref) { - QMetaObject::invokeMethod(guiref, "error", Qt::QueuedConnection, + bool modal = (style & wxMODAL); + // in case of modal message, use blocking connection to wait for user to click OK + QMetaObject::invokeMethod(guiref, "error", + modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(caption)), - Q_ARG(QString, QString::fromStdString(message))); + Q_ARG(QString, QString::fromStdString(message)), + Q_ARG(bool, modal)); } else { @@ -64,7 +59,7 @@ int ThreadSafeMessageBox(const std::string& message, const std::string& caption, return 4; } -bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent) +bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) { if(!guiref) return false; @@ -222,15 +217,16 @@ int main(int argc, char *argv[]) try { + BitcoinGUI window; + guiref = &window; if(AppInit2(argc, argv)) { { - // Put this in a block, so that BitcoinGUI is cleaned up properly before - // calling Shutdown() in case of exceptions. + // Put this in a block, so that the Model objects are cleaned up before + // calling Shutdown(). optionsModel.Upgrade(); // Must be done after AppInit2 - BitcoinGUI window; if (splashref) splash.finish(&window); @@ -239,7 +235,6 @@ int main(int argc, char *argv[]) WalletModel walletModel(pwalletMain, &optionsModel); walletmodel = &walletModel; - guiref = &window; window.setClientModel(&clientModel); window.setWalletModel(&walletModel); @@ -276,6 +271,8 @@ int main(int argc, char *argv[]) #endif app.exec(); + window.setClientModel(0); + window.setWalletModel(0); guiref = 0; clientmodel = 0; walletmodel = 0; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index f2d131851..c65a26deb 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -336,7 +336,7 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int))); // Report errors from network/worker thread - connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString))); + connect(clientModel, SIGNAL(error(QString,QString, bool)), this, SLOT(error(QString,QString,bool))); } } @@ -346,7 +346,7 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel) if(walletModel) { // Report errors from wallet thread - connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString))); + connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool))); // Put transaction list in tabs transactionView->setModel(walletModel); @@ -538,10 +538,15 @@ void BitcoinGUI::setNumBlocks(int count) progressBar->setToolTip(tooltip); } -void BitcoinGUI::error(const QString &title, const QString &message) +void BitcoinGUI::error(const QString &title, const QString &message, bool modal) { // Report errors from network/worker thread - notificator->notify(Notificator::Critical, title, message); + if(modal) + { + QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok); + } else { + notificator->notify(Notificator::Critical, title, message); + } } void BitcoinGUI::changeEvent(QEvent *e) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 2130babcb..c684d7cc3 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -115,7 +115,7 @@ public slots: void setEncryptionStatus(int status); /** Notify the user of an error in the network or transaction handling code. */ - void error(const QString &title, const QString &message); + void error(const QString &title, const QString &message, bool modal); /** Asks the user whether to pay the transaction fee or to cancel the transaction. It is currently not possible to pass a return value to another thread through BlockingQueuedConnection, so an indirected pointer is used. diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 3dfbcecc0..6366b4d61 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -52,7 +52,7 @@ signals: void numBlocksChanged(int count); //! Asynchronous error notification - void error(const QString &title, const QString &message); + void error(const QString &title, const QString &message, bool modal); public slots: diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 084185492..6cc023792 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -140,7 +140,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList #include "wallet.h" -typedef void wxWindow; #define wxYES 0x00000002 #define wxOK 0x00000004 #define wxNO 0x00000008 @@ -34,11 +33,11 @@ typedef void wxWindow; #define wxHELP 0x00008000 #define wxMORE 0x00010000 #define wxSETUP 0x00020000 +// Force blocking, modal message box dialog (not just notification) +#define wxMODAL 0x00040000 -extern int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1); -#define wxMessageBox MyMessageBox -extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1); -extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent); +extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK); +extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption); extern void ThreadSafeHandleURL(const std::string& strURL); extern void MainFrameRepaint(); extern void AddressBookRepaint(); diff --git a/src/util.cpp b/src/util.cpp index cf73ecf5a..4f34ab616 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1041,7 +1041,7 @@ void AddTimeData(const CNetAddr& ip, int64 nTime) string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly."); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1)); + ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION); } } } diff --git a/src/wallet.cpp b/src/wallet.cpp index 3bdb4bb56..e444e5f69 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1219,7 +1219,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, return strError; } - if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL)) + if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."))) return "ABORTED"; if (!CommitTransaction(wtxNew, reservekey)) From 5a60b66a9d2a9e7a9dda269d6ee4a2fe6d01a354 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 31 Mar 2012 15:08:25 +0200 Subject: [PATCH 09/10] Use a messagebox to display the error when -server is provided without providing a rpc password --- src/bitcoinrpc.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index e511505c1..eb2f04f1d 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -2362,16 +2362,17 @@ void ThreadRPCServer2(void* parg) strWhatAmI = strprintf(_("To use the %s option"), "\"-server\""); else if (mapArgs.count("-daemon")) strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\""); - std::string strMessage = _("%s, you must set a rpcpassword in the configuration file:\n %s\n" - "It is recommended you use the following random password:\n" - "rpcuser=bitcoinrpc\n" - "rpcpassword=%s\n" - "(you do not need to remember this password)\n" - "If the file does not exist, create it with owner-readable-only file permissions.\n"); - fprintf(stderr, strMessage.c_str(), + ThreadSafeMessageBox(strprintf( + _("%s, you must set a rpcpassword in the configuration file:\n %s\n" + "It is recommended you use the following random password:\n" + "rpcuser=bitcoinrpc\n" + "rpcpassword=%s\n" + "(you do not need to remember this password)\n" + "If the file does not exist, create it with owner-readable-only file permissions.\n"), strWhatAmI.c_str(), GetConfigFile().c_str(), - EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()); + EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), + _("Error"), wxOK | wxMODAL); QueueShutdown(); return; } From 5cccb13dad589b66957772ee36b3be0ef06ed0dc Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 4 Apr 2012 13:19:30 +0200 Subject: [PATCH 10/10] Move from noui.h / ui.h to one ui_interface.h with dummy implementation for the daemon. --- bitcoin-qt.pro | 5 +-- src/headers.h | 7 +--- src/makefile.linux-mingw | 3 +- src/makefile.mingw | 3 +- src/makefile.osx | 3 +- src/makefile.unix | 3 +- src/noui.cpp | 45 ++++++++++++++++++++ src/noui.h | 76 ---------------------------------- src/qt/transactiondesc.cpp | 2 +- src/{qtui.h => ui_interface.h} | 8 ++-- 10 files changed, 63 insertions(+), 92 deletions(-) create mode 100644 src/noui.cpp delete mode 100644 src/noui.h rename src/{qtui.h => ui_interface.h} (90%) diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index a2bf4010e..7ad94037c 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -115,7 +115,6 @@ HEADERS += src/qt/bitcoingui.h \ src/key.h \ src/db.h \ src/script.h \ - src/noui.h \ src/init.h \ src/headers.h \ src/irc.h \ @@ -135,7 +134,6 @@ HEADERS += src/qt/bitcoingui.h \ src/qt/guiconstants.h \ src/qt/optionsmodel.h \ src/qt/monitoreddatamapper.h \ - src/qtui.h \ src/qt/transactiondesc.h \ src/qt/transactiondescdialog.h \ src/qt/bitcoinamountfield.h \ @@ -156,7 +154,8 @@ HEADERS += src/qt/bitcoingui.h \ src/protocol.h \ src/qt/notificator.h \ src/qt/qtipcserver.h \ - src/allocators.h + src/allocators.h \ + src/ui_interface.h SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \ src/qt/transactiontablemodel.cpp \ diff --git a/src/headers.h b/src/headers.h index 3596fd08d..ceee02897 100644 --- a/src/headers.h +++ b/src/headers.h @@ -87,8 +87,5 @@ #include "bignum.h" #include "base58.h" #include "main.h" -#ifdef QT_GUI -#include "qtui.h" -#else -#include "noui.h" -#endif +#include "wallet.h" +#include "ui_interface.h" diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 40ce1dcdc..0bbe612a0 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -59,7 +59,8 @@ OBJS= \ obj/rpcdump.o \ obj/script.o \ obj/util.o \ - obj/wallet.o + obj/wallet.o \ + obj/noui.o all: bitcoind.exe diff --git a/src/makefile.mingw b/src/makefile.mingw index f7dfcc74c..307fca783 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -57,7 +57,8 @@ OBJS= \ obj/rpcdump.o \ obj/script.o \ obj/util.o \ - obj/wallet.o + obj/wallet.o \ + obj/noui.o all: bitcoind.exe diff --git a/src/makefile.osx b/src/makefile.osx index 8790d92ce..6388a71e1 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -74,7 +74,8 @@ OBJS= \ obj/rpcdump.o \ obj/script.o \ obj/util.o \ - obj/wallet.o + obj/wallet.o \ + obj/noui.o ifdef USE_UPNP DEFS += -DUSE_UPNP=$(USE_UPNP) diff --git a/src/makefile.unix b/src/makefile.unix index 92c1b97e1..66e020bbe 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -105,7 +105,8 @@ OBJS= \ obj/rpcdump.o \ obj/script.o \ obj/util.o \ - obj/wallet.o + obj/wallet.o \ + obj/noui.o all: bitcoind diff --git a/src/noui.cpp b/src/noui.cpp new file mode 100644 index 000000000..077e460a7 --- /dev/null +++ b/src/noui.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +#include "ui_interface.h" + +#include +#include "headers.h" +#include "init.h" + +int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +{ + 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) +{ + return true; +} + +void MainFrameRepaint() +{ +} + +void AddressBookRepaint() +{ +} + +void InitMessage(const std::string &message) +{ +} + +std::string _(const char* psz) +{ + return psz; +} + +void QueueShutdown() +{ + // Without UI, Shutdown can simply be started in a new thread + CreateThread(Shutdown, NULL); +} + diff --git a/src/noui.h b/src/noui.h deleted file mode 100644 index 4ae57365a..000000000 --- a/src/noui.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2012 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_NOUI_H -#define BITCOIN_NOUI_H - -#include -#include "wallet.h" -#include "init.h" - -#define wxYES 0x00000002 -#define wxOK 0x00000004 -#define wxNO 0x00000008 -#define wxYES_NO (wxYES|wxNO) -#define wxCANCEL 0x00000010 -#define wxAPPLY 0x00000020 -#define wxCLOSE 0x00000040 -#define wxOK_DEFAULT 0x00000000 -#define wxYES_DEFAULT 0x00000000 -#define wxNO_DEFAULT 0x00000080 -#define wxCANCEL_DEFAULT 0x80000000 -#define wxICON_EXCLAMATION 0x00000100 -#define wxICON_HAND 0x00000200 -#define wxICON_WARNING wxICON_EXCLAMATION -#define wxICON_ERROR wxICON_HAND -#define wxICON_QUESTION 0x00000400 -#define wxICON_INFORMATION 0x00000800 -#define wxICON_STOP wxICON_HAND -#define wxICON_ASTERISK wxICON_INFORMATION -#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800) -#define wxFORWARD 0x00001000 -#define wxBACKWARD 0x00002000 -#define wxRESET 0x00004000 -#define wxHELP 0x00008000 -#define wxMORE 0x00010000 -#define wxSETUP 0x00020000 -// Force blocking, modal message box dialog (not just notification) -#define wxMODAL 0x00040000 - -inline int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK) -{ - printf("%s: %s\n", caption.c_str(), message.c_str()); - fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); - return 4; -} - -inline bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) -{ - return true; -} - -inline void MainFrameRepaint() -{ -} - -inline void AddressBookRepaint() -{ -} - -inline void InitMessage(const std::string &message) -{ -} - -inline const char* _(const char* psz) -{ - return psz; -} - -inline void QueueShutdown() -{ - // Without UI, Shutdown can simply be started in a new thread - CreateThread(Shutdown, NULL); -} - -#endif diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 4cb2e68d0..c32a006f7 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -4,7 +4,7 @@ #include "bitcoinunits.h" #include "headers.h" -#include "qtui.h" +#include "ui_interface.h" #include diff --git a/src/qtui.h b/src/ui_interface.h similarity index 90% rename from src/qtui.h rename to src/ui_interface.h index 405fc497c..2e29f2af1 100644 --- a/src/qtui.h +++ b/src/ui_interface.h @@ -1,11 +1,11 @@ // Copyright (c) 2010 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_EXTERNUI_H -#define BITCOIN_EXTERNUI_H +#ifndef BITCOIN_UI_INTERFACE_H +#define BITCOIN_UI_INTERFACE_H #include -#include "wallet.h" +#include "util.h" // for int64 #define wxYES 0x00000002 #define wxOK 0x00000004 @@ -36,6 +36,8 @@ // Force blocking, modal message box dialog (not just notification) #define wxMODAL 0x00040000 +/* These UI communication functions are implemented in bitcoin.cpp (for ui) and noui.cpp (no ui) */ + extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK); extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption); extern void ThreadSafeHandleURL(const std::string& strURL);