From: Pieter Wuille Date: Wed, 4 Apr 2012 12:03:07 +0000 (-0700) Subject: Merge pull request #1019 from laanwj/2012_03_uirefactor X-Git-Tag: v0.4.0-unstable~129^2~110 X-Git-Url: https://git.novaco.in/?a=commitdiff_plain;h=b0a7e05a45a925d78efd00ecca6dce9b7a9530f9;hp=cadae3588c5553b8c7ef76c14d07041f639fb926;p=novacoin.git Merge pull request #1019 from laanwj/2012_03_uirefactor Streamline UI ↔ Core interface --- diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index d9206b3..7ad9403 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 \ @@ -155,7 +153,9 @@ 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 \ + src/ui_interface.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 0000000..85d9cfb --- /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/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 868419e..eb2f04f 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"; } @@ -2371,19 +2362,18 @@ 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()); -#ifndef QT_GUI - CreateThread(Shutdown, NULL); -#endif + EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), + _("Error"), wxOK | wxMODAL); + QueueShutdown(); return; } diff --git a/src/crypter.h b/src/crypter.h index 0f9ea02..59a005a 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/headers.h b/src/headers.h index 3596fd0..ceee028 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/init.cpp b/src/init.cpp index 8531b20..eecbc83 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 @@ -248,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 @@ -337,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; } @@ -379,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 @@ -451,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; } @@ -507,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; } } @@ -538,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; } } @@ -558,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); } // @@ -574,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 ca75b9f..7c49316 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1811,8 +1811,8 @@ 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); - CreateThread(Shutdown, NULL); + ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL); + QueueShutdown(); return false; } return true; @@ -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/makefile.linux-mingw b/src/makefile.linux-mingw index 40ce1dc..0bbe612 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 f7dfcc7..307fca7 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 8790d92..6388a71 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 92c1b97..66e020b 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 0000000..077e460 --- /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 458fc64..0000000 --- a/src/noui.h +++ /dev/null @@ -1,74 +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 -#include "wallet.h" - -typedef void wxWindow; -#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 - -inline int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1) -{ - 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) -{ - return true; -} - -inline void CalledSetStatusBar(const std::string& strText, int nField) -{ -} - -inline void UIThreadCall(boost::function0 fn) -{ -} - -inline void MainFrameRepaint() -{ -} - -inline void InitMessage(const std::string &message) -{ -} - -#endif diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index cb185be..8821283 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 8fd6d52..198a857 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 0743300..7fd07cf 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 6ee7fed..394e4a7 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 @@ -21,27 +21,35 @@ #include -// Need a global reference for the notifications to find the GUI -BitcoinGUI *guiref; -QSplashScreen *splashref; +#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 -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; -} +// 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, 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 { @@ -51,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; @@ -59,15 +67,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)); @@ -79,31 +79,22 @@ 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))); } -void CalledSetStatusBar(const std::string& strText, int nField) -{ - // Only used for built-in mining, which is disabled, simple ignore -} - -void UIThreadCall(boost::function0 fn) +void MainFrameRepaint() { - // Only used for built-in mining, which is disabled, simple ignore + if(clientmodel) + QMetaObject::invokeMethod(clientmodel, "update", Qt::QueuedConnection); + if(walletmodel) + QMetaObject::invokeMethod(walletmodel, "update", Qt::QueuedConnection); } -void MainFrameRepaint() +void AddressBookRepaint() { - if(guiref) - QMetaObject::invokeMethod(guiref, "refreshStatusBar", Qt::QueuedConnection); + if(walletmodel) + QMetaObject::invokeMethod(walletmodel, "updateAddressList", Qt::QueuedConnection); } void InitMessage(const std::string &message) @@ -115,6 +106,11 @@ void InitMessage(const std::string &message) } } +void QueueShutdown() +{ + QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); +} + /* Translate string to current locale using Qt. */ @@ -221,22 +217,24 @@ 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); ClientModel clientModel(&optionsModel); + clientmodel = &clientModel; WalletModel walletModel(pwalletMain, &optionsModel); + walletmodel = &walletModel; - guiref = &window; window.setClientModel(&clientModel); window.setWalletModel(&walletModel); @@ -273,7 +271,11 @@ int main(int argc, char *argv[]) #endif app.exec(); + window.setClientModel(0); + window.setWalletModel(0); guiref = 0; + clientmodel = 0; + walletmodel = 0; } Shutdown(NULL); } diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 00bb5bd..a60b585 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -339,7 +339,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))); } } @@ -349,7 +349,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); @@ -552,23 +552,15 @@ 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) +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 dbc3264..c684d7c 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -113,11 +113,9 @@ 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); + 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.cpp b/src/qt/clientmodel.cpp index 5a0b4aa..8163da0 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 5a12c4f..6366b4d 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -43,6 +43,7 @@ private: int cachedNumConnections; int cachedNumBlocks; + QString cachedStatusBar; int numBlocksAtStartup; @@ -51,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/guiutil.cpp b/src/qt/guiutil.cpp index ac69bd0..ad530a7 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 75ba53f..06426d7 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 diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 4cb2e68..c32a006 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/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 8344a65..6cc0237 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()); @@ -142,7 +140,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QListupdateList(); - return SendCoinsReturn(OK, 0, hex); } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index e894842..c446817 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; @@ -135,12 +135,11 @@ signals: void requireUnlock(); // Asynchronous error notification - void error(const QString &title, const QString &message); + void error(const QString &title, const QString &message, bool modal); public slots: - -private slots: void update(); + void updateAddressList(); }; diff --git a/src/serialize.h b/src/serialize.h index 227bfb9..2d4aaba 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/qtui.h b/src/ui_interface.h similarity index 75% rename from src/qtui.h rename to src/ui_interface.h index 9791ba5..2e29f2a 100644 --- a/src/qtui.h +++ b/src/ui_interface.h @@ -1,14 +1,12 @@ // 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 -#include "wallet.h" +#include "util.h" // for int64 -typedef void wxWindow; #define wxYES 0x00000002 #define wxOK 0x00000004 #define wxNO 0x00000008 @@ -35,15 +33,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 -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); +/* 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); -extern void CalledSetStatusBar(const std::string& strText, int nField); -extern void UIThreadCall(boost::function0 fn); extern void MainFrameRepaint(); +extern void AddressBookRepaint(); +extern void QueueShutdown(); extern void InitMessage(const std::string &message); extern std::string _(const char* psz); diff --git a/src/util.cpp b/src/util.cpp index cf73ecf..4f34ab6 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/util.h b/src/util.h index 0af5b0a..e4cf83f 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 - @@ -267,16 +260,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); diff --git a/src/wallet.cpp b/src/wallet.cpp index 27ed722..e444e5f 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)) @@ -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());