mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-13 13:22:38 -03:00
Merge pull request #3493
9a2305a
qt: Stop shutdown detection timer during shutdown (Wladimir J. van der Laan)35ecf85
qt: Remove global references in bitcoin.cpp (Wladimir J. van der Laan)55fe4de
qt: Show window while shutting down (Wladimir J. van der Laan)202d853
qt: Move initialization/shutdown to a thread (Wladimir J. van der Laan)
This commit is contained in:
commit
054be736d4
6 changed files with 409 additions and 141 deletions
|
@ -108,7 +108,7 @@ QT_MOC_CPP = moc_aboutdialog.cpp moc_addressbookpage.cpp \
|
||||||
|
|
||||||
BITCOIN_MM = macdockiconhandler.mm macnotificationhandler.mm
|
BITCOIN_MM = macdockiconhandler.mm macnotificationhandler.mm
|
||||||
|
|
||||||
QT_MOC = intro.moc overviewpage.moc rpcconsole.moc
|
QT_MOC = intro.moc overviewpage.moc rpcconsole.moc bitcoin.moc
|
||||||
|
|
||||||
QT_QRC_CPP = qrc_bitcoin.cpp
|
QT_QRC_CPP = qrc_bitcoin.cpp
|
||||||
QT_QRC = bitcoin.qrc
|
QT_QRC = bitcoin.qrc
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
#if defined(QT_STATICPLUGIN)
|
#if defined(QT_STATICPLUGIN)
|
||||||
#include <QtPlugin>
|
#include <QtPlugin>
|
||||||
|
@ -52,40 +55,8 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
|
||||||
// Declare meta types used for QMetaObject::invokeMethod
|
// Declare meta types used for QMetaObject::invokeMethod
|
||||||
Q_DECLARE_METATYPE(bool*)
|
Q_DECLARE_METATYPE(bool*)
|
||||||
|
|
||||||
// Need a global reference for the notifications to find the GUI
|
|
||||||
static BitcoinGUI *guiref;
|
|
||||||
static SplashScreen *splashref;
|
|
||||||
|
|
||||||
static bool ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
|
|
||||||
{
|
|
||||||
if(guiref)
|
|
||||||
{
|
|
||||||
bool modal = (style & CClientUIInterface::MODAL);
|
|
||||||
bool ret = false;
|
|
||||||
// In case of modal message, use blocking connection to wait for user to click a button
|
|
||||||
QMetaObject::invokeMethod(guiref, "message",
|
|
||||||
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
|
|
||||||
Q_ARG(QString, QString::fromStdString(caption)),
|
|
||||||
Q_ARG(QString, QString::fromStdString(message)),
|
|
||||||
Q_ARG(unsigned int, style),
|
|
||||||
Q_ARG(bool*, &ret));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrintf("%s: %s\n", caption.c_str(), message.c_str());
|
|
||||||
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InitMessage(const std::string &message)
|
static void InitMessage(const std::string &message)
|
||||||
{
|
{
|
||||||
if(splashref)
|
|
||||||
{
|
|
||||||
splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(55,55,55));
|
|
||||||
qApp->processEvents();
|
|
||||||
}
|
|
||||||
LogPrintf("init message: %s\n", message.c_str());
|
LogPrintf("init message: %s\n", message.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,15 +68,6 @@ static std::string Translate(const char* psz)
|
||||||
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
|
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle runaway exceptions. Shows a message box with the problem and quits the program.
|
|
||||||
*/
|
|
||||||
static void handleRunawayException(std::exception *e)
|
|
||||||
{
|
|
||||||
PrintExceptionContinue(e, "Runaway exception");
|
|
||||||
QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + QString::fromStdString(strMiscWarning));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set up translations */
|
/** Set up translations */
|
||||||
static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
|
static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
|
||||||
{
|
{
|
||||||
|
@ -162,6 +124,300 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Class encapsulating Bitcoin Core startup and shutdown.
|
||||||
|
* Allows running startup and shutdown in a different thread from the UI thread.
|
||||||
|
*/
|
||||||
|
class BitcoinCore: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit BitcoinCore();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void initialize();
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void initializeResult(int retval);
|
||||||
|
void shutdownResult(int retval);
|
||||||
|
void runawayException(const QString &message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::thread_group threadGroup;
|
||||||
|
|
||||||
|
/// Pass fatal exception message to UI thread
|
||||||
|
void handleRunawayException(std::exception *e);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Main Bitcoin application object */
|
||||||
|
class BitcoinApplication: public QApplication
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit BitcoinApplication(int &argc, char **argv);
|
||||||
|
~BitcoinApplication();
|
||||||
|
|
||||||
|
/// Create payment server
|
||||||
|
void createPaymentServer();
|
||||||
|
/// Create options model
|
||||||
|
void createOptionsModel();
|
||||||
|
/// Create main window
|
||||||
|
void createWindow(bool isaTestNet);
|
||||||
|
/// Create splash screen
|
||||||
|
void createSplashScreen(bool isaTestNet);
|
||||||
|
|
||||||
|
/// Request core initialization
|
||||||
|
void requestInitialize();
|
||||||
|
/// Request core shutdown
|
||||||
|
void requestShutdown();
|
||||||
|
|
||||||
|
/// Get process return value
|
||||||
|
int getReturnValue() { return returnValue; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void initializeResult(int retval);
|
||||||
|
void shutdownResult(int retval);
|
||||||
|
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
|
||||||
|
void handleRunawayException(const QString &message);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void requestedInitialize();
|
||||||
|
void requestedShutdown();
|
||||||
|
void stopThread();
|
||||||
|
void splashFinished(QWidget *window);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QThread *coreThread;
|
||||||
|
PaymentServer* paymentServer;
|
||||||
|
OptionsModel *optionsModel;
|
||||||
|
ClientModel *clientModel;
|
||||||
|
BitcoinGUI *window;
|
||||||
|
WalletModel *walletModel;
|
||||||
|
QTimer *pollShutdownTimer;
|
||||||
|
int returnValue;
|
||||||
|
|
||||||
|
void startThread();
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "bitcoin.moc"
|
||||||
|
|
||||||
|
BitcoinCore::BitcoinCore():
|
||||||
|
QObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinCore::handleRunawayException(std::exception *e)
|
||||||
|
{
|
||||||
|
PrintExceptionContinue(e, "Runaway exception");
|
||||||
|
emit runawayException(QString::fromStdString(strMiscWarning));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinCore::initialize()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogPrintf("Running AppInit2 in thread\n");
|
||||||
|
int rv = AppInit2(threadGroup);
|
||||||
|
emit initializeResult(rv);
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
handleRunawayException(&e);
|
||||||
|
} catch (...) {
|
||||||
|
handleRunawayException(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinCore::shutdown()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogPrintf("Running Shutdown in thread\n");
|
||||||
|
threadGroup.interrupt_all();
|
||||||
|
threadGroup.join_all();
|
||||||
|
Shutdown();
|
||||||
|
LogPrintf("Shutdown finished\n");
|
||||||
|
emit shutdownResult(1);
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
handleRunawayException(&e);
|
||||||
|
} catch (...) {
|
||||||
|
handleRunawayException(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BitcoinApplication::BitcoinApplication(int &argc, char **argv):
|
||||||
|
QApplication(argc, argv),
|
||||||
|
coreThread(0),
|
||||||
|
paymentServer(0),
|
||||||
|
optionsModel(0),
|
||||||
|
clientModel(0),
|
||||||
|
window(0),
|
||||||
|
walletModel(0),
|
||||||
|
pollShutdownTimer(0),
|
||||||
|
returnValue(0)
|
||||||
|
{
|
||||||
|
setQuitOnLastWindowClosed(false);
|
||||||
|
startThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
BitcoinApplication::~BitcoinApplication()
|
||||||
|
{
|
||||||
|
LogPrintf("Stopping thread\n");
|
||||||
|
emit stopThread();
|
||||||
|
coreThread->wait();
|
||||||
|
LogPrintf("Stopped thread\n");
|
||||||
|
|
||||||
|
delete window;
|
||||||
|
delete paymentServer;
|
||||||
|
delete optionsModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::createPaymentServer()
|
||||||
|
{
|
||||||
|
paymentServer = new PaymentServer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::createOptionsModel()
|
||||||
|
{
|
||||||
|
optionsModel = new OptionsModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::createWindow(bool isaTestNet)
|
||||||
|
{
|
||||||
|
window = new BitcoinGUI(isaTestNet, 0);
|
||||||
|
|
||||||
|
pollShutdownTimer = new QTimer(window);
|
||||||
|
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
|
||||||
|
pollShutdownTimer->start(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::createSplashScreen(bool isaTestNet)
|
||||||
|
{
|
||||||
|
SplashScreen *splash = new SplashScreen(QPixmap(), 0, isaTestNet);
|
||||||
|
splash->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
splash->show();
|
||||||
|
connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::startThread()
|
||||||
|
{
|
||||||
|
coreThread = new QThread(this);
|
||||||
|
BitcoinCore *executor = new BitcoinCore();
|
||||||
|
executor->moveToThread(coreThread);
|
||||||
|
|
||||||
|
/* communication to and from thread */
|
||||||
|
connect(executor, SIGNAL(initializeResult(int)), this, SLOT(initializeResult(int)));
|
||||||
|
connect(executor, SIGNAL(shutdownResult(int)), this, SLOT(shutdownResult(int)));
|
||||||
|
connect(executor, SIGNAL(runawayException(QString)), this, SLOT(handleRunawayException(QString)));
|
||||||
|
connect(this, SIGNAL(requestedInitialize()), executor, SLOT(initialize()));
|
||||||
|
connect(this, SIGNAL(requestedShutdown()), executor, SLOT(shutdown()));
|
||||||
|
/* make sure executor object is deleted in its own thread */
|
||||||
|
connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater()));
|
||||||
|
connect(this, SIGNAL(stopThread()), coreThread, SLOT(quit()));
|
||||||
|
|
||||||
|
coreThread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::requestInitialize()
|
||||||
|
{
|
||||||
|
LogPrintf("Requesting initialize\n");
|
||||||
|
emit requestedInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::requestShutdown()
|
||||||
|
{
|
||||||
|
LogPrintf("Requesting shutdown\n");
|
||||||
|
window->hide();
|
||||||
|
window->setClientModel(0);
|
||||||
|
window->removeAllWallets();
|
||||||
|
pollShutdownTimer->stop();
|
||||||
|
|
||||||
|
delete walletModel;
|
||||||
|
walletModel = 0;
|
||||||
|
delete clientModel;
|
||||||
|
clientModel = 0;
|
||||||
|
|
||||||
|
// Show a simple window indicating shutdown status
|
||||||
|
QWidget *shutdownWindow = new QWidget();
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout();
|
||||||
|
layout->addWidget(new QLabel(
|
||||||
|
tr("Bitcoin Core is shutting down...\n") +
|
||||||
|
tr("Do not shut down the computer until this window disappears.")));
|
||||||
|
shutdownWindow->setLayout(layout);
|
||||||
|
|
||||||
|
// Center shutdown window at where main window was
|
||||||
|
const QPoint global = window->mapToGlobal(window->rect().center());
|
||||||
|
shutdownWindow->move(global.x() - shutdownWindow->width() / 2, global.y() - shutdownWindow->height() / 2);
|
||||||
|
shutdownWindow->show();
|
||||||
|
|
||||||
|
// Request shutdown from core thread
|
||||||
|
emit requestedShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::initializeResult(int retval)
|
||||||
|
{
|
||||||
|
LogPrintf("Initialization result: %i\n", retval);
|
||||||
|
// Set exit result: 0 if successful, 1 if failure
|
||||||
|
returnValue = retval ? 0 : 1;
|
||||||
|
if(retval)
|
||||||
|
{
|
||||||
|
// Miscellaneous initialization after core is initialized
|
||||||
|
optionsModel->Upgrade(); // Must be done after AppInit2
|
||||||
|
|
||||||
|
PaymentServer::LoadRootCAs();
|
||||||
|
paymentServer->setOptionsModel(optionsModel);
|
||||||
|
|
||||||
|
emit splashFinished(window);
|
||||||
|
|
||||||
|
clientModel = new ClientModel(optionsModel);
|
||||||
|
window->setClientModel(clientModel);
|
||||||
|
|
||||||
|
if(pwalletMain)
|
||||||
|
{
|
||||||
|
walletModel = new WalletModel(pwalletMain, optionsModel);
|
||||||
|
|
||||||
|
window->addWallet("~Default", walletModel);
|
||||||
|
window->setCurrentWallet("~Default");
|
||||||
|
|
||||||
|
connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)),
|
||||||
|
paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If -min option passed, start window minimized.
|
||||||
|
if(GetBoolArg("-min", false))
|
||||||
|
{
|
||||||
|
window->showMinimized();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that initialization/startup is done, process any command-line
|
||||||
|
// bitcoin: URIs or payment requests:
|
||||||
|
connect(paymentServer, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
|
||||||
|
window, SLOT(handlePaymentRequest(SendCoinsRecipient)));
|
||||||
|
connect(window, SIGNAL(receivedURI(QString)),
|
||||||
|
paymentServer, SLOT(handleURIOrFile(QString)));
|
||||||
|
connect(paymentServer, SIGNAL(message(QString,QString,unsigned int)),
|
||||||
|
window, SLOT(message(QString,QString,unsigned int)));
|
||||||
|
QTimer::singleShot(100, paymentServer, SLOT(uiReady()));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
quit(); // Exit main loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::shutdownResult(int retval)
|
||||||
|
{
|
||||||
|
LogPrintf("Shutdown result: %i\n", retval);
|
||||||
|
quit(); // Exit main loop after shutdown finished
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinApplication::handleRunawayException(const QString &message)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message);
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef BITCOIN_QT_TEST
|
#ifndef BITCOIN_QT_TEST
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -189,7 +445,7 @@ int main(int argc, char *argv[])
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Q_INIT_RESOURCE(bitcoin);
|
Q_INIT_RESOURCE(bitcoin);
|
||||||
QApplication app(argc, argv);
|
BitcoinApplication app(argc, argv);
|
||||||
#if QT_VERSION > 0x050100
|
#if QT_VERSION > 0x050100
|
||||||
// Generate high-dpi pixmaps
|
// Generate high-dpi pixmaps
|
||||||
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
|
@ -215,6 +471,7 @@ int main(int argc, char *argv[])
|
||||||
// Now that QSettings are accessible, initialize translations
|
// Now that QSettings are accessible, initialize translations
|
||||||
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
|
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
|
||||||
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
|
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
|
||||||
|
uiInterface.Translate.connect(Translate);
|
||||||
|
|
||||||
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
|
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
|
||||||
// but before showing splash screen.
|
// but before showing splash screen.
|
||||||
|
@ -254,7 +511,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
// Start up the payment server early, too, so impatient users that click on
|
// Start up the payment server early, too, so impatient users that click on
|
||||||
// bitcoin: links repeatedly have their payment requests routed to this process:
|
// bitcoin: links repeatedly have their payment requests routed to this process:
|
||||||
PaymentServer* paymentServer = new PaymentServer(&app);
|
app.createPaymentServer();
|
||||||
|
|
||||||
/// 8. Main GUI initialization
|
/// 8. Main GUI initialization
|
||||||
// Install global event filter that makes sure that long tooltips can be word-wrapped
|
// Install global event filter that makes sure that long tooltips can be word-wrapped
|
||||||
|
@ -266,24 +523,22 @@ int main(int argc, char *argv[])
|
||||||
qInstallMessageHandler(DebugMessageHandler);
|
qInstallMessageHandler(DebugMessageHandler);
|
||||||
#endif
|
#endif
|
||||||
// Load GUI settings from QSettings
|
// Load GUI settings from QSettings
|
||||||
OptionsModel optionsModel;
|
app.createOptionsModel();
|
||||||
|
|
||||||
// Subscribe to global signals from core
|
// Subscribe to global signals from core
|
||||||
uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox);
|
|
||||||
uiInterface.InitMessage.connect(InitMessage);
|
uiInterface.InitMessage.connect(InitMessage);
|
||||||
uiInterface.Translate.connect(Translate);
|
|
||||||
|
|
||||||
// Show splash screen if appropriate
|
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
|
||||||
SplashScreen splash(QPixmap(), 0, isaTestNet);
|
// but before showing splash screen.
|
||||||
if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false))
|
if (mapArgs.count("-?") || mapArgs.count("--help"))
|
||||||
{
|
{
|
||||||
splash.show();
|
GUIUtil::HelpMessageBox help;
|
||||||
splash.setAutoFillBackground(true);
|
help.showOrPrint();
|
||||||
splashref = &splash;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.processEvents();
|
if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false))
|
||||||
app.setQuitOnLastWindowClosed(false);
|
app.createSplashScreen(isaTestNet);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -293,93 +548,18 @@ int main(int argc, char *argv[])
|
||||||
if (GUIUtil::GetStartOnSystemStartup())
|
if (GUIUtil::GetStartOnSystemStartup())
|
||||||
GUIUtil::SetStartOnSystemStartup(true);
|
GUIUtil::SetStartOnSystemStartup(true);
|
||||||
#endif
|
#endif
|
||||||
|
app.createWindow(isaTestNet);
|
||||||
boost::thread_group threadGroup;
|
app.requestInitialize();
|
||||||
|
app.exec();
|
||||||
BitcoinGUI window(isaTestNet, 0);
|
app.requestShutdown();
|
||||||
guiref = &window;
|
app.exec();
|
||||||
|
|
||||||
QTimer* pollShutdownTimer = new QTimer(guiref);
|
|
||||||
QObject::connect(pollShutdownTimer, SIGNAL(timeout()), guiref, SLOT(detectShutdown()));
|
|
||||||
pollShutdownTimer->start(200);
|
|
||||||
|
|
||||||
if(AppInit2(threadGroup))
|
|
||||||
{
|
|
||||||
{
|
|
||||||
// Put this in a block, so that the Model objects are cleaned up before
|
|
||||||
// calling Shutdown().
|
|
||||||
|
|
||||||
optionsModel.Upgrade(); // Must be done after AppInit2
|
|
||||||
|
|
||||||
PaymentServer::LoadRootCAs();
|
|
||||||
paymentServer->setOptionsModel(&optionsModel);
|
|
||||||
|
|
||||||
if (splashref)
|
|
||||||
splash.finish(&window);
|
|
||||||
|
|
||||||
ClientModel clientModel(&optionsModel);
|
|
||||||
window.setClientModel(&clientModel);
|
|
||||||
|
|
||||||
WalletModel *walletModel = 0;
|
|
||||||
if(pwalletMain)
|
|
||||||
walletModel = new WalletModel(pwalletMain, &optionsModel);
|
|
||||||
|
|
||||||
if(walletModel)
|
|
||||||
{
|
|
||||||
window.addWallet("~Default", walletModel);
|
|
||||||
window.setCurrentWallet("~Default");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If -min option passed, start window minimized.
|
|
||||||
if(GetBoolArg("-min", false))
|
|
||||||
{
|
|
||||||
window.showMinimized();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
window.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that initialization/startup is done, process any command-line
|
|
||||||
// bitcoin: URIs or payment requests:
|
|
||||||
QObject::connect(paymentServer, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
|
|
||||||
&window, SLOT(handlePaymentRequest(SendCoinsRecipient)));
|
|
||||||
QObject::connect(&window, SIGNAL(receivedURI(QString)),
|
|
||||||
paymentServer, SLOT(handleURIOrFile(QString)));
|
|
||||||
if(walletModel)
|
|
||||||
{
|
|
||||||
QObject::connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)),
|
|
||||||
paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray)));
|
|
||||||
}
|
|
||||||
QObject::connect(paymentServer, SIGNAL(message(QString,QString,unsigned int)),
|
|
||||||
guiref, SLOT(message(QString,QString,unsigned int)));
|
|
||||||
QTimer::singleShot(100, paymentServer, SLOT(uiReady()));
|
|
||||||
|
|
||||||
app.exec();
|
|
||||||
|
|
||||||
window.hide();
|
|
||||||
window.setClientModel(0);
|
|
||||||
window.removeAllWallets();
|
|
||||||
guiref = 0;
|
|
||||||
delete walletModel;
|
|
||||||
}
|
|
||||||
// Shutdown the core and its threads, but don't exit the GUI here
|
|
||||||
threadGroup.interrupt_all();
|
|
||||||
threadGroup.join_all();
|
|
||||||
Shutdown();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
threadGroup.interrupt_all();
|
|
||||||
threadGroup.join_all();
|
|
||||||
Shutdown();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
handleRunawayException(&e);
|
PrintExceptionContinue(&e, "Runaway exception");
|
||||||
|
app.handleRunawayException(QString::fromStdString(strMiscWarning));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
handleRunawayException(NULL);
|
PrintExceptionContinue(NULL, "Runaway exception");
|
||||||
|
app.handleRunawayException(QString::fromStdString(strMiscWarning));
|
||||||
}
|
}
|
||||||
return 0;
|
return app.getReturnValue();
|
||||||
}
|
}
|
||||||
#endif // BITCOIN_QT_TEST
|
#endif // BITCOIN_QT_TEST
|
||||||
|
|
|
@ -170,10 +170,16 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
|
||||||
|
|
||||||
// Initially wallet actions should be disabled
|
// Initially wallet actions should be disabled
|
||||||
setWalletActionsEnabled(false);
|
setWalletActionsEnabled(false);
|
||||||
|
|
||||||
|
// Subscribe to notifications from core
|
||||||
|
subscribeToCoreSignals();
|
||||||
}
|
}
|
||||||
|
|
||||||
BitcoinGUI::~BitcoinGUI()
|
BitcoinGUI::~BitcoinGUI()
|
||||||
{
|
{
|
||||||
|
// Unsubscribe from notifications from core
|
||||||
|
unsubscribeFromCoreSignals();
|
||||||
|
|
||||||
GUIUtil::saveWindowGeometry("nWindow", this);
|
GUIUtil::saveWindowGeometry("nWindow", this);
|
||||||
if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
|
if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
|
||||||
trayIcon->hide();
|
trayIcon->hide();
|
||||||
|
@ -849,5 +855,35 @@ void BitcoinGUI::toggleHidden()
|
||||||
void BitcoinGUI::detectShutdown()
|
void BitcoinGUI::detectShutdown()
|
||||||
{
|
{
|
||||||
if (ShutdownRequested())
|
if (ShutdownRequested())
|
||||||
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
|
{
|
||||||
|
if(rpcConsole)
|
||||||
|
rpcConsole->hide();
|
||||||
|
qApp->quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
|
||||||
|
{
|
||||||
|
bool modal = (style & CClientUIInterface::MODAL);
|
||||||
|
bool ret = false;
|
||||||
|
// In case of modal message, use blocking connection to wait for user to click a button
|
||||||
|
QMetaObject::invokeMethod(gui, "message",
|
||||||
|
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
|
||||||
|
Q_ARG(QString, QString::fromStdString(caption)),
|
||||||
|
Q_ARG(QString, QString::fromStdString(message)),
|
||||||
|
Q_ARG(unsigned int, style),
|
||||||
|
Q_ARG(bool*, &ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::subscribeToCoreSignals()
|
||||||
|
{
|
||||||
|
// Connect signals to client
|
||||||
|
uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::unsubscribeFromCoreSignals()
|
||||||
|
{
|
||||||
|
// Disconnect signals from client
|
||||||
|
uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,11 @@ private:
|
||||||
/** Enable or disable all wallet-related actions */
|
/** Enable or disable all wallet-related actions */
|
||||||
void setWalletActionsEnabled(bool enabled);
|
void setWalletActionsEnabled(bool enabled);
|
||||||
|
|
||||||
|
/** Connect core signals to GUI client */
|
||||||
|
void subscribeToCoreSignals();
|
||||||
|
/** Disconnect core signals from GUI client */
|
||||||
|
void unsubscribeFromCoreSignals();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/** Signal raised when a URI was entered or dragged to the GUI */
|
/** Signal raised when a URI was entered or dragged to the GUI */
|
||||||
void receivedURI(const QString &uri);
|
void receivedURI(const QString &uri);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "clientversion.h"
|
#include "clientversion.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "ui_interface.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
@ -13,6 +14,8 @@
|
||||||
SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTestNet) :
|
SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTestNet) :
|
||||||
QSplashScreen(pixmap, f)
|
QSplashScreen(pixmap, f)
|
||||||
{
|
{
|
||||||
|
setAutoFillBackground(true);
|
||||||
|
|
||||||
// set reference point, paddings
|
// set reference point, paddings
|
||||||
int paddingRight = 50;
|
int paddingRight = 50;
|
||||||
int paddingTop = 50;
|
int paddingTop = 50;
|
||||||
|
@ -83,4 +86,37 @@ SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTest
|
||||||
pixPaint.end();
|
pixPaint.end();
|
||||||
|
|
||||||
this->setPixmap(newPixmap);
|
this->setPixmap(newPixmap);
|
||||||
|
|
||||||
|
subscribeToCoreSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
SplashScreen::~SplashScreen()
|
||||||
|
{
|
||||||
|
unsubscribeFromCoreSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::slotFinish(QWidget *mainWin)
|
||||||
|
{
|
||||||
|
finish(mainWin);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InitMessage(SplashScreen *splash, const std::string &message)
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(splash, "showMessage",
|
||||||
|
Qt::QueuedConnection,
|
||||||
|
Q_ARG(QString, QString::fromStdString(message)),
|
||||||
|
Q_ARG(int, Qt::AlignBottom|Qt::AlignHCenter),
|
||||||
|
Q_ARG(QColor, QColor(55,55,55)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::subscribeToCoreSignals()
|
||||||
|
{
|
||||||
|
// Connect signals to client
|
||||||
|
uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::unsubscribeFromCoreSignals()
|
||||||
|
{
|
||||||
|
// Disconnect signals from client
|
||||||
|
uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,17 @@ class SplashScreen : public QSplashScreen
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTestNet);
|
explicit SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTestNet);
|
||||||
|
~SplashScreen();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/** Slot to call finish() method as it's not defined as slot */
|
||||||
|
void slotFinish(QWidget *mainWin);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Connect core signals to splash screen */
|
||||||
|
void subscribeToCoreSignals();
|
||||||
|
/** Disconnect core signals to splash screen */
|
||||||
|
void unsubscribeFromCoreSignals();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SPLASHSCREEN_H
|
#endif // SPLASHSCREEN_H
|
||||||
|
|
Loading…
Reference in a new issue