Browse Source

ui: Fix GUI initialization order

Fixes at least #3478.

Splits and documents the phases:
1. Parse command-line options. These take precedence over anything else.
2. Basic Qt initialization (not dependent on parameters or configuration)
3. Application identification
4. Initialization of translations
5. Now that settings and translations are available, ask user for data directory
6. Determine availability of data directory and parse bitcoin.conf
7. URI IPC sending
8. Main GUI initialization

Splits command line parsing logic from ipcSendCommandLine into
ipcParseCommandLine, as isTestNet() can only be overridden in the early
stages before choosing a data directory. Sending however needs to happen
after choosing a data directory.
metaverse
Wladimir J. van der Laan 11 years ago
parent
commit
2102ab9f5c
  1. 82
      src/qt/bitcoin.cpp
  2. 2
      src/qt/intro.cpp
  3. 15
      src/qt/paymentserver.cpp
  4. 6
      src/qt/paymentserver.h

82
src/qt/bitcoin.cpp

@ -161,22 +161,23 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
#ifndef BITCOIN_QT_TEST #ifndef BITCOIN_QT_TEST
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
bool fMissingDatadir = false;
bool fSelParFromCLFailed = false; bool fSelParFromCLFailed = false;
/// 1. Parse command-line options. These take precedence over anything else.
// Command-line options take precedence: // Command-line options take precedence:
ParseParameters(argc, argv); ParseParameters(argc, argv);
// ... then bitcoin.conf:
if (!boost::filesystem::is_directory(GetDataDir(false))) {
fMissingDatadir = true;
} else {
ReadConfigFile(mapArgs, mapMultiArgs);
}
// Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause) // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause)
if (!SelectParamsFromCommandLine()) { if (!SelectParamsFromCommandLine()) {
fSelParFromCLFailed = true; fSelParFromCLFailed = true;
} }
// Parse URIs on command line -- this can affect TestNet() / RegTest() mode
if (!PaymentServer::ipcParseCommandLine(argc, argv))
exit(0);
bool isaTestNet = TestNet() || RegTest();
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
/// 2. Basic Qt initialization (not dependent on parameters or configuration)
#if QT_VERSION < 0x050000 #if QT_VERSION < 0x050000
// Internal string conversion is all UTF-8 // Internal string conversion is all UTF-8
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
@ -196,9 +197,9 @@ int main(int argc, char *argv[])
// Register meta types used for QMetaObject::invokeMethod // Register meta types used for QMetaObject::invokeMethod
qRegisterMetaType< bool* >(); qRegisterMetaType< bool* >();
// Application identification (must be set before OptionsModel is initialized, /// 3. Application identification
// as it is used to locate QSettings) // must be set before OptionsModel is initialized or translations are loaded,
bool isaTestNet = TestNet() || RegTest(); // as it is used to locate QSettings
QApplication::setOrganizationName("Bitcoin"); QApplication::setOrganizationName("Bitcoin");
QApplication::setOrganizationDomain("bitcoin.org"); QApplication::setOrganizationDomain("bitcoin.org");
if (isaTestNet) // Separate UI settings for testnets if (isaTestNet) // Separate UI settings for testnets
@ -206,34 +207,52 @@ int main(int argc, char *argv[])
else else
QApplication::setApplicationName("Bitcoin-Qt"); QApplication::setApplicationName("Bitcoin-Qt");
/// 4. Initialization of translations, so that intro dialog is in user's language
// 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);
// Do this early as we don't want to bother initializing if we are just calling IPC // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// ... but do it after creating app and setting up translations, so errors are // but before showing splash screen.
// translated properly. if (mapArgs.count("-?") || mapArgs.count("--help"))
if (PaymentServer::ipcSendCommandLine(argc, argv)) {
exit(0); GUIUtil::HelpMessageBox help;
help.showOrPrint();
// Now that translations are initialized check for errors and allow a translatable error message
if (fMissingDatadir) {
QMessageBox::critical(0, QObject::tr("Bitcoin"),
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"])));
return 1; return 1;
} }
else if (fSelParFromCLFailed) { // Now that translations are initialized, check for earlier errors and show a translatable error message
if (fSelParFromCLFailed) {
QMessageBox::critical(0, QObject::tr("Bitcoin"), QObject::tr("Error: Invalid combination of -regtest and -testnet.")); QMessageBox::critical(0, QObject::tr("Bitcoin"), QObject::tr("Error: Invalid combination of -regtest and -testnet."));
return 1; return 1;
} }
/// 5. Now that settings and translations are available, ask user for data directory
// User language is set up: pick a data directory
Intro::pickDataDirectory(isaTestNet);
/// 6. Determine availability of data directory and parse bitcoin.conf
if (!boost::filesystem::is_directory(GetDataDir(false)))
{
QMessageBox::critical(0, QObject::tr("Bitcoin"),
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"])));
return 1;
}
ReadConfigFile(mapArgs, mapMultiArgs);
/// 7. URI IPC sending
// - Do this early as we don't want to bother initializing if we are just calling IPC
// - Do this *after* setting up the data directory, as the data directory hash is used in the name
// of the server.
// - Do this after creating app and setting up translations, so errors are
// translated properly.
if (PaymentServer::ipcSendCommandLine())
exit(0);
// 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); PaymentServer* paymentServer = new PaymentServer(&app);
// User language is set up: pick a data directory /// 8. Main GUI initialization
Intro::pickDataDirectory(isaTestNet);
// 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
app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
// Install qDebug() message handler to route to debug.log // Install qDebug() message handler to route to debug.log
@ -242,8 +261,7 @@ int main(int argc, char *argv[])
#else #else
qInstallMessageHandler(DebugMessageHandler); qInstallMessageHandler(DebugMessageHandler);
#endif #endif
// Load GUI settings from QSettings
// ... now GUI settings:
OptionsModel optionsModel; OptionsModel optionsModel;
// Subscribe to global signals from core // Subscribe to global signals from core
@ -251,15 +269,7 @@ int main(int argc, char *argv[])
uiInterface.InitMessage.connect(InitMessage); uiInterface.InitMessage.connect(InitMessage);
uiInterface.Translate.connect(Translate); uiInterface.Translate.connect(Translate);
// Show help message immediately after parsing command-line options (for "-lang") and setting locale, // Show splash screen if appropriate
// but before showing splash screen.
if (mapArgs.count("-?") || mapArgs.count("--help"))
{
GUIUtil::HelpMessageBox help;
help.showOrPrint();
return 1;
}
SplashScreen splash(QPixmap(), 0, isaTestNet); SplashScreen splash(QPixmap(), 0, isaTestNet);
if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false)) if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false))
{ {

2
src/qt/intro.cpp

@ -148,7 +148,7 @@ QString Intro::getDefaultDataDirectory()
void Intro::pickDataDirectory(bool fIsTestnet) void Intro::pickDataDirectory(bool fIsTestnet)
{ {
namespace fs = boost::filesystem;; namespace fs = boost::filesystem;
QSettings settings; QSettings settings;
/* If data directory provided on command line, no need to look at settings /* If data directory provided on command line, no need to look at settings
or show a picking dialog */ or show a picking dialog */

15
src/qt/paymentserver.cpp

@ -180,10 +180,8 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
// and the items in savedPaymentRequest will be handled // and the items in savedPaymentRequest will be handled
// when uiReady() is called. // when uiReady() is called.
// //
bool PaymentServer::ipcSendCommandLine(int argc, char* argv[]) bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
{ {
bool fResult = false;
for (int i = 1; i < argc; i++) for (int i = 1; i < argc; i++)
{ {
QString arg(argv[i]); QString arg(argv[i]);
@ -226,7 +224,18 @@ bool PaymentServer::ipcSendCommandLine(int argc, char* argv[])
qDebug() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg; qDebug() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg;
} }
} }
return true;
}
//
// Sending to the server is done synchronously, at startup.
// If the server isn't already running, startup continues,
// and the items in savedPaymentRequest will be handled
// when uiReady() is called.
//
bool PaymentServer::ipcSendCommandLine()
{
bool fResult = false;
foreach (const QString& r, savedPaymentRequests) foreach (const QString& r, savedPaymentRequests)
{ {
QLocalSocket* socket = new QLocalSocket(); QLocalSocket* socket = new QLocalSocket();

6
src/qt/paymentserver.h

@ -56,12 +56,16 @@ class PaymentServer : public QObject
Q_OBJECT Q_OBJECT
public: public:
// Parse URIs on command line
// Returns false on error
static bool ipcParseCommandLine(int argc, char *argv[]);
// Returns true if there were URIs on the command line // Returns true if there were URIs on the command line
// which were successfully sent to an already-running // which were successfully sent to an already-running
// process. // process.
// Note: if a payment request is given, SelectParams(MAIN/TESTNET) // Note: if a payment request is given, SelectParams(MAIN/TESTNET)
// will be called so we startup in the right mode. // will be called so we startup in the right mode.
static bool ipcSendCommandLine(int argc, char *argv[]); static bool ipcSendCommandLine();
// parent should be QApplication object // parent should be QApplication object
PaymentServer(QObject* parent, bool startLocalServer = true); PaymentServer(QObject* parent, bool startLocalServer = true);

Loading…
Cancel
Save