You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

starwels.cpp 23KB

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