Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make UI more responsive #28

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion pinkcoin-qt.pro
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ macx {

isEmpty(BOOST_LIB_SUFFIX) {
macx:BOOST_LIB_SUFFIX = -mt
windows:BOOST_LIB_SUFFIX = -mgw49-mt-s-1_57
windows:BOOST_LIB_SUFFIX = -mt-s
}

isEmpty(BOOST_THREAD_LIB_SUFFIX) {
Expand Down Expand Up @@ -139,6 +139,9 @@ contains(RELEASE, 1) {
# This can be enabled for Windows, when we switch to MinGW >= 4.4.x.
}

# Temporarily fix issue with too big main.o file
Debug:win32:QMAKE_CXXFLAGS *= -Wa,-mbig-obj -O1

# for extra security on Windows: enable ASLR and DEP via GCC linker flags
win32:QMAKE_LFLAGS *= -Wl,--dynamicbase -Wl,--nxcompat
win32:QMAKE_LFLAGS += -static-libgcc -static-libstdc++ -static
Expand Down
26 changes: 18 additions & 8 deletions src/db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,11 @@ void CDBEnv::CheckpointLSN(std::string strFile)
}


CDB::CDB(const char *pszFile, const char* pszMode) :
CDB::CDB(const char *pszFile, const char* pszMode, bool fFlushOnCloseIn) :
pdb(NULL), activeTxn(NULL)
{
int ret;
fFlushOnClose = fFlushOnCloseIn;
if (pszFile == NULL)
return;

Expand Down Expand Up @@ -303,14 +304,10 @@ static bool IsChainFile(std::string strFile)
return false;
}

void CDB::Close()
void CDB::Flush()
{
if (!pdb)
return;
if (activeTxn)
activeTxn->abort();
activeTxn = NULL;
pdb = NULL;
return;

// Flush database activity from memory pool to disk log
unsigned int nMinutes = 0;
Expand All @@ -321,7 +318,20 @@ void CDB::Close()
if (IsChainFile(strFile) && IsInitialBlockDownload())
nMinutes = 5;

bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0);
}

void CDB::Close()
{
if (!pdb)
return;
if (activeTxn)
activeTxn->abort();
activeTxn = NULL;
pdb = NULL;

if (fFlushOnClose)
Flush();

{
LOCK(bitdb.cs_db);
Expand Down
4 changes: 3 additions & 1 deletion src/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,12 @@ class CDB
std::string strFile;
DbTxn *activeTxn;
bool fReadOnly;
bool fFlushOnClose;

explicit CDB(const char* pszFile, const char* pszMode="r+");
explicit CDB(const char* pszFile, const char* pszMode="r+", bool fFlushOnCloseIn=true);
~CDB() { Close(); }
public:
void Flush();
void Close();
private:
CDB(const CDB&);
Expand Down
15 changes: 15 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <openssl/crypto.h>
Expand Down Expand Up @@ -346,6 +347,17 @@ std::string HelpMessage()
return strUsage;
}

static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex)
{
if (initialSync || !pBlockIndex)
return;

std::string strCmd = GetArg("-blocknotify", "");

boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
}

