1 // Copyright (c) 2011-2019 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #if defined(HAVE_CONFIG_H)
6 #include <config/bitcoin-config.h>
7 #endif
8
9 #include <qt/bitcoin.h>
10 #include <qt/bitcoingui.h>
11
12 #include <chainparams.h>
13 #include <qt/clientmodel.h>
14 #include <fs.h>
15 #include <qt/guiconstants.h>
16 #include <qt/guiutil.h>
17 #include <qt/intro.h>
18 #include <qt/networkstyle.h>
19 #include <qt/optionsmodel.h>
20 #include <qt/platformstyle.h>
21 #include <qt/splashscreen.h>
22 #include <qt/utilitydialog.h>
23 #include <qt/winshutdownmonitor.h>
24
25 #ifdef ENABLE_WALLET
26 #include <qt/paymentserver.h>
27 #include <qt/walletcontroller.h>
28 #endif
29
30 #include <interfaces/handler.h>
31 #include <interfaces/node.h>
32 #include <noui.h>
33 #include <rpc/server.h>
34 #include <ui_interface.h>
35 #include <uint256.h>
36 #include <util/system.h>
37 #include <warnings.h>
38
39 #include <walletinitinterface.h>
40
41 #include <memory>
42 #include <stdint.h>
43
44 #include <boost/thread.hpp>
45
46 #include <QApplication>
47 #include <QDebug>
48 #include <QLibraryInfo>
49 #include <QLocale>
50 #include <QMessageBox>
51 #include <QSettings>
52 #include <QThread>
53 #include <QTimer>
54 #include <QTranslator>
55
56 #if defined(QT_STATICPLUGIN)
57 #include <QtPlugin>
58 #if defined(QT_QPA_PLATFORM_XCB)
59 Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
60 #elif defined(QT_QPA_PLATFORM_WINDOWS)
61 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
62 #elif defined(QT_QPA_PLATFORM_COCOA)
63 Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
64 #endif
65 #endif
66
67 // Declare meta types used for QMetaObject::invokeMethod
68 Q_DECLARE_METATYPE(bool*)
Q_DECLARE_METATYPE(CAmount)69 Q_DECLARE_METATYPE(CAmount)
70 Q_DECLARE_METATYPE(uint256)
71
72 static QString GetLangTerritory()
73 {
74 QSettings settings;
75 // Get desired locale (e.g. "de_DE")
76 // 1) System default language
77 QString lang_territory = QLocale::system().name();
78 // 2) Language from QSettings
79 QString lang_territory_qsettings = settings.value("language", "").toString();
80 if(!lang_territory_qsettings.isEmpty())
81 lang_territory = lang_territory_qsettings;
82 // 3) -lang command line argument
83 lang_territory = QString::fromStdString(gArgs.GetArg("-lang", lang_territory.toStdString()));
84 return lang_territory;
85 }
86
87 /** Set up translations */
initTranslations(QTranslator & qtTranslatorBase,QTranslator & qtTranslator,QTranslator & translatorBase,QTranslator & translator)88 static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
89 {
90 // Remove old translators
91 QApplication::removeTranslator(&qtTranslatorBase);
92 QApplication::removeTranslator(&qtTranslator);
93 QApplication::removeTranslator(&translatorBase);
94 QApplication::removeTranslator(&translator);
95
96 // Get desired locale (e.g. "de_DE")
97 // 1) System default language
98 QString lang_territory = GetLangTerritory();
99
100 // Convert to "de" only by truncating "_DE"
101 QString lang = lang_territory;
102 lang.truncate(lang_territory.lastIndexOf('_'));
103
104 // Load language files for configured locale:
105 // - First load the translator for the base language, without territory
106 // - Then load the more specific locale translator
107
108 // Load e.g. qt_de.qm
109 if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
110 QApplication::installTranslator(&qtTranslatorBase);
111
112 // Load e.g. qt_de_DE.qm
113 if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
114 QApplication::installTranslator(&qtTranslator);
115
116 // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc)
117 if (translatorBase.load(lang, ":/translations/"))
118 QApplication::installTranslator(&translatorBase);
119
120 // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc)
121 if (translator.load(lang_territory, ":/translations/"))
122 QApplication::installTranslator(&translator);
123 }
124
125 /* qDebug() message handler --> debug.log */
DebugMessageHandler(QtMsgType type,const QMessageLogContext & context,const QString & msg)126 void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
127 {
128 Q_UNUSED(context);
129 if (type == QtDebugMsg) {
130 LogPrint(BCLog::QT, "GUI: %s\n", msg.toStdString());
131 } else {
132 LogPrintf("GUI: %s\n", msg.toStdString());
133 }
134 }
135
BitcoinCore(interfaces::Node & node)136 BitcoinCore::BitcoinCore(interfaces::Node& node) :
137 QObject(), m_node(node)
138 {
139 }
140
handleRunawayException(const std::exception * e)141 void BitcoinCore::handleRunawayException(const std::exception *e)
142 {
143 PrintExceptionContinue(e, "Runaway exception");
144 Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings("gui")));
145 }
146
initialize()147 void BitcoinCore::initialize()
148 {
149 try
150 {
151 qDebug() << __func__ << ": Running initialization in thread";
152 bool rv = m_node.appInitMain();
153 Q_EMIT initializeResult(rv);
154 } catch (const std::exception& e) {
155 handleRunawayException(&e);
156 } catch (...) {
157 handleRunawayException(nullptr);
158 }
159 }
160
shutdown()161 void BitcoinCore::shutdown()
162 {
163 try
164 {
165 qDebug() << __func__ << ": Running Shutdown in thread";
166 m_node.appShutdown();
167 qDebug() << __func__ << ": Shutdown finished";
168 Q_EMIT shutdownResult();
169 } catch (const std::exception& e) {
170 handleRunawayException(&e);
171 } catch (...) {
172 handleRunawayException(nullptr);
173 }
174 }
175
176 static int qt_argc = 1;
177 static const char* qt_argv = "litecoin-qt";
178
BitcoinApplication(interfaces::Node & node)179 BitcoinApplication::BitcoinApplication(interfaces::Node& node):
180 QApplication(qt_argc, const_cast<char **>(&qt_argv)),
181 coreThread(nullptr),
182 m_node(node),
183 optionsModel(nullptr),
184 clientModel(nullptr),
185 window(nullptr),
186 pollShutdownTimer(nullptr),
187 returnValue(0),
188 platformStyle(nullptr)
189 {
190 setQuitOnLastWindowClosed(false);
191 }
192
setupPlatformStyle()193 void BitcoinApplication::setupPlatformStyle()
194 {
195 // UI per-platform customization
196 // This must be done inside the BitcoinApplication constructor, or after it, because
197 // PlatformStyle::instantiate requires a QApplication
198 std::string platformName;
199 platformName = gArgs.GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM);
200 platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName));
201 if (!platformStyle) // Fall back to "other" if specified name not found
202 platformStyle = PlatformStyle::instantiate("other");
203 assert(platformStyle);
204 }
205
~BitcoinApplication()206 BitcoinApplication::~BitcoinApplication()
207 {
208 if(coreThread)
209 {
210 qDebug() << __func__ << ": Stopping thread";
211 coreThread->quit();
212 coreThread->wait();
213 qDebug() << __func__ << ": Stopped thread";
214 }
215
216 delete window;
217 window = nullptr;
218 #ifdef ENABLE_WALLET
219 delete paymentServer;
220 paymentServer = nullptr;
221 delete m_wallet_controller;
222 m_wallet_controller = nullptr;
223 #endif
224 delete optionsModel;
225 optionsModel = nullptr;
226 delete platformStyle;
227 platformStyle = nullptr;
228 }
229
230 #ifdef ENABLE_WALLET
createPaymentServer()231 void BitcoinApplication::createPaymentServer()
232 {
233 paymentServer = new PaymentServer(this);
234 }
235 #endif
236
createOptionsModel(bool resetSettings)237 void BitcoinApplication::createOptionsModel(bool resetSettings)
238 {
239 optionsModel = new OptionsModel(m_node, nullptr, resetSettings);
240 }
241
createWindow(const NetworkStyle * networkStyle)242 void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
243 {
244 window = new BitcoinGUI(m_node, platformStyle, networkStyle, nullptr);
245
246 pollShutdownTimer = new QTimer(window);
247 connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown);
248 }
249
createSplashScreen(const NetworkStyle * networkStyle)250 void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
251 {
252 SplashScreen *splash = new SplashScreen(m_node, nullptr, networkStyle);
253 // We don't hold a direct pointer to the splash screen after creation, but the splash
254 // screen will take care of deleting itself when finish() happens.
255 splash->show();
256 connect(this, &BitcoinApplication::splashFinished, splash, &SplashScreen::finish);
257 connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close);
258 }
259
baseInitialize()260 bool BitcoinApplication::baseInitialize()
261 {
262 return m_node.baseInitialize();
263 }
264
startThread()265 void BitcoinApplication::startThread()
266 {
267 if(coreThread)
268 return;
269 coreThread = new QThread(this);
270 BitcoinCore *executor = new BitcoinCore(m_node);
271 executor->moveToThread(coreThread);
272
273 /* communication to and from thread */
274 connect(executor, &BitcoinCore::initializeResult, this, &BitcoinApplication::initializeResult);
275 connect(executor, &BitcoinCore::shutdownResult, this, &BitcoinApplication::shutdownResult);
276 connect(executor, &BitcoinCore::runawayException, this, &BitcoinApplication::handleRunawayException);
277 connect(this, &BitcoinApplication::requestedInitialize, executor, &BitcoinCore::initialize);
278 connect(this, &BitcoinApplication::requestedShutdown, executor, &BitcoinCore::shutdown);
279 /* make sure executor object is deleted in its own thread */
280 connect(coreThread, &QThread::finished, executor, &QObject::deleteLater);
281
282 coreThread->start();
283 }
284
parameterSetup()285 void BitcoinApplication::parameterSetup()
286 {
287 // Default printtoconsole to false for the GUI. GUI programs should not
288 // print to the console unnecessarily.
289 gArgs.SoftSetBoolArg("-printtoconsole", false);
290
291 m_node.initLogging();
292 m_node.initParameterInteraction();
293 }
294
requestInitialize()295 void BitcoinApplication::requestInitialize()
296 {
297 qDebug() << __func__ << ": Requesting initialize";
298 startThread();
299 Q_EMIT requestedInitialize();
300 }
301
requestShutdown()302 void BitcoinApplication::requestShutdown()
303 {
304 // Show a simple window indicating shutdown status
305 // Do this first as some of the steps may take some time below,
306 // for example the RPC console may still be executing a command.
307 shutdownWindow.reset(ShutdownWindow::showShutdownWindow(window));
308
309 qDebug() << __func__ << ": Requesting shutdown";
310 startThread();
311 window->hide();
312 // Must disconnect node signals otherwise current thread can deadlock since
313 // no event loop is running.
314 window->unsubscribeFromCoreSignals();
315 // Request node shutdown, which can interrupt long operations, like
316 // rescanning a wallet.
317 m_node.startShutdown();
318 // Unsetting the client model can cause the current thread to wait for node
319 // to complete an operation, like wait for a RPC execution to complate.
320 window->setClientModel(nullptr);
321 pollShutdownTimer->stop();
322
323 delete clientModel;
324 clientModel = nullptr;
325
326 // Request shutdown from core thread
327 Q_EMIT requestedShutdown();
328 }
329
initializeResult(bool success)330 void BitcoinApplication::initializeResult(bool success)
331 {
332 qDebug() << __func__ << ": Initialization result: " << success;
333 // Set exit result.
334 returnValue = success ? EXIT_SUCCESS : EXIT_FAILURE;
335 if(success)
336 {
337 // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
338 qWarning() << "Platform customization:" << platformStyle->getName();
339 #ifdef ENABLE_WALLET
340 m_wallet_controller = new WalletController(m_node, platformStyle, optionsModel, this);
341 #ifdef ENABLE_BIP70
342 PaymentServer::LoadRootCAs();
343 #endif
344 if (paymentServer) {
345 paymentServer->setOptionsModel(optionsModel);
346 #ifdef ENABLE_BIP70
347 connect(m_wallet_controller, &WalletController::coinsSent, paymentServer, &PaymentServer::fetchPaymentACK);
348 #endif
349 }
350 #endif
351
352 clientModel = new ClientModel(m_node, optionsModel);
353 window->setClientModel(clientModel);
354 #ifdef ENABLE_WALLET
355 window->setWalletController(m_wallet_controller);
356 #endif
357
358 // If -min option passed, start window minimized (iconified) or minimized to tray
359 if (!gArgs.GetBoolArg("-min", false)) {
360 window->show();
361 } else if (clientModel->getOptionsModel()->getMinimizeToTray() && window->hasTrayIcon()) {
362 // do nothing as the window is managed by the tray icon
363 } else {
364 window->showMinimized();
365 }
366 Q_EMIT splashFinished();
367 Q_EMIT windowShown(window);
368
369 #ifdef ENABLE_WALLET
370 // Now that initialization/startup is done, process any command-line
371 // bitcoin: URIs or payment requests:
372 if (paymentServer) {
373 connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
374 connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile);
375 connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
376 window->message(title, message, style);
377 });
378 QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
379 }
380 #endif
381 pollShutdownTimer->start(200);
382 } else {
383 Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown
384 quit(); // Exit first main loop invocation
385 }
386 }
387
shutdownResult()388 void BitcoinApplication::shutdownResult()
389 {
390 quit(); // Exit second main loop invocation after shutdown finished
391 }
392
handleRunawayException(const QString & message)393 void BitcoinApplication::handleRunawayException(const QString &message)
394 {
395 QMessageBox::critical(nullptr, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Litecoin can no longer continue safely and will quit.") + QString("\n\n") + message);
396 ::exit(EXIT_FAILURE);
397 }
398
getMainWinId() const399 WId BitcoinApplication::getMainWinId() const
400 {
401 if (!window)
402 return 0;
403
404 return window->winId();
405 }
406
SetupUIArgs()407 static void SetupUIArgs()
408 {
409 #if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
410 gArgs.AddArg("-allowselfsignedrootcertificates", strprintf("Allow self signed root certificates (default: %u)", DEFAULT_SELFSIGNED_ROOTCERTS), true, OptionsCategory::GUI);
411 #endif
412 gArgs.AddArg("-choosedatadir", strprintf("Choose data directory on startup (default: %u)", DEFAULT_CHOOSE_DATADIR), false, OptionsCategory::GUI);
413 gArgs.AddArg("-lang=<lang>", "Set language, for example \"de_DE\" (default: system locale)", false, OptionsCategory::GUI);
414 gArgs.AddArg("-min", "Start minimized", false, OptionsCategory::GUI);
415 gArgs.AddArg("-resetguisettings", "Reset all settings changed in the GUI", false, OptionsCategory::GUI);
416 gArgs.AddArg("-rootcertificates=<file>", "Set SSL root certificates for payment request (default: -system-)", false, OptionsCategory::GUI);
417 gArgs.AddArg("-splash", strprintf("Show splash screen on startup (default: %u)", DEFAULT_SPLASHSCREEN), false, OptionsCategory::GUI);
418 gArgs.AddArg("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM), true, OptionsCategory::GUI);
419 }
420
421 #ifndef BITCOIN_QT_TEST
GuiMain(int argc,char * argv[])422 int GuiMain(int argc, char* argv[])
423 {
424 #ifdef WIN32
425 util::WinCmdLineArgs winArgs;
426 std::tie(argc, argv) = winArgs.get();
427 #endif
428 SetupEnvironment();
429
430 std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
431
432 // Subscribe to global signals from core
433 std::unique_ptr<interfaces::Handler> handler_message_box = node->handleMessageBox(noui_ThreadSafeMessageBox);
434 std::unique_ptr<interfaces::Handler> handler_question = node->handleQuestion(noui_ThreadSafeQuestion);
435 std::unique_ptr<interfaces::Handler> handler_init_message = node->handleInitMessage(noui_InitMessage);
436
437 // Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
438
439 /// 1. Basic Qt initialization (not dependent on parameters or configuration)
440 Q_INIT_RESOURCE(bitcoin);
441 Q_INIT_RESOURCE(bitcoin_locale);
442
443 // Generate high-dpi pixmaps
444 QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
445 #if QT_VERSION >= 0x050600
446 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
447 #endif
448 #ifdef Q_OS_MAC
449 QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
450 #endif
451
452 BitcoinApplication app(*node);
453
454 // Register meta types used for QMetaObject::invokeMethod
455 qRegisterMetaType< bool* >();
456 #ifdef ENABLE_WALLET
457 qRegisterMetaType<WalletModel*>();
458 #endif
459 // Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
460 // IMPORTANT if it is no longer a typedef use the normal variant above
461 qRegisterMetaType< CAmount >("CAmount");
462 qRegisterMetaType< std::function<void()> >("std::function<void()>");
463 qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
464 /// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
465 // Command-line options take precedence:
466 node->setupServerArgs();
467 SetupUIArgs();
468 std::string error;
469 if (!node->parseParameters(argc, argv, error)) {
470 QMessageBox::critical(nullptr, PACKAGE_NAME,
471 QObject::tr("Error parsing command line arguments: %1.").arg(QString::fromStdString(error)));
472 return EXIT_FAILURE;
473 }
474
475 // Now that the QApplication is setup and we have parsed our parameters, we can set the platform style
476 app.setupPlatformStyle();
477
478 /// 3. Application identification
479 // must be set before OptionsModel is initialized or translations are loaded,
480 // as it is used to locate QSettings
481 QApplication::setOrganizationName(QAPP_ORG_NAME);
482 QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN);
483 QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT);
484
485 /// 4. Initialization of translations, so that intro dialog is in user's language
486 // Now that QSettings are accessible, initialize translations
487 QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
488 initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
489
490 // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
491 // but before showing splash screen.
492 if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
493 HelpMessageDialog help(*node, nullptr, gArgs.IsArgSet("-version"));
494 help.showOrPrint();
495 return EXIT_SUCCESS;
496 }
497
498 /// 5. Now that settings and translations are available, ask user for data directory
499 // User language is set up: pick a data directory
500 if (!Intro::pickDataDirectory(*node))
501 return EXIT_SUCCESS;
502
503 /// 6. Determine availability of data and blocks directory and parse bitcoin.conf
504 /// - Do not call GetDataDir(true) before this step finishes
505 if (!fs::is_directory(GetDataDir(false)))
506 {
507 QMessageBox::critical(nullptr, PACKAGE_NAME,
508 QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
509 return EXIT_FAILURE;
510 }
511 if (!node->readConfigFiles(error)) {
512 QMessageBox::critical(nullptr, PACKAGE_NAME,
513 QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error)));
514 return EXIT_FAILURE;
515 }
516
517 /// 7. Determine network (and switch to network specific options)
518 // - Do not call Params() before this step
519 // - Do this after parsing the configuration file, as the network can be switched there
520 // - QSettings() will use the new application name after this, resulting in network-specific settings
521 // - Needs to be done before createOptionsModel
522
523 // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
524 try {
525 node->selectParams(gArgs.GetChainName());
526 } catch(std::exception &e) {
527 QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what()));
528 return EXIT_FAILURE;
529 }
530 #ifdef ENABLE_WALLET
531 // Parse URIs on command line -- this can affect Params()
532 PaymentServer::ipcParseCommandLine(*node, argc, argv);
533 #endif
534
535 QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
536 assert(!networkStyle.isNull());
537 // Allow for separate UI settings for testnets
538 QApplication::setApplicationName(networkStyle->getAppName());
539 // Re-initialize translations after changing application name (language in network-specific settings can be different)
540 initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
541
542 #ifdef ENABLE_WALLET
543 /// 8. URI IPC sending
544 // - Do this early as we don't want to bother initializing if we are just calling IPC
545 // - Do this *after* setting up the data directory, as the data directory hash is used in the name
546 // of the server.
547 // - Do this after creating app and setting up translations, so errors are
548 // translated properly.
549 if (PaymentServer::ipcSendCommandLine())
550 exit(EXIT_SUCCESS);
551
552 // Start up the payment server early, too, so impatient users that click on
553 // bitcoin: links repeatedly have their payment requests routed to this process:
554 app.createPaymentServer();
555 #endif
556
557 /// 9. Main GUI initialization
558 // Install global event filter that makes sure that long tooltips can be word-wrapped
559 app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
560 #if defined(Q_OS_WIN)
561 // Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION)
562 qApp->installNativeEventFilter(new WinShutdownMonitor());
563 #endif
564 // Install qDebug() message handler to route to debug.log
565 qInstallMessageHandler(DebugMessageHandler);
566 // Allow parameter interaction before we create the options model
567 app.parameterSetup();
568 // Load GUI settings from QSettings
569 app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
570
571 if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
572 app.createSplashScreen(networkStyle.data());
573
574 int rv = EXIT_SUCCESS;
575 try
576 {
577 app.createWindow(networkStyle.data());
578 // Perform base initialization before spinning up initialization/shutdown thread
579 // This is acceptable because this function only contains steps that are quick to execute,
580 // so the GUI thread won't be held up.
581 if (app.baseInitialize()) {
582 app.requestInitialize();
583 #if defined(Q_OS_WIN)
584 WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(PACKAGE_NAME), (HWND)app.getMainWinId());
585 #endif
586 app.exec();
587 app.requestShutdown();
588 app.exec();
589 rv = app.getReturnValue();
590 } else {
591 // A dialog with detailed error will have been shown by InitError()
592 rv = EXIT_FAILURE;
593 }
594 } catch (const std::exception& e) {
595 PrintExceptionContinue(&e, "Runaway exception");
596 app.handleRunawayException(QString::fromStdString(node->getWarnings("gui")));
597 } catch (...) {
598 PrintExceptionContinue(nullptr, "Runaway exception");
599 app.handleRunawayException(QString::fromStdString(node->getWarnings("gui")));
600 }
601 return rv;
602 }
603 #endif // BITCOIN_QT_TEST
604