Skip to content

Commit 2102ab9

Browse files
committed
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.
1 parent 16403b4 commit 2102ab9

File tree

4 files changed

+64
-41
lines changed

4 files changed

+64
-41
lines changed

src/qt/bitcoin.cpp

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -161,22 +161,23 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
161161
#ifndef BITCOIN_QT_TEST
162162
int main(int argc, char *argv[])
163163
{
164-
bool fMissingDatadir = false;
165164
bool fSelParFromCLFailed = false;
166-
165+
/// 1. Parse command-line options. These take precedence over anything else.
167166
// Command-line options take precedence:
168167
ParseParameters(argc, argv);
169-
// ... then bitcoin.conf:
170-
if (!boost::filesystem::is_directory(GetDataDir(false))) {
171-
fMissingDatadir = true;
172-
} else {
173-
ReadConfigFile(mapArgs, mapMultiArgs);
174-
}
175168
// Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause)
176169
if (!SelectParamsFromCommandLine()) {
177170
fSelParFromCLFailed = true;
178171
}
172+
// Parse URIs on command line -- this can affect TestNet() / RegTest() mode
173+
if (!PaymentServer::ipcParseCommandLine(argc, argv))
174+
exit(0);
175+
176+
bool isaTestNet = TestNet() || RegTest();
177+
178+
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
179179

180+
/// 2. Basic Qt initialization (not dependent on parameters or configuration)
180181
#if QT_VERSION < 0x050000
181182
// Internal string conversion is all UTF-8
182183
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
@@ -196,44 +197,62 @@ int main(int argc, char *argv[])
196197
// Register meta types used for QMetaObject::invokeMethod
197198
qRegisterMetaType< bool* >();
198199

199-
// Application identification (must be set before OptionsModel is initialized,
200-
// as it is used to locate QSettings)
201-
bool isaTestNet = TestNet() || RegTest();
200+
/// 3. Application identification
201+
// must be set before OptionsModel is initialized or translations are loaded,
202+
// as it is used to locate QSettings
202203
QApplication::setOrganizationName("Bitcoin");
203204
QApplication::setOrganizationDomain("bitcoin.org");
204205
if (isaTestNet) // Separate UI settings for testnets
205206
QApplication::setApplicationName("Bitcoin-Qt-testnet");
206207
else
207208
QApplication::setApplicationName("Bitcoin-Qt");
208209

210+
/// 4. Initialization of translations, so that intro dialog is in user's language
209211
// Now that QSettings are accessible, initialize translations
210212
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
211213
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
212214

213-
// Do this early as we don't want to bother initializing if we are just calling IPC
214-
// ... but do it after creating app and setting up translations, so errors are
215-
// translated properly.
216-
if (PaymentServer::ipcSendCommandLine(argc, argv))
217-
exit(0);
218-
219-
// Now that translations are initialized check for errors and allow a translatable error message
220-
if (fMissingDatadir) {
221-
QMessageBox::critical(0, QObject::tr("Bitcoin"),
222-
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"])));
215+
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
216+
// but before showing splash screen.
217+
if (mapArgs.count("-?") || mapArgs.count("--help"))
218+
{
219+
GUIUtil::HelpMessageBox help;
220+
help.showOrPrint();
223221
return 1;
224222
}
225-
else if (fSelParFromCLFailed) {
223+
// Now that translations are initialized, check for earlier errors and show a translatable error message
224+
if (fSelParFromCLFailed) {
226225
QMessageBox::critical(0, QObject::tr("Bitcoin"), QObject::tr("Error: Invalid combination of -regtest and -testnet."));
227226
return 1;
228227
}
229228

229+
/// 5. Now that settings and translations are available, ask user for data directory
230+
// User language is set up: pick a data directory
231+
Intro::pickDataDirectory(isaTestNet);
232+
233+
/// 6. Determine availability of data directory and parse bitcoin.conf
234+
if (!boost::filesystem::is_directory(GetDataDir(false)))
235+
{
236+
QMessageBox::critical(0, QObject::tr("Bitcoin"),
237+
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"])));
238+
return 1;
239+
}
240+
ReadConfigFile(mapArgs, mapMultiArgs);
241+
242+
/// 7. URI IPC sending
243+
// - Do this early as we don't want to bother initializing if we are just calling IPC
244+
// - Do this *after* setting up the data directory, as the data directory hash is used in the name
245+
// of the server.
246+
// - Do this after creating app and setting up translations, so errors are
247+
// translated properly.
248+
if (PaymentServer::ipcSendCommandLine())
249+
exit(0);
250+
230251
// Start up the payment server early, too, so impatient users that click on
231252
// bitcoin: links repeatedly have their payment requests routed to this process:
232253
PaymentServer* paymentServer = new PaymentServer(&app);
233254

234-
// User language is set up: pick a data directory
235-
Intro::pickDataDirectory(isaTestNet);
236-
255+
/// 8. Main GUI initialization
237256
// Install global event filter that makes sure that long tooltips can be word-wrapped
238257
app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
239258
// Install qDebug() message handler to route to debug.log
@@ -242,24 +261,15 @@ int main(int argc, char *argv[])
242261
#else
243262
qInstallMessageHandler(DebugMessageHandler);
244263
#endif
245-
246-
// ... now GUI settings:
264+
// Load GUI settings from QSettings
247265
OptionsModel optionsModel;
248266

249267
// Subscribe to global signals from core
250268
uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox);
251269
uiInterface.InitMessage.connect(InitMessage);
252270
uiInterface.Translate.connect(Translate);
253271

254-
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
255-
// but before showing splash screen.
256-
if (mapArgs.count("-?") || mapArgs.count("--help"))
257-
{
258-
GUIUtil::HelpMessageBox help;
259-
help.showOrPrint();
260-
return 1;
261-
}
262-
272+
// Show splash screen if appropriate
263273
SplashScreen splash(QPixmap(), 0, isaTestNet);
264274
if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false))
265275
{

src/qt/intro.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ QString Intro::getDefaultDataDirectory()
148148

149149
void Intro::pickDataDirectory(bool fIsTestnet)
150150
{
151-
namespace fs = boost::filesystem;;
151+
namespace fs = boost::filesystem;
152152
QSettings settings;
153153
/* If data directory provided on command line, no need to look at settings
154154
or show a picking dialog */

src/qt/paymentserver.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,8 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
180180
// and the items in savedPaymentRequest will be handled
181181
// when uiReady() is called.
182182
//
183-
bool PaymentServer::ipcSendCommandLine(int argc, char* argv[])
183+
bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
184184
{
185-
bool fResult = false;
186-
187185
for (int i = 1; i < argc; i++)
188186
{
189187
QString arg(argv[i]);
@@ -226,7 +224,18 @@ bool PaymentServer::ipcSendCommandLine(int argc, char* argv[])
226224
qDebug() << "PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg;
227225
}
228226
}
227+
return true;
228+
}
229229

230+
//
231+
// Sending to the server is done synchronously, at startup.
232+
// If the server isn't already running, startup continues,
233+
// and the items in savedPaymentRequest will be handled
234+
// when uiReady() is called.
235+
//
236+
bool PaymentServer::ipcSendCommandLine()
237+
{
238+
bool fResult = false;
230239
foreach (const QString& r, savedPaymentRequests)
231240
{
232241
QLocalSocket* socket = new QLocalSocket();

src/qt/paymentserver.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,16 @@ class PaymentServer : public QObject
5656
Q_OBJECT
5757

5858
public:
59+
// Parse URIs on command line
60+
// Returns false on error
61+
static bool ipcParseCommandLine(int argc, char *argv[]);
62+
5963
// Returns true if there were URIs on the command line
6064
// which were successfully sent to an already-running
6165
// process.
6266
// Note: if a payment request is given, SelectParams(MAIN/TESTNET)
6367
// will be called so we startup in the right mode.
64-
static bool ipcSendCommandLine(int argc, char *argv[]);
68+
static bool ipcSendCommandLine();
6569

6670
// parent should be QApplication object
6771
PaymentServer(QObject* parent, bool startLocalServer = true);

0 commit comments

Comments
 (0)