/** Sanity checks
* Ensure that Bitcoin is running in a usable environment with all
* necessary library support.
Expand Down Expand Up @@ -949,6 +961,9 @@ bool AppInit2(boost::thread_group& threadGroup)

// ********************************************************* Step 9: import blocks

if (mapArgs.count("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);

if (mapArgs.count("-loadblock"))
{
uiInterface.InitMessage(_("Importing blockchain data file."));
Expand Down
9 changes: 1 addition & 8 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include "kernel.h"
#include "smessage.h"
#include "time.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

Expand Down Expand Up @@ -2060,13 +2059,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
strMiscWarning = _("Warning: This version is obsolete, upgrade required!");
}

std::string strCmd = GetArg("-blocknotify", "");

if (!fIsInitialDownload && !strCmd.empty())
{
boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
}
uiInterface.NotifyBlockTip(fIsInitialDownload, pindexBest);

return true;
}
Expand Down
10 changes: 5 additions & 5 deletions src/makefile.mingw
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ LIBPATHS= \
-L"C:\openssl-1.0.1c-mgw"

LIBS= \
-l boost_system-mgw44-mt-1_53 \
-l boost_filesystem-mgw44-mt-1_53 \
-l boost_program_options-mgw44-mt-1_53 \
-l boost_thread-mgw44-mt-1_53 \
-l boost_chrono-mgw44-mt-1_53 \
-l boost_system-mt-s \
-l boost_filesystem-mt-s \
-l boost_program_options-mt-s \
-l boost_thread-mt-s \
-l boost_chrono-mt-s \
-l db_cxx \
-l ssl \
-l crypto
Expand Down
55 changes: 47 additions & 8 deletions src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QProgressDialog>
#include <QLocale>
#include <QMessageBox>
#include <QMimeData>
Expand Down Expand Up @@ -394,6 +395,10 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage()));
connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex)));

// Receive and report messages
connect(this, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
connect(sendCoinsPage, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));

// Double-clicking on a transaction on the transaction history page shows details
connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));

Expand Down Expand Up @@ -766,14 +771,14 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel, WalletModel *stakeMode
// Report errors from wallet thread
connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));

// Put transaction list in tabs
transactionView->setModel(walletModel);
// Put transaction list in tabs
transactionView->setModel(walletModel);

overviewPage->setModel(walletModel);
addressBookPage->setModel(walletModel->getAddressTableModel());
receiveCoinsPage->setModel(walletModel->getAddressTableModel());
sendCoinsPage->setModel(walletModel);
signVerifyMessageDialog->setModel(walletModel);
overviewPage->setModel(walletModel);
addressBookPage->setModel(walletModel->getAddressTableModel());
receiveCoinsPage->setModel(walletModel->getAddressTableModel());
sendCoinsPage->setModel(walletModel);
signVerifyMessageDialog->setModel(walletModel);

setEncryptionStatus(walletModel->getEncryptionStatus());
connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
Expand All @@ -788,6 +793,9 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel, WalletModel *stakeMode
}
if(stakeModel)
stakeCoinsPage->setModel(stakeModel->getAddressTableModel());

// Show progress dialog
connect(walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
}

void BitcoinGUI::setMessageModel(MessageModel *messageModel)
Expand Down Expand Up @@ -1074,7 +1082,11 @@ void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int
{
if(!walletModel || !clientModel)
return;

TransactionTableModel *ttm = walletModel->getTransactionTableModel();
if (!ttm || ttm->processingQueuedTransactions())
return;

qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
.data(Qt::EditRole).toULongLong();

Expand Down Expand Up @@ -1332,8 +1344,12 @@ void BitcoinGUI::backupWallet()
QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
if(!filename.isEmpty()) {
if(!walletModel->backupWallet(filename)) {
QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."));
emit message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."),
CClientUIInterface::MSG_ERROR);
}
else
emit message(tr("Backup Successful"), tr("The wallet data was successfully saved to the new location."),
CClientUIInterface::MSG_INFORMATION);
}
}

Expand Down Expand Up @@ -1471,6 +1487,29 @@ void BitcoinGUI::updateStakingIcon()
}
}

void BitcoinGUI::showProgress(const QString &title, int nProgress)
{
if (nProgress == 0)
{
progressDialog = new QProgressDialog(title, "", 0, 100);
progressDialog->setWindowModality(Qt::ApplicationModal);
progressDialog->setMinimumDuration(0);
progressDialog->setCancelButton(0);
progressDialog->setAutoClose(false);
progressDialog->setValue(0);
}
else if (nProgress == 100)
{
if (progressDialog)
{
progressDialog->close();
progressDialog->deleteLater();
}
}
else if (progressDialog)
progressDialog->setValue(nProgress);
}

/* zeewolf: Hot swappable wallet themes */
void BitcoinGUI::changeTheme(QString theme)
{
Expand Down
9 changes: 9 additions & 0 deletions src/qt/bitcoingui.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class QTableView;
class QAbstractItemModel;
class QModelIndex;
class QProgressBar;
class QProgressDialog;
class QStackedWidget;
class QUrl;
QT_END_NAMESPACE
Expand Down Expand Up @@ -114,6 +115,7 @@ class BitcoinGUI : public QMainWindow
QToolBar *mainToolbar;
QToolBar *secondaryToolbar;
QProgressBar *progressBar;
QProgressDialog *progressDialog;

QMenuBar *appMenuBar;
QAction *overviewAction;
Expand Down Expand Up @@ -197,6 +199,9 @@ public slots:
void mainToolbarOrientation(Qt::Orientation orientation);
//void secondaryToolbarOrientation(Qt::Orientation orientation);

/** Show progress dialog e.g. for rescan */
void showProgress(const QString &title, int nProgress);

private slots:
/** Switch to overview (home) page */
void gotoOverviewPage();
Expand Down Expand Up @@ -268,6 +273,10 @@ private slots:
void loadTheme(QString theme);
void listThemes(QStringList& themes);
void keyPressEvent(QKeyEvent * e);

signals:
/** Fired when a message should be reported to the user */
void message(const QString &title, const QString &message, unsigned int style);
};

#endif
Expand Down
52 changes: 30 additions & 22 deletions src/qt/clientmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
#include <QDateTime>
#include <QTimer>

class CBlockIndex;

static int64_t nLastBlockTipUpdateNotification = 0;
static const int64_t nClientStartupTime = GetTime();

ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
QObject(parent), optionsModel(optionsModel),
cachedNumBlocks(0), cachedNumBlocksOfPeers(0), numBlocksAtStartup(-1), pollTimer(0)
QObject(parent), optionsModel(optionsModel), numBlocksAtStartup(-1), pollTimer(0)
{
pollTimer = new QTimer(this);
pollTimer->setInterval(MODEL_UPDATE_DELAY);
Expand Down Expand Up @@ -68,26 +70,8 @@ QDateTime ClientModel::getLastBlockDate() const

void ClientModel::updateTimer()
{
// Get required lock upfront. This avoids the GUI from getting stuck on
// periodical polls if the core is holding the locks for a longer time -
// for example, during a wallet rescan.
TRY_LOCK(cs_main, lockMain);
if(!lockMain)
return;
// Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
// Periodically check and update with a timer.
int newNumBlocks = getNumBlocks();
int newNumBlocksOfPeers = getNumBlocksOfPeers();

if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers)
{
cachedNumBlocks = newNumBlocks;
cachedNumBlocksOfPeers = newNumBlocksOfPeers;

// ensure we return the maximum of newNumBlocksOfPeers and newNumBlocks to not create weird displays in the GUI
emit numBlocksChanged(newNumBlocks, std::max(newNumBlocksOfPeers, newNumBlocks));
}

// No locking required at this point
// the following calls will aquire the required lock
emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
}

Expand Down Expand Up @@ -175,16 +159,40 @@ static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, Ch
Q_ARG(int, status));
}

static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex)
{
// Lock free async UI updates in case we have a new block tip
// during initial sync, only update the UI if the last update
// was > MODEL_UPDATE_DELAY ms ago
int64_t now = 0;
if (initialSync)
now = GetTimeMillis();

// If we are in-sync, update the UI regardless of last update time.
if (!initialSync || now - nLastBlockTipUpdateNotification > MODEL_UPDATE_DELAY) {
int newNumBlocks = pIndex->nHeight;
int newNumBlocksOfPeers = GetNumBlocksOfPeers();

// Passes an async signal to the UI thread.
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
Q_ARG(int, newNumBlocks),
Q_ARG(int, std::max(newNumBlocksOfPeers, newNumBlocks)));
nLastBlockTipUpdateNotification = now;
}
}

void ClientModel::subscribeToCoreSignals()
{
// Connect signals to client
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2));
}

void ClientModel::unsubscribeFromCoreSignals()
{
// Disconnect signals from client
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2));
